I have an activity non visible, with some variables that must be accesed by static way. This activity can't be a service, because it is a MapView activity.
I need to access some static varibales of the activity anytime. I know that Android can close suspended activities (non visible activities) so.... how can i avoid it? i need that my suspended non visible activitity never get's deleted by Android.
The variable that i need to access staticly is a the own MapActivity instance variable because i need to pass it to another mapView objects from other activities
public class OsmMapActivity extends MapActivity {
public static OsmMapActivity instance;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View v = new View(this);
setContentView(v);
instance=this;
How many variables do you have? I would create a singleton and manage those with maybe SharedSettings. You can create a POJO and save it.
Also, you could make an object, implement Parcelable interface and pass it to the Activity where you need the information.
Related
I started to learn the android framework and my biggest problem is the hell around the activity life cycle. So when the user rotate the screen my application just crash. As I understand beside the normal activity life cycle Android hacked a force-instance-deleter-and-partially-recovery service for me which is not a bug but a feature.
So I just want my member variable keeps safe, so a I thought a start storing it in the Application class.
So I want to refactor my program in the following way:
I create an own Application
public class MainApp extends Application {
LoginActivityData loginActivityData; // create data "segment" for every activity
FirstActivityData firstActivityData;
...
public static MainApp getInstance(final Context context) {
if (context == null) return null;
final Context app = context.getApplicationContext();
return app instanceof MainApp ? (MainApp) app : null;
}
}
In activities and fragments I stop using member variables except the one from the MainApp class.
public class LoginActivity extends Activity {
LoginActivityData loginActivityData;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loginActivityData = MainApp.getInstance(this).loginActivityData;
}
Is there any drawback of this design?
Yes, there is a drawback. Your application object can and will be destroyed by the system when it needs to recover memory, and the application object does not have callback methods that can be used to save state. See here for a fuller explanation.
There are many ways to persist data/state, but if you use the following approach you generally won't go far wrong:
Use onPause() to save long-term data to a SQLite DB/SharedPreferences/cloud etc. Restore it wherever appropriate (onCreate(), onResume(), ...).
Use onSaveInstanceState() to save temporary data to a Bundle. Restore it in onCreate()/onRestoreInstanceState(). The bundle is automatically passed around to the appropriate methods by the system. Note that there is no guarantee that onSaveInstanceState() will be called, so don't use it for critical data.
I'll try really hard to turn this into one comprehensive question:
I'm writing a method to get a String that contains the name of an Android device's city, as determined by the LocationManager and getLastKnownLocation() and all that.
Then I realized I'd need to do the same thing again in another activity, so why not just make an entirely separate class (LocationFinder) that I could use across my program, instead of writing duplicate code everywhere?
But I've run into problems that confuses me. For instance, if I make this class (LocationFinder), should it extend Activity, even though it is never actually visualized? All this class would do is have a variety of getters like getLastKnownCity() or getCurrentCity() and return strings. I assumed it wouldn't HAVE to extend the Activity class, since it's really not an activity.
But then what Context do I use for:
Geocoder geocoder = new Geocoder(Context context, Locale locale)
?
This made me assume it MUST be an activity. So I extended Activity, and replaced the constructor with
#Override
protected void onCreate(..............
but for some reason, that never ends up getting called, even when I put
String city = new LocationFinder().getLastKnownCity();
My very first line of LocationFinder's onCreate() is
System.out.println("HEY!")
and it never even gets to that. I get a null pointer at android.internal.os.LoggingPrintStream.println() and other stuff.
Plus, there's a bunch of system constants that come from Activity classes. For instance, I need to get at LOCATION_SERVICE, which is a String, which I can't get without extending Activity. Sure, I could cheat and just put in the literal string, but that feels wrong.
EDIT: If possible, use frogmanx's answer. This should only be used when his answer is not possible to use. (ie. singletons that need a context right off the bat.)
Sounds like you should extend Application and not Activity.
Make your Application something like this:
public class MyApplication extends Application {
private static MyApplication instance;
public MyApplication() {
instance = this;
}
public static MyApplication getInstance() {
return instance;
}
Then add this attribute to the application tag of the manifest:
<application android:name=".your.package.MyApplication" ... />
After all that, you can get a Context by calling MyApplication.getInstance() from anywhere.
When constructing your class, you can have a constructor that takes in a Context and assigns it a local Context object within your class.
public class LocationFinder {
private Context myContext;
private Geocoder geocoder;
public LocationFinder(Context context)
{
myContext = context;
geocoder = new Geocoder(myContext);
}
}
And then when you try to access this class, make sure you initialise it like:
public class TestActivity extends Activity {
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LocationFinder lFinder = new LocationFinder(getApplication());
}
}
Of course, you can't access a context from every class that you will be running. So a reference to a View can suffice.
LocationFinder lFinder = new LocationFinder(anyView.getApplication());
should it extend Activity, even though it is never actually visualized?
No. From the Android docs
An activity is a single, focused thing that the user can do. Almost
all activities interact with the user, so the Activity class takes
care of creating a window for you in which you can place your UI with
setContentView(View)
Think of an Activity as a screen the user sees.
But then what Context do I use for
Geocoder geocoder = new Geocoder(Context context, Locale locale)
The Activity class extends Context, as do a lot of other classes including Application. A context provides access to resources associated with the class which extends the context.
You only need, and should only use, an Activity context when required to interact with resources associated with that Activity and methods implemented by the concrete Activity class. When you do need that access to that context, then you would pass it to the class needing access, typically as an argument to a constructor of that class.
If you ever do pass an Activity context outside of the activity extending it, make sure that the scope and lifecycle of the reference is less than or equal to the extending activity otherwise you will leak large amounts of memory if the activity is destroyed since the garbage collector cannot free the memory since there is a reference to the context.
If you take a look at the constructor for Geocoder you will see that it takes a Context as an argument, as you know. There is a clue as to why the Context is needed in the description:
Geocoder(Context context, Locale locale)
Constructs a Geocoder whose responses will be localized for the given Locale. [1]:
The reason the Context is required is to gain access to system information about the platform locales and the current system locale.
So in your example, you could simply pass the Application context to the constructor, which you can get a reference to with getApplicationContext()
For instance, I need to get at LOCATION_SERVICE, which is a String, which I can't get without extending Activity
You can get it from the application context.
We all know you can't use static on findViewById so ...
The basic code is:
public class DiffViewFlowExample extends Activity implements OnItemClickListener {
#Override
public void onCreate() {
}
static void hereismymethod() {
}
How can I use a findViewById here? I know I can't locally but because static won't work then...
Oh you might say: add it as an argument,well I would,but I will call the hereismymethod from a service,and we all know that services don't like to play with stuff that is about display...
So can anybody save me?
You shouldn't be calling method2, static or not, on an Activity from outside of the Activity. If you want to act upon your Activity from within the Service, then create a listener interface and then register your activity as a listener inside of the service. Then, when it's appropriate, have your service find the view and act on it. To allow the service to access the views in your Activity, simply make your interface method pass a reference to the Activity. Then, the Service can call activity.findViewById() and do whatever it wants to it.
Is there a way to intercept whenever the Application creates a new Activity instance? I'm only interested in Activities belonging to the Application process not all Activities on the phone. Is there some way to do this? Is the Application class involved in doing this in some way? What methods can I override to get at the Activity instance after it's been created?
Ok, just an idea - in your app you can create a base activity class so all the rest of activities are subclassed from that base activity. Then in the onCreate() callback you may notify some listener instance about the fact of a new app activity instance creation:
public class BaseActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// put the code to notify a listener here
}
}
public class YourWorkingActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
}
If you use a ListActivity (that is common for an average Android app), then you should also create a similar BaseListActivity for it.
Most likely the best candidate for a listener would be an Application subclass since it is guaranteed by the OS that is will be created before any Activity will be instantiated.
Warning: you should avoid keeping a strong reference to an Activity in the listener since it will create a memory leak when the OS will try to kill that Activity (as a part of the Activity or Process life-cycle). Probably use WeakReference for this.
I have to use context in many places of my code such as database operations, preference operations, etc. I don't want to pass in context for every method.
Is it a good practice to create a reference to application context at the main Activity and use it anywhere such as database operations? So, I don't need some many context in method parameters, and the code can avoid position memory leak due to use of Activity Context.
public class MainActivity extends Activity {
public static Context s_appContext;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
s_appContext = this.getApplicationContext();
To me it smells like a hack although I do agree it can be a pain having to pass all those contexts around. At least one problem I see with that approach is when trying to unit test any of your code needing a context - now everything depends on your main activity's onCreate method having been called.