SqliteException busy iOS/Android Xamarin MVVMCross - android

In our Android and iOS MVVMCross app we are experiencing occasional SQLiteException: busy exceptions.
Given the code below, we have several repositories each of which construct a instance of the below and an associated connection to the Sqlite database. Imagine we have a Stocks Repository and a Valuations Repository, two instances of SqliteDataService will be created: SqliteDataService with type Stocks and SqliteDataService with types Valuations, each of which have a connection to the Sqlite database.
Actions on the repositories may operate on background threads which means that we may attempt to insert Stocks into the database at the same time as Valuations.
Now given each repository creates its own SqliteDataService the connectionObject lock will only protect the same repository types from accessing the database at the same time rather than protecting Stocks and Valuations from accessing the database at the same time.
My questions are:
Is it valid to create a connections per repository and if so, how do we guard against SqliteException: busy?
Is there a better pattern? i.e. Should we create a non-generic SqliteDataService class that shares the same connection across threads? We have tried this but on Android we experience fatal exceptions.
Does anybody have a solid Sqlite DAL pattern for Xamarin MVVMCross?
public class SqliteDataService<T> : IDataService<T> where T : new()
{
private static object lockObject = new object();
private static object connectionObject = new object();
private static ISQLiteConnection _connection;
private static SqliteDataService<T> _instance;
public SqliteDataService(ISQLiteConnectionFactory connectionFactory, string dbPath)
{
if (_connection == null)
{
_connection = connectionFactory.Create (dbPath);
_connection.CreateTable<T> ();
}
}
public static SqliteDataService<T> GetInstance(ISQLiteConnectionFactory connectionFactory, string dbPath)
{
if (_instance == null)
{
lock (lockObject)
{
_instance = new SqliteDataService<T> (connectionFactory, dbPath);
}
}
return _instance;
}
public void CreateTable<T> ()
{
}
public void Insert(T value)
{
lock (connectionObject) {
_connection.Insert (value, typeof(T));
}
}
public void InsertAll(IEnumerable<T> values)
{
lock (connectionObject) {
_connection.Insert (values, typeof(T));
}
}
public IEnumerable<T> Read(Expression<Func<T, bool>> predicate)
{
lock (connectionObject) {
return _connection.Table<T> ().Where (predicate);
}
}
public T ReadFirst(Expression<Func<T, bool>> predicate)
{
lock (connectionObject) {
return Read (predicate).FirstOrDefault ();
}
}
public void Update(T value)
{
lock (connectionObject) {
_connection.Update (value, typeof(T));
}
}
public void Delete(Expression<Func<T, bool>> predicate)
{
lock (connectionObject) {
var valuesToDelete = Read (predicate);
if (valuesToDelete == null)
return;
foreach (var value in valuesToDelete) {
_connection.Delete (value);
}
}

It sounds like you have a few options:
Instantiate only a single SqliteDataService and pass a reference to it to both your Stocks and Valuations objects, this would seem most sensible as both are operating on the same DB
Instantiate an object for use as a lock outside the service and pass a reference into the SqliteDataService constructor so the lock is shared by both services. I believe this would work but I am no expert on locking.
You could handle the Busy exception in a try catch block and iterate a counter to make a max number of attempts against the database with a short wait each time so that you have a good chance of connecting. If the DB remains busy you will still get the exception and this solution is quite a messy one.
Restructure the DB so that the two areas are separated, this is probably not possible but worth a thought.

Related

What happens if I close my android application without closing an open realm instance?

I have kept a single realm instance opened on main thread in Application class and I use that single instance to do all kinds of DB operations from MainActivity. Since my application has a single activity, I close the instance in the activity's onDestroy(). The app is working fine for me as of now.
What are the repercussions of not doing a realm.close()? My database hasn't corrupted with or without the same.
Also, I've read that there are scenarios in which the Activity's onDestroy() may not get called at all. What effects the database can have in such a scenario if closing realm is so important?
public class MyApp extends Application {
private static MyApp instance;
private Realm realm;
public void onCreate() {
super.onCreate();
Realm.init(this);
Realm.setDefaultConfiguration(new RealmConfiguration.Builder()
.schemaVersion(BuildConfig.VERSION_CODE)
.migration(new RealmMigrationClass())
.compactOnLaunch()
.build());
realm = Realm.getInstance(Realm.getDefaultConfiguration());
}
public static MyApp getInstance() {
return instance;
}
public Realm getRealm() {
return realm;
}
}
MainActivity
public class MainActivity extends Activity {
#Override
protected void onDestroy() {
MyApp.getInstance().getRealm().close();
super.onDestroy();
}
}
Closing the realm instance is very important because of realm core has been written in c++ programming language and is compiled in the native code.And we know the c++ garbage collection does not run automatically we require to manually call the garbage collection.So when you call the realm.close() it means that realm deallocation the native memory means free or delete the pointer variable and also do the file descriptor job.From realm.close() means you give the command or tell to native c++ compiler to run the garbage collection.
If you look the "doc" (REALM_DOC) for Realm for Java you can find:
Realm implements Closeable to take care of native memory deallocation
and file descriptors, so always close your Realm instances when you’re
done with them.
Realm instances are reference counted—if you call getInstance twice in
a thread, you need to call close twice as well. This allows you to
implement Runnable classes without having to worry about which thread
will execute them: simply start it with getInstance and end it with
close.
Personally I suggest you to define a class in which define your Realm functions and an "Realm attribute" (like a "RealmHelper" class) then inside this class define:
- a unstatic Realm
- a static RealmHelper instance
You will always use this RealmHelper static instance for all operations in your Realm inside your main Thread, inside other threads you will call "new RealmHelper()" and CLOSE the realm just after you did the operation.
Doing this in your MainThread you just need to close ONE realm instance when the application get closed, to do this you can use the "Application.ActivityLifecycleCallbacks" interface inside a Custom defined Application class (so which extends Application of Android).
Example inside you Application custom class:
/* START Override ActivityLifecycleCallbacks Methods */
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
// Check if your MyRealmClass instance is null or is closed, in this case
// re-initialize it.
if(MyRealmClass.getInstance() == null || MyRealmClass.getInstance().getRealm().isClosed()){
MyRealmClass.initInstance();
}
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
if(!AppUtils.isAppOnForeground(this)){
// Close your MyRealmClass instance
if(MyRealmClass.getInstance() != null) {
MyRealmClass.getInstance().close();
MyRealmClass.getInstance().logRealmInstanceCount(LABEL_APP_IN_BACKGROUND);
MyRealmClass.setMyInstance(null);
}
}
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
/* END Override ActivityLifecycleCallbacks Methods */
Code of "isAppOnForeground" (check if your app is in foreground, if is not this mean your app is being closed):
public static boolean isAppOnForeground(Context context) {
boolean ret = false;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if(appProcesses != null){
String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
ret = true;
}
}
}
return ret;
}
Your "MyRealmClass" will look like:
public class MyRealmClass {
protected Realm mRealm;
protected static MyRealmClass mInstance;
public MyRealmClass() {
mRealm = Realm.getDefaultInstance();
}
public static MyRealmClass initInstance(){
if(mInstance == null){
mInstance = new MyRealmClass();
}
return mInstance;
}
public static MyRealmClass getInstance(){
return mInstance;
}
public static void setMyInstance(MyRealmClass instance) {
mInstance = instance;
}
public Realm getRealm() {
return mRealm;
}
public void setRealm(Realm realm){
this.mRealm = realm;
}
public void close() {
if (mRealm != null) {
try {
mRealm.close();
} catch(Exception e){
onException(e);
}
}
}
[...]
Then you need to check that all your Realm instance is not closed when you use a RealmObject or you do some operation in your Realm. And if it is closed (because the app got in background and then restarted) you need to re-initialize the realm (if you have an activity with a MyRealmClass instance as attribute).
Example in a BaseMyActivity:
public abstract class MyBaseActivity extends AppCompatActivity {
protected MyRealmClass mRealmClass;
/* START Override Lifecycle Methods */
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initMyRealmClass();
Lyra.instance().restoreState(this, savedInstanceState);
}
#Override
protected void onStart() {
super.onStart();
initMyRealmClass();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Lyra.instance().saveState(this, outState);
}
/* END Override Lifecycle Methods */
/* START Private Methods */
protected void initMyRealmClass(){
if(mRealmClass == null || mRealmClass.getRealm().isClosed()){
mRealmClass = MyRealmClass.initInstance();
}
}
/* END Private Methods */
}
Basically all your activities will extend this BaseActivity if they need to use Realm functions. (Lyra is used to save the state of any of your attributes: LYRA)
REMEMBER THAT:
if you set or get some attributes from a RealmObject or you get an object from a RealmList or RealmResults you NEED THAT YOUR REALM INSTANCE, from which the object was take, IS OPEN.
OTHERWISE you need to use this method when you init a variable with objects from the realm: (this methods should be placed in yuour "MyRealmClass")
public <T extends RealmObject> List<T> toList(RealmResults<T> results) {
return mRealm.copyFromRealm(results);
}
public <T extends RealmObject> List<T> toList(RealmList<T> results) {
return mRealm.copyFromRealm(results);
}
public <T extends RealmObject> T copyObjectFromRealm(T obj) {
return mRealm.copyFromRealm(obj);
}
public <T extends RealmObject> RealmResults<T> findAllObject(Class<T> classObject) {
RealmQuery<T> query = mRealm.where(classObject);
return query.findAll();
}
Now if you need to get a List of "MyRealmObjectClass" objects and add them to an adapter you will do this:
List<MyRealmObjectClass> myObjects = mRealmClass.toList(mRealmClass.findAllObject(MyRealmObjectClass.class))
myAdapter.addAll(myObjects);
Doing this if you "get" or "set" an attribute after the Realm instance, from which you got the objects, was closed (for example after the app get to background and then restarted) you won't get an exception.
BUT if you "set" an attribute of your RealmObject this WON'T BE SET in the REALM INSTANCE, so to change the value of a RealmObject inside the Realm in this case you need to Save the object!
OTHERWISE if you have a RealmResults or a RealmObject which is still connected to the Realm, so you can directly change, inside a transaction, an attribute of it and it will be changed inside the Realm too.
To do a Realm Transaction I suggest you to follow the DOC in the first link and, if you don't need to close the Realm in the Finally block, enable lambda and do this:
mRealm.executeTransaction(
realm -> {
[do your Realm operations]
}
)
or you can also do:
public boolean doRealmOperation(Object... params){
AtomicBoolean ret = new AtomicBoolean(false);
mRealm.executeTransaction(
realm -> {
try{
[do your realm operation]
ret.set(true);
} catch(Exception e){
onException(e)
ret.set(false);
}
}
)
}
in this case you need to use the "AtomicBoolean" because you will set the value you want to return inside the transaction, but inside a transaction the value got from outside of the transaction itself (in this case the "ret" variable) MUST BE A FINAL variable. But you can't define "ret" as "final" and then set it again, so you need to use the "AtomicBoolean" to set the variable outside the transaction and set it again inside the transaction itself.
(You can also avoid this problem by using a temporary variable to get the "true/false" value inside the transaction and then set the "ret" variable using that "temp variable". But personally I prefer to use "AtomicBoolean" class which is, I think, safer and more clean than a temp variable)
Hope this is helpful,
see you by and happy coding! ;)
Realm implements Closeable to take care of native memory deallocation and file descriptors, so always close your Realm instances when you’re done with them.
Realm instances are reference counted—if you call getInstance twice in a thread, you need to call close twice as well.
From my personal experience not closing realm has not caused a lot of issues, in fact when I tried closing it at times it would cause an issue when the app went into the background and was then resumed which caused a crash due to realm instance being closed, I am not sure why a new instance of realm was not created in that case, might have been a bug.
As of now I follow the realm docs and close my realm instances until they cause an issue.
General coding practises suggest that anything that is opened should be safely closed.
Yes, it will get closed only if you called close() method on your application's destroy() method. Remember Realm implements Closeable in order to take care of native memory deallocation and file descriptors so it is important to close your Realm instances when you are done with them.
For further info visit this link.

Realm on Android: keep DB logic separate

I used to work with un-auto-managed model objects that were copied from Realm. I switched to using auto-managed Realm object for my new projects and have a problem.
Where before I could keep my DB logic separate, in DAO classes, right now, the Realm code is all over my application.
Realm objects should be managed (closed) well, everywhere, on every thread, on every activity and fragment. But what I dislike most: every setter on every model object needs to be in a Realm transaction. There is Realm all over my code right now!
Did anyone find a way to keep the DB logic somewhat separate, while using auto managed Realm objects?
Conclusion, after a few months with Realm auto-managed objects:
Having your database code centralised, in Data Access Object (DAO) classes or the like, is hardly possible when using Realm’s auto-updated objects.
Every setter on every model object needs to be inside a Realm transaction block. If you use RetroLambda, the calls are relatively clean:
realm.executeTransaction(r -> user.setFirstName(firstName));
These blocks will be all over your project within no time. Forgetting to wrap a setter method (or a constructor call) in a transaction will crash your app. Believe me, this will happen a lot in the first weeks of adopting auto-updated objects.
Auto-updated objects cannot be shared across threads. The same is true for Realm instances.
All threads, and often activities and fragments, will have to open and close Realm instances. You’ll be thinking constantly “On which thread am I?”. If you cross thread boundaries with model objects or Realm instances, you will crash your app.
More info here: https://medium.com/#ffvanderlaan/realm-auto-updated-objects-what-you-need-to-know-b2d769d12d76
and here: https://medium.com/#Zhuinden/how-to-use-realm-for-android-like-a-champ-and-how-to-tell-if-youre-doing-it-wrong-ac4f66b7f149#.gazrajqwt
What I did was created a RealmController class that handles all of my Realm transactions, and fetches new data from the API. The skeleton for the implementation is borrowed from another SO post which I can't find right now, but you should be able to find it on Google by searching RealmController.
public class RealmController {
private static RealmController instance;
private final Realm realm;
private ServiceInterface restInterface;
private final String TAG = "RealmController";
private static boolean browseFetchAllowed = true;
private RealmConfiguration config = new RealmConfiguration.Builder()
.name("myRealm")
.schemaVersion(0)
.deleteRealmIfMigrationNeeded()
.build();
public RealmController(Application application) {
restInterface = ServiceGenerator.createService(ServiceInterface.class);
realm = Realm.getInstance(config);
}
public void setAuthentication(String token, String uid) {
this.restInterface = ServiceGenerator.createService(ServiceInterface.class, token, uid);
}
public static RealmController with(Fragment fragment) {
if (instance == null) {
instance = new RealmController(fragment.getActivity().getApplication());
}
return instance;
}
public static RealmController with(Activity activity) {
if (instance == null) {
instance = new RealmController(activity.getApplication());
}
return instance;
}
public static RealmController with(Application application) {
if (instance == null) {
instance = new RealmController(application);
}
return instance;
}
public RealmController getInstance() {
return instance;
}
public ServiceInterface getRestInterface() {
return restInterface;
}
public Realm getRealm() {
return realm;
}
public RealmResults<MyRealmObject> getStuff() {
return realm.where(MyRealObject.class).findAll();
}
public void setStuff(RealmList<MyRealmObject> stuff) {
realm.beginTransaction();
realm.copyToRealmOrUpdate(stuff);
realm.commitTransaction();
}
public void getStuffFromServer() {
restInterface.getStuff().enqueue(new Callback<RealmList<MyRealmObject>>() {
#Override
public void onResponse(Call<RealmList<MyRealmObject>> call, Response<RealmList<MyRealmObject>> response) {
if (response.isSuccessful()) {
realm.beginTransaction();
realm.copyToRealmOrUpdate(response.body);
realm.commitTransaction();
}
}
#Override
public void onFailure(Call<RealmList<RealmAd>> call, Throwable t) {
t.printStackTrace();
}
});
}
}
Towards the bottom of the file I've added a few examples, but usage is quite simple:
RealmResults<MyRealmObject> results = RealmController.with(this).getStuff();
In terms of having the objects auto-managed, what I've been using is RealmResults, which is always auto-managed (even if you're querying for a single object). Then just add a change listener to the results of the query and voilà. Also, if you want to have auto-updating data in recyclerviews, I would recommend RealmRecyclerView.

How to create an Observable in Android?

What I want to do is to create a simple in-memory cache just to try Observables out. However I got stuck because I don't understand how to create an observable. This is the code I have gotten so far:
public class MovieCache {
MovieWrapper movieWrapper;
public Observable<MovieWrapper> getMovies() {
//How to create and return an Observable<MovieWrapper> here?
}
public void setCache(MovieWrapper wrapper) {
movieWrapper = wrapper;
}
public void clearCache() {
movieWrapper = null;
}
}
In the getMovies() method I want to create an Observable and return my local field movieWrapper to the subscriber. How can I do this? I tried with using new Observable.just(movieWrapper) but it results in a null exception.
Take a look at this tutorial as it does exactly what you are looking for. Basically you use defer() to make sure you always get the latest version of your cached object:
public class MovieCache {
MovieWrapper movieWrapper;
public Observable<MovieWrapper> getMovies() {
return Observable.defer(new Func0<Observable<MovieWrapper>>() {
#Override
public Observable<MovieWrapper> call() {
return Observable.just(movieWrapper);
}
});
}
public void setCache(MovieWrapper wrapper) {
movieWrapper = wrapper;
}
public void clearCache() {
movieWrapper = null;
}
}
defer() makes sure that you will get the object upon subscription to the Observable not on creation.
Note however that, according to the author of the post:
The only downside to defer() is that it creates a new Observable each
time you get a subscriber. create() can use the same function for each
subscriber, so it's more efficient. As always, measure performance and
optimize if necessary.
As already said, accepted answer has downside
it creates a new Observable each time you get a subscriber
But it is not the only one.
Consumer won't receive any value if he calls getMovies().subscribe(...) before setCache(...) is called.
Consumer should resubscribe if he want to receive any updates (let's say setCache() can be called multiple times.
Of course all of them can be irrelevant in your scenario. I just want to show you another way (I'm sure there are many more).
You can use BehaviorSubject in order to eliminate all these disadvantages.
public class MovieCache {
private BehaviorSubject<MovieWrapper> mMovieCache = BehaviorSubject.create();
public void setCache(MovieWrapper wrapper) {
mMovieCache.onNext(wrapper);
}
public Observable<MovieWrapper> getMovieObservable() {
//use this if consumer want to receive all updates
return mMovieCache.asObservable();
}
public MovieWrapper getMovie() {
//use this if consumer want to get only current value
//and not interested in updates
return mMovieCache.getValue();
}
public void clearCache() {
//CAUTION consumer should be ready to receive null value
mMovieCache.onNext(null);
//another way is to call mMovieCache.onCompleted();
//in this case consumer should be ready to resubcribe
}
public static class MovieWrapper {}
}
Take a look at BehaviorSubject marble diagram.

RxJava as event bus?

I'm start learning RxJava and I like it so far. I have a fragment that communicate with an activity on button click (to replace the current fragment with a new fragment). Google recommends interface for fragments to communicate up to the activity but it's too verbose, I tried to use broadcast receiver which works generally but it had drawbacks.
Since I'm learning RxJava I wonder if it's a good option to communicate from fragments to activities (or fragment to fragment)?. If so, whats the best way to use RxJava for this type of communication?. Do I need to make event bus like this one and if that's the case should I make a single instance of the bus and use it globally (with subjects)?
Yes and it's pretty amazing after you learn how to do it. Consider the following singleton class:
public class UsernameModel {
private static UsernameModel instance;
private PublishSubject<String> subject = PublishSubject.create();
public static UsernameModel instanceOf() {
if (instance == null) {
instance = new UsernameModel();
}
return instance;
}
/**
* Pass a String down to event listeners.
*/
public void setString(String string) {
subject.onNext(string);
}
/**
* Subscribe to this Observable. On event, do something e.g. replace a fragment
*/
public Observable<String> getStringObservable() {
return subject;
}
}
In your Activity be ready to receive events (e.g. have it in the onCreate):
UsernameModel usernameModel = UsernameModel.instanceOf();
//be sure to unsubscribe somewhere when activity is "dying" e.g. onDestroy
subscription = usernameModel.getStringObservable()
.subscribe(s -> {
// Do on new string event e.g. replace fragment here
}, throwable -> {
// Normally no error will happen here based on this example.
});
In you Fragment pass down the event when it occurs:
UsernameModel.instanceOf().setString("Nick");
Your activity then will do something.
Tip 1: Change the String with any object type you like.
Tip 2: It works also great if you have Dependency injection.
Update:
I wrote a more lengthy article
Currently I think my preferred approach to this question is this to:
1.) Instead of one global bus that handles everything throughout the app (and consequently gets quite unwieldy) use "local" buses for clearly defined purposes and only plug them in where you need them.
For example you might have:
One bus for sending data between your Activitys and your ApiService.
One bus for communicating between several Fragments in an Activity.
One bus that sends the currently selected app theme color to all Activitys so that they can tint all icons accordingly.
2.) Use Dagger (or maybe AndroidAnnotations if you prefer that) to make the wiring-everything-together a bit less painful (and to also avoid lots of static instances). This also makes it easier to, e. g. have a single component that deals only with storing and reading the login status in the SharedPreferences - this component could then also be wired directly to your ApiService to provide the session token for all requests.
3.) Feel free to use Subjects internally but "cast" them to Observable before handing them out to the public by calling return subject.asObservable(). This prevents other classes from pushing values into the Subject where they shouldn't be allowed to.
Define events
public class Trigger {
public Trigger() {
}
public static class Increment {
}
public static class Decrement {
}
public static class Reset {
}
}
Event controller
public class RxTrigger {
private PublishSubject<Object> mRxTrigger = PublishSubject.create();
public RxTrigger() {
// required
}
public void send(Object o) {
mRxTrigger.onNext(o);
}
public Observable<Object> toObservable() {
return mRxTrigger;
}
// check for available events
public boolean hasObservers() {
return mRxTrigger.hasObservers();
}
}
Application.class
public class App extends Application {
private RxTrigger rxTrigger;
public App getApp() {
return (App) getApplicationContext();
}
#Override
public void onCreate() {
super.onCreate();
rxTrigger = new RxTrigger();
}
public RxTrigger reactiveTrigger() {
return rxTrigger;
}
}
Register event listener wherever required
MyApplication mApp = (App) getApplicationContext();
mApp
.reactiveTrigger() // singleton object of trigger
.toObservable()
.subscribeOn(Schedulers.io()) // push to io thread
.observeOn(AndroidSchedulers.mainThread()) // listen calls on main thread
.subscribe(object -> { //receive events here
if (object instanceof Trigger.Increment) {
fabCounter.setText(String.valueOf(Integer.parseInt(fabCounter.getText().toString()) + 1));
} else if (object instanceof Trigger.Decrement) {
if (Integer.parseInt(fabCounter.getText().toString()) != 0)
fabCounter.setText(String.valueOf(Integer.parseInt(fabCounter.getText().toString()) - 1));
} else if (object instanceof Trigger.Reset) {
fabCounter.setText("0");
}
});
Send/Fire event
MyApplication mApp = (App) getApplicationContext();
//increment
mApp
.reactiveTrigger()
.send(new Trigger.Increment());
//decrement
mApp
.reactiveTrigger()
.send(new Trigger.Decrement());
Full implementation for above library with example -> RxTrigger

Store Objects in ApplicationContext

When my application goes to background , my (static and singleton) objects are cleared.
So I tried to store these objects in Applicaton Context . I am using the following code.
Accounts.create(getApplicationContext()) will be called once to store the accounts instance.
Is that possible(reliable) to store objects in Application Context ? I am not sure the following way is correct or not . please guide ..
public class Init extends Application {
private Hashtable<Object, Object> globalStore = new Hashtable<Object, Object>();
public void putToGlobalStore(Object key, Object value) {
globalStore.put(key, value);
}
public Object takeFromGlobalStore(Object key) {
return this.globalStore.get(key);
}
public void removeFromGlobalStore(Object key) {
this.globalStore.remove(key);
}
public boolean containsInGlobalStore(Object key) {
return this.globalStore.containsKey(key);
}
}
public class Accounts {
protected Accounts(String name, Context context) {
Init init = (Init) applicationContext;
init.putToGlobalStore(name, this);
}
private static Init applicationContext;
public static void create(Context context) {
if (context instanceof Application)
applicationContext = (Init) context;
else
applicationContext = (Init) context.getApplicationContext();
if (applicationContext.containsInGlobalStore(GLOBAL_NAME))
Logger.log("Warning " + GLOBAL_NAME
+ " is already created. This will remove all old datas");
new Accounts(GLOBAL_NAME, applicationContext);
}
private static final String GLOBAL_NAME = "accounts";
public static Accounts getInstance() {
try {
return (Accounts) applicationContext
.takeFromGlobalStore(GLOBAL_NAME);
} catch (Exception e) {
Logger.log("GLOBAL_NAME Lost");
return null;
}
}
Please help.
You should know that the application context itself gets destroyed if left unused for a long time in the background. So there is no guarantee that your static and singleton objects will not be cleared when the app is in background. Instead what you can do is persist your objects from time to time (either in a flat-file or shared preference or database) and restore them in the onCreate method of the Application class
I have been using this method in my application and i didn't see any problem unless my process gets killed by the OS or if there is a crash in my application and my app gets restarted.
If you think whatever data you are storing is valid for only life time of a program why don't you override OnCreate of Application object and create all your singletons there. This way you can always make sure your application has all singletons before your app starts functioning.
Application class is not permanent.
If App process killed, Application class private member variable data loss.
Using Shared Preferences.
I know this question was asked a long time ago, but here's a good article that suggests using the Application object to store data is generally not a sound design methodology.

Categories

Resources