Objects just disapper after a few hours (Android) - android

I have a list of custom objects ... these objects simple monitor a few of my websites for any new data that users may have added. I keep these objects in a static List<> that is a member of a final class .... I create a service to go through the list at a given interval and update as needed.
final public class MonitorHandler {
public static List<MonitorSettings> monitorsSettings = new ArrayList<MonitorSettings>();
ect....
}
everything works perfectly fine for some time ... no exceptions come up at all. But if I let the app run for a period of time .. like say over night the list is empty ... like the objects have been garbage collected or removed by android. Why is this?? don't static objects persist even after the app is closed or sent to backround?

Why is this?
Your process was terminated.
don't static objects persist even after the app is closed or sent to backround?
Only while the process is running. Your process can be terminated once it is no longer in the foreground. Whether that takes seconds or hours will depend upon what is going on with the device.
If you have data that you want to hang around, please store it in a persistent fashion, using a database, file, or SharedPreferences.

Why is this?? don't static objects persist even after the app is closed or sent to backround?
No, if your app was actually closed by system, this might happen. You should log in your Service.onDestroy() to make sure this is really the cause, but it is not guaranted that onDestroy will actually be called.
So you should persist your data in some storage, preferable SharedPreferences or DB - sqlite.

You haven't shown enough code to be certain, but it's very likely that you are not holding a reference to your data anywhere in your application except the static elements of the MonitorHandler class. The Dalvik VM will unload unreferenced classes from time to time, so the next time you access the class it is reloaded, the static initialisation is re-run, and you end up with a new, empty list.
The bottom line is that the only class that you can rely on not being unloaded during the execution of your Android application is the Application class itself.
If you want to retain data in your application the only approach that works is to maintain a reference to it from your Application class. In the case of your list the simplest way to do that is put it into your Application class directly. With more complex data you would probably want to create an instance of a separate class and hold a reference to it statically in your Application class. Here is an example showing two different ways to create the data, one statically, one lazily.
import android.app.Application;
import android.content.Context;
import com.example.DiskLruImageCache;
import java.util.ArrayList;
import java.util.List;
public class TestApp extends Application {
static final public int CACHE_SIZE = 1024 * 1024 * 15; // 15MB
private static List<String> stringList = new ArrayList<String>();
private static DiskLruImageCache imageCache = null;
private static Context context;
#Override
public void onCreate() {
super.onCreate();
context = this;
}
public static List<String> getStringList() {
return stringList;
}
static public DiskLruImageCache getImageCache() {
if(imageCache == null) {
synchronized(context) {
if(imageCache == null)
imageCache = new DiskLruImageCache(context, "TestImages", CACHE_SIZE);
}
}
return imageCache;
}
}
Now in your Activities or Service you can simply call TestApp.getStringList() to get the list. Any changes to this will be preserved as long as the application is running.

Related

How do I share common functions and data across many activities in a single android application

I am looking for how to share functions and data across multiple activities within a single application. I researched the daylights out of it and find some ideology war between overriding the extend for the application and doing a singleton, neither of which I can find examples sufficient to make me understand. Basically I want to share data and share functions. All activities need the same functions and data so this is not one activity sharing data with another activity. It is all activities needing to have access to the same functions and data.
What I want to know is what is the way to go and how do I do it. I need to see what I need to do in my 34 activities, what the class that is going to be common looks like, and what the Manifest entry needs to be. I also need to be sure the common data area will not be closed by the OS.
This is my first Android - Java program and now find my 15,000 line, 34 activity application needs some structure. I know, should have done things differently but the app works really well with two exceptions. One is that it is structurally a mess. Two is that the fact it is a mess is making it hard to fix one behavior I would like to fix.
This is a GPS based application for racing sailboats. It is timing critical and every activity basically runs a once a second loop inside the location manager onLocationChanged function. That part is fine and I do not want to put the GPS code in one place. The problem is that most activities need to filter the data so a lot of code is copied and pasted to the activities. The filter needs history so it needs to remember a state. There are other functions that are used by several activities so these have been copied as well. Think of a function that averages the last three GPS speed readings. It needs to save some history, do its thing, and give a result. All activities need to do the exact same thing. All this works but the problem is that the averaging starts over every time I switch activities because every activity has its own filter. That gives a glitch in the data that I need to get rid of. I need common place to save the data and hopefully a common place to run the filtering and other functions that are common. If every activity can call the filter function that is using common state data, there will be no glitch across activity changes.
I would appreciate some guidance.
Why you don't just make a Class with only static functions, passing needed Parameters? An example if you want to show an ErrorDialog
public class SharedHelper{
public static Dialog showErrorDialog(Context ctx, String message, String title, DialogInterface.OnClickListener okListener, DialogInterface.OnClickListener cancelListener){
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setMessage(message).setTitle(tilte);
if (okListener != null){
builder.setPositiveButton(R.string.button_positive, okListener);
}
if (cancelListener != null){
builder.setNegativeButton(R.string.button_negative, cancelListener);
}
return builder.show();
}
}
Singletons are (from my point of view) one of the uglyest design pattern and will bite you sooner or later. Putting anything in Application requires you to cast it everytime to the Special Application class you designed. A class with only statics however is very flexible in its usage and doesn't need an instance to work.
For the storage-issue:
lookup "SharedPreferences" & "SQLite" and decide afterwards which storage-type suits your needs more.
For the methods-issue:
This question is a bit more complex and there are different ways to do it. For example you could write a parent-class that implements all your globally needed questions and you let all your activity-classes inherit from it.
public class MyParentActivity extends Activity {
public void myMethod() {
}
}
and:
public class Activity1of34 extends MyParentActivity {
myMethod();
}
I think what this comes down to is not an Android problem but an Object-Oriented Programming problem. If I understand the situation correctly, I'm betting the best solution would be to take your shared filter and create a new Filter class that is instantiated within each Activity (this is likely more manageable than a singleton, but not having seen your use case, it's hard to say for sure). If you need to centrally track the averaging, you can simply create a static variable within the Filter class that maintains the same value during the life of the application. If you really want to maintain that average (even past the application's current lifecycle), you can persist it in a database or other local data options. However, I don't see any reason to put everything in a singleton just to maintain that average. Singletons (and all static data structures) can be potentially troublesome if used incorrectly.
I, for one, do not mind the singleton pattern. Of course as everything else it should not be abused.
This is the construction I use for my shared objects. My app is divided into modules this way but can just as well be used in your case.
public class SharedDataObject {
private Context context;
private static SharedDataObject instance;
public static SharedDataObject getInstance() {
if (instance == null) throw new RuntimeException("Reference to SharedDataObject was null");
return instance;
}
public static SharedDataObject createInstance(Context context) {
if (instance != null) {
return instance;
}
return instance = new SharedDataObject(context.getApplicationContext());
}
// notice the constructor is private
private SharedDataObject(Context context) {
this.context = context;
}
...
public void myMethod() {
// do stuff
}
}
Notice that it uses the application context, that means among other things, means that the context owned by SharedDataObject cannot be used for GUI operations. But, the context will live for the entire lifetime of the application, which is nice.
Furthermore I hate having to pass a context everytime I wish to call methods on my SharedDataObject, thus I have a splashscreen calling SharedDataObject.createInstance() on all my modules.
Once an instance is create, I can call:
SharedDataObject.getInstance().myMethod();
Anywhere in my code, regardless of a context being present or not (from the place calling this code that is).

Efficiently Passing Custom Object Data between Android Activities [Mono Android]

I've been stumped with this for a while now.
I'm working on an android app that stores a person's fish catches, favorite fishing locations, tackle box inventory and other data. All my classes are Serializable and can saved and loaded between activities which seems to work thus far. But I'm predicting as more and more data is stored, the app will start running slow.
What I'm basically asking is there any way to retain this data throughout the entire application, so I don't have to load it every time a new screen pops up. I've already found the following information to help but it needs to be a little more clear for me to understand:
Another forum said you could stuff it in the Application object:
[Application]
public class MyApp : Android.App.Application {
public MyApp(IntPtr handle)
: base (handle)
{
}
public FishingData Data {get; set;}
}
Then within your Activity:
((MyApp) this.ApplicationContext).Data = value;
So I've never really heard of doing this approach before and I'm not sure this will live through the entire application process (I feel like either way it's going to have to load the data via serialization. Here's what I want the app todo:
The first activity is the main menu and the following must be done when the screen loads:
If a settings file is found, use serialization to load a previous FishingData object (I know how to do this)
If not, then create a new clean FishingData object to save later (I know this as well)
So now that we have a FishingData object, how do I ensure that I don't have to repeat steps 1-2 in every activity. How can I somehow pass the FishingData object to the next activity and ensure that it lives globaly while the app is still living. I only want to load it once (via serializing) (<--Don't know how to do this) and save it only when a user adds data to this object (which I know how to do).
Any help will be appreciated. This is bugging me I cant seem to figure this out. This seems like it would be a common thing to do but I haven't had any luck finding any detailed information.
Here is how I would pass my data around the app via parcelable. Lets say you have a class named Fisherman (for a user basically)
public class Fisherman implements Parcelable {
private String name;
private Tacklebox box;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeParcelable(box, 0);
}
public static final Parcelable.Creator<Fisherman> CREATOR
= new Parcelable.Creator<Fisherman>() {
public Fisherman createFromParcel(Parcel in) {
return new Fisherman(in);
}
public Fisherman[] newArray(int size) {
return new Fisherman[size];
}
};
private Fisherman(Parcel in) {
name = in.readString();
box = in.readParcelable(com.fisher.Tacklebox);
}
}
In this example, you define parcelable for each data model you have. So say you have a fisherman object, that contains another object called tacklebox. You will also define this for tacklebox, and so on if you continue to nest models. This way, all you need to do to pass data between activities is
Intent intent = new Intent(this, Activity.class);
intent.putParcelableExtra("com.fisher.Fisherman", fisherman);
and read
Bundle b = getIntent().getExtras();
Fisherman fisher = b.getParcelable("com.fisher.Fisherman");
This unfortunetly answers only step 3 of your problem, but I suggest breaking each one of your 3 steps into its own question because what your trying to do is slightly more lengthy than one question
You can use this approach, it will live as long as your Application object is alive (Which means it will live through your entire application and activities). You can read more about using global variables stored in the Application object here. I don't think mono would make a difference which will prevent you from using this approach.

Share Database Between Activity and Service

I'm creating an queued upload manager. With this answer to my previous question's guidance, I'll be using a Service, to upload these images. It was recommended that I use a database to keep track of the successfully uploaded, and the pending files.
My initial research leads me to believe that I'll want to create a Bound Service, so I can update my UI once the photos have uploaded, as well as a Started Service, so it can run independent of my Activities that create it. It seems that I'll also need to start it in its own process via the process=":something" directive in the app manifest.
My question is, what would the best way of sharing an SQLite (unless there is a better way) database amongst the N activity clients and the uploader service?
I envision it working like this, in pseudo code:
// in an app
writeRecordToDb( . . . );
// start service
if( service doesn't exist )
{
// start service, and bind
}
// in the service:
if( shared db has another row )
{
doDownload( . . . );
if( download worked )
{
notifyActivity();
if( db has another row )
doDownload( . . . );
}
else
{
retryDownload( . . . );
}
}
Is this the correct way to go about this? I'm again attempting to circumvent the problem of having multiple Activity instances request photo uploads when there is little to no cellular signal. I've just finished reading though the Service and Bound Service docs, and I'm feeling good, but not great.
My initial research leads me to believe that I'll want to create a Bound Service
I wouldn't.
so I can update my UI once the photos have uploaded
You do not need to use the binding pattern to update the UI. You can:
send a local broadcast using LocalBroadcastManager that the activity picks up, or
invoke a PendingIntent supplied in an Intent extra on startActivity() by the activity, or
give Square's Otto event bus a try (looks interesting, but I haven't used it yet)
etc.
as well as a Started Service, so it can run independent of my Activities that create it
Which is why you should not bother with binding, as you do not need that, but you do need to start the service.
My question is, what would the best way of sharing an SQLite (unless there is a better way) database amongst the N activity clients and the uploader service?
Option #1: Keep your SQLiteOpenHelper in a static data member
Option #2: Use a ContentProvider wrapper around your database
Is this the correct way to go about this?
Using a database as a communications channel between components is akin to two next-door neighbors communicating with each other using a banner towed by a biplane. Yes, it works. However, it is slow and expensive.
(also, there's never a biplane when you need one, but I digress...)
If you wish to use a database as a backing store for pending downloads, in case there is some interruption (e.g., user powers down the device) and you wish to pick up those downloads later on, that's fine. However, the service will know what to download by the command you send to it via startService().
CommonsWare covers basically everything you need... but here is some code illustrating the two options just in case there is any confusion.
Keep your SQLiteOpenHelper in a static data member.
public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
private static final String DATABASE_NAME = "databaseName";
private static final String DATABASE_TABLE = "tableName";
private static final int DATABASE_VERSION = 1;
private Context mCxt;
public static DatabaseHelper getInstance(Context ctx) {
/**
* use the application context as suggested by CommonsWare.
* this will ensure that you dont accidentally leak an Activitys
* context (see this article for more information:
* http://developer.android.com/resources/articles/avoiding-memory-leaks.html)
*/
if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext());
}
return mInstance;
}
/**
* constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context ctx) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mCtx = ctx;
}
}
Then in your Service/Activity, keep a reference to your DatabaseHelper and call getInstance() on it.
Wrap the database in a ContentProvider. If you already have one implemented, then you can simply use
mContext.getContentResolver().query(...);
This works because Activity and Service both extend Context (which holds a reference to the ContentResolver).

Is a "Globals" class holding static variables in Android safe?

Can anyone enlighten me about the safety of a class holding global values in Android?
Here's a short example of what I mean:
public class Globals {
public static int someVariable = 0;
public static User currentUser = null;
public static Handler onLogin = null;
}
Then somewhere in an Activity I do the following:
Globals.someVariable = 42;
Globals.currentUser = new User("John", "Doe");
I have to rely on Globals.currentUser at multiple places in my app as soon as the user is logged in, but I'm unsure if I should do it, and also if I could use a Handler like this.
I read everywhere that an Android app could be killed anytime, does this mean it is killed completely or maybe just a part of it, thus killing my Globals class only?
Or is there any other way to store globally available data in a safe way, without writing every member change to the database (in fact, my User class is a little more complex than in this example. ;-)
Thanks for your effort!
Edit: Ok, here's what I finally did:
public class MyApp extends Application {
private static MyApp _instance;
public MyApp() {
super();
_instance = this;
}
public static MyApp getContext() {
return _instance;
}
....
private User _user = null;
public User getUser() {
if (_user == null) _user = new User();
return _user;
}
}
Then modify the AndroidManifest.xml and add android:name=".MyApp" to your application node to tell the app to use your subclass.
So far everything works fine and I can easily access the current Context (f.ex. in SQLiteOpenHelper) by calling MyApp.getContext().
It would be better to use the Android Application class. It's meant to store global application state
http://developer.android.com/reference/android/app/Application.html
Just create a subclass and make sure to update your manifest file to use your version. Then you can store whatever you need to in it. Activities have a method getApplication() which you can cast to your class to access your implementation
The pattern is discouraged--you will run into problems when unit testing.
Can you explain how you unit-test a class that must supply different custom "Users" here? You are either forcing a mock/fake class into "User" which will probably have a cross-effect on other tests or you are putting an if(test) into your code which gets ugly quick.
Over time populating this class artificially for testing gets more complex and starts to have relationships and dependencies.
More simply it makes it difficult to unit test a class in isolation.
It's one of those patterns that a given programmer either doesn't see a problem with or never uses because he's been burnt--you'll see little middle ground.

Where should I globally keep/cache data needed for all application lifecycle?

I'm fairly new in Android/Java programming, so some of the basic stuff is still quite confusing. So, lets say my application gets all data (articles) it requires from external XML files, it parses them to data models (Article class) and those articles will be used (displaying in lists or single article) all over the application for all it's lifecycle.
Where should I keep them? Can I create singleton class with an array containing all the articles I've parsed? Or should I save them to database and then query it on demand? (that sounds like too much work, I don't need to cache them for now) What's the best practice here?
Keep them in Application. This is a base class of any android application and it's alive during the whole lifetime of the application, whereas Activities are killed when not shown or orientation is changed.
You have to declare android:name in your AndroidManifest.xml:
<application android:name=".YourApplication"/>
Edited:
This is also relevant: How do I pass data between Activities/Services within a single application?
that depends what is your programming style lol.
you can as you said create a singleton that will read your xml and store everything.
you can create a static hash in your class. this way when you create a new object you will have access to the static information from that class.
you can pass the information from class to class as parameters.
if you want us to tell you which one would be the best it will be difficult without knowing the architecture of your program.
for example you could have a view controller that handle any changes and then it is simple to store the data at that level to pass it on when you switch views.
you could have static views in wich you could directly set all the values as you open them.
you could have losely linked views that call each other without any controller to handle the switching and in that case you would may prefer having a way to collect the info you need from a singleton or a static method...
As long as you make sure that you don't have any threads acting on the shared data you can just create a static class with static members. each activity will be able to access it. If using async download for your data then in the onPostExecute of your handler you can touch the GlobeVars because that runs on the UI thread.
public class GlobalVars {
public static String userId = "?";
//public static String serverUrl = "10.0.2.2"; //localhost when developing
public static String serverUrl = "192.168.1.4"; //on device to laptop
//public static String serverUrl = "102.192.293.10"; //production
public static Book currentBook = null;
public static Chapter currentChapter = null;
public static int lastclickedChapter = -1;
public static Voice currentVoice = null;
public static String catalogJson = "";
public static ArrayList<Book> catalogItems = null;
}
onCreate of MainActivity I can set the catalog to my downloaded list of xml coverted to objects
GlobeVars.catalogItems = downloaded xml to object list
in my SubActivity which is a list of chapters in onclicklistener I can set:
GlobeVars.currentChapter = items[clickeditem];
when you return to the main activity the values will still be set.

Categories

Resources