proper way to access DB from both Activity and a started Service? - android

Short version: what is the best practice way to access the same DB from both activity and from started service?
Long version: I have a case where I start persistent service from activity. Service is populating the DB with data while activity is displaying it on screen. Neither of them is running all the time - service can run when there is no activity, and activity can run when service is not started yet. But service can only be stopped from activity (it never stops itself).
I am using subclass of SQLiteOpenHelper to access the DB. The problem I tripped over is that apparently closing DB in one SQLiteOpenHelper instance closes it in another too.
I can think of these options:
singleton pattern (single SQLiteDatabase instance in a public static var - only activity can close it (because it knows if the service is running or not)) - ugly
check if service/activity is running before closing it in the other one - ugly
build acquire/release into SQLiteOpenHelper's getReadableDatabase()/close()
I would go with 3., but this must be a very common pattern, so I'm wondering if there is such a built-in mechanism in place already - I'd hate to reinvent the wheel.
In other words, what would be the proper way to do it?

The usual paradigm for any database on Android is to have one provider open the database and handle requests as intents. This has the advantage of serializing requests.
Opening databases from different code is completely non-standard.
If you really need an app to notice each time something is added, a broadcast intent from the provider might be the answer.

I have solved the problem using retain/release counter:
public class DBHandler extends SQLiteOpenHelper
{
private static int retainCount = 0;
#Override
public synchronized SQLiteDatabase getReadableDatabase()
{
DBHandler.retainCount++;
return super.getReadableDatabase();
}
#Override
public synchronized SQLiteDatabase getWritableDatabase()
{
DBHandler.retainCount++;
return super.getWritableDatabase();
}
#Override
public synchronized void close()
{
DBHandler.retainCount--;
if (DBHandler.retainCount == 0)
super.close();
}
}
}

Related

Why extend the Android Application class?

An extended Application class can declare global variables. Are there other reasons?
Introduction:
If we consider an apk file in our mobile, it is comprised of
multiple useful blocks such as, Activitys, Services and
others.
These components do not communicate with each other regularly and
not forget they have their own life cycle. which indicate that
they may be active at one time and inactive the other moment.
Requirements:
Sometimes we may require a scenario where we need to access a
variable and its states across the entire Application regardless of
the Activity the user is using,
An example is that a user might need to access a variable that holds his
personnel information (e.g. name) that has to be accessed across the
Application,
We can use SQLite but creating a Cursor and closing it again and
again is not good on performance,
We could use Intents to pass the data but it's clumsy and activity
itself may not exist at a certain scenario depending on the memory-availability.
Uses of Application Class:
Access to variables across the Application,
You can use the Application to start certain things like analytics
etc. since the application class is started before Activitys or
Servicess are being run,
There is an overridden method called onConfigurationChanged() that is
triggered when the application configuration is changed (horizontal
to vertical & vice-versa),
There is also an event called onLowMemory() that is triggered when
the Android device is low on memory.
Application class is the object that has the full lifecycle of your application. It is your highest layer as an application. example possible usages:
You can add what you need when the application is started by overriding onCreate in the Application class.
store global variables that jump from Activity to Activity. Like Asynctask.
etc
Sometimes you want to store data, like global variables which need to be accessed from multiple Activities - sometimes everywhere within the application. In this case, the Application object will help you.
For example, if you want to get the basic authentication data for each http request, you can implement the methods for authentication data in the application object.
After this,you can get the username and password in any of the activities like this:
MyApplication mApplication = (MyApplication)getApplicationContext();
String username = mApplication.getUsername();
String password = mApplication.getPassword();
And finally, do remember to use the Application object as a singleton object:
public class MyApplication extends Application {
private static MyApplication singleton;
public MyApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton = this;
}
}
For more information, please Click Application Class
Offhand, I can't think of a real scenario in which extending Application is either preferable to another approach or necessary to accomplish something. If you have an expensive, frequently used object you can initialize it in an IntentService when you detect that the object isn't currently present. Application itself runs on the UI thread, while IntentService runs on its own thread.
I prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences. There are also ways to pass data from a Fragment to its parent Activity using interfaces.
The Application class is a singleton that you can access from any activity or anywhere else you have a Context object.
You also get a little bit of lifecycle.
You could use the Application's onCreate method to instantiate expensive, but frequently used objects like an analytics helper. Then you can access and use those objects everywhere.
Best use of application class.
Example: Suppose you need to restart your alarm manager on boot completed.
public class BaseJuiceApplication extends Application implements BootListener {
public static BaseJuiceApplication instance = null;
public static Context getInstance() {
if (null == instance) {
instance = new BaseJuiceApplication();
}
return instance;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onBootCompleted(Context context, Intent intent) {
new PushService().scheduleService(getInstance());
//startToNotify(context);
}
Not an answer but an observation: keep in mind that the data in the extended application object should not be tied to an instance of an activity, as it is possible that you have two instances of the same activity running at the same time (one in the foreground and one not being visible).
For example, you start your activity normally through the launcher, then "minimize" it. You then start another app (ie Tasker) which starts another instance of your activitiy, for example in order to create a shortcut, because your app supports android.intent.action.CREATE_SHORTCUT. If the shortcut is then created and this shortcut-creating invocation of the activity modified the data the application object, then the activity running in the background will start to use this modified application object once it is brought back to the foreground.
I see that this question is missing an answer. I extend Application because I use Bill Pugh Singleton implementation (see reference) and some of my singletons need context. The Application class looks like this:
public class MyApplication extends Application {
private static final String TAG = MyApplication.class.getSimpleName();
private static MyApplication sInstance;
#Contract(pure = true)
#Nullable
public static Context getAppContext() {
return sInstance;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() called");
sInstance = this;
}
}
And the singletons look like this:
public class DataManager {
private static final String TAG = DataManager.class.getSimpleName();
#Contract(pure = true)
public static DataManager getInstance() {
return InstanceHolder.INSTANCE;
}
private DataManager() {
doStuffRequiringContext(MyApplication.getAppContext());
}
private static final class InstanceHolder {
#SuppressLint("StaticFieldLeak")
private static final DataManager INSTANCE = new DataManager();
}
}
This way I don't need to have a context every time I'm using a singleton and get lazy synchronized initialization with minimal amount of code.
Tip: updating Android Studio singleton template saves a lot of time.
I think you can use the Application class for many things, but they are all tied to your need to do some stuff BEFORE any of your Activities or Services are started.
For instance, in my application I use custom fonts. Instead of calling
Typeface.createFromAsset()
from every Activity to get references for my fonts from the Assets folder (this is bad because it will result in memory leak as you are keeping a reference to assets every time you call that method), I do this from the onCreate() method in my Application class:
private App appInstance;
Typeface quickSandRegular;
...
public void onCreate() {
super.onCreate();
appInstance = this;
quicksandRegular = Typeface.createFromAsset(getApplicationContext().getAssets(),
"fonts/Quicksand-Regular.otf");
...
}
Now, I also have a method defined like this:
public static App getAppInstance() {
return appInstance;
}
and this:
public Typeface getQuickSandRegular() {
return quicksandRegular;
}
So, from anywhere in my application, all I have to do is:
App.getAppInstance().getQuickSandRegular()
Another use for the Application class for me is to check if the device is connected to the Internet BEFORE activities and services that require a connection actually start and take necessary action.
Source: https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class
In many apps, there's no need to work with an application class directly. However, there are a few acceptable uses of a custom application class:
Specialized tasks that need to run before the creation of your first activity
Global initialization that needs to be shared across all components (crash reporting, persistence)
Static methods for easy access to static immutable data such as a shared network client object
You should never store mutable instance data inside the Application object because if you assume that your data will stay there, your application will inevitably crash at some point with a NullPointerException. The application object is not guaranteed to stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
To add onto the other answers that state that you might wish store variables in the application scope, for any long-running threads or other objects that need binding to your application where you are NOT using an activity (application is not an activity).. such as not being able to request a binded service.. then binding to the application instance is preferred. The only obvious warning with this approach is that the objects live for as long as the application is alive, so more implicit control over memory is required else you'll encounter memory-related problems like leaks.
Something else you may find useful is that in the order of operations, the application starts first before any activities. In this timeframe, you can prepare any necessary housekeeping that would occur before your first activity if you so desired.
2018-10-19 11:31:55.246 8643-8643/: application created
2018-10-19 11:31:55.630 8643-8643/: activity created
You can access variables to any class without creating objects, if its extended by Application. They can be called globally and their state is maintained till application is not killed.
The use of extending application just make your application sure for any kind of operation that you want throughout your application running period. Now it may be any kind of variables and suppose if you want to fetch some data from server then you can put your asynctask in application so it will fetch each time and continuously, so that you will get a updated data automatically.. Use this link for more knowledge....
http://www.intridea.com/blog/2011/5/24/how-to-use-application-object-of-android

How to keep a global db4o throughout the lifecycle of an android application

We are developing an Android application that uses db4o for storing various objects throughout multiple activities and services. We are looking for the best approach on working with db4o and specifically when to open and close the db. We don’t want to close the db after each single store operation and reopen it on every single retrieve operation because that could impact the speed of the application as opening and closing is hard on the processor. We prefer to keep a global state of the db4o that can be used throughout the app's lifecycle.
I was reading here
global db4o database for multiple activities
that is a good idea to keep the database on a Custom Application Object and get an instance when we need it:
public class MyApplication extends Application {
private volatile ObjectContainer container;
#Override
public void onCreate() {
super.onCreate();
// the application object is a regular Android context,
// So you can get the required info`
this.container = Db4oEmbedded.openFile(...)
}
#Override
public void onTerminate() {
super.onTerminate();
// if something was not finished, better rollback
container.rollback();
container.close();
}
public ObjectContainer database(){
return container;
}
}
However, I realised that the onTerminate() method of the Application exists only for emulation purposes and is never executed on an actual phone. And my question is, if the onTerminate() is never called where should we close the db object, and was is the best strategy on opening and closing?
You can create Lazy load singleton instance in your application class and initialize(Open) it in Launching Activity's OnCreate method and Close it inside onDestroy.

Android : Persisting object(s) between BroadcastReceiver.onReceive() calls

I have an app that receives SMS and starts certain "work", now this work is done through Camera and some other third party APIs. So when I receive the appropriate START message (SMS) for my app, I start the work and it continues till the app receives STOP message from remote device.
The receiver is registered in the manifest.xml file and works fine otherwise.
Now the problem is, my app starts the work fine on receiving the START message, but when I receive STOP message after some time, I cannot really stop the work because the handles/object references I have for the camera and the third party API both are null. I do not have any control over either of them - and can't make them singleton. So I need to persist those object references between two calls of the BroadcastReceiver, and I can't figure out a way to do this properly. For now, I have just made these two static members of the class and it works fine, but it's not really a good solution. What's the best way to handle situation in this case? How can I use the initialized objects between multiple onReceive() calls of the BroadcastReceiver?
Any help/pointers would be highly appreciated!
TIA,
- Manish
You can't use singleton that class, but you can create a normal class and have it singleton. That class has a HashMap and stores your api and camera objects with a key. When you need to stop particular task, you can find it by some key and stops them by that object.
When you start the task store that object in that singleton and when you want to stop that find that object from the hashmap and stops/dispose the task.
I suggest you to create a singleton object volatile.
private static volatile Utils _instance = null;
public static Utils Instance() {
if (_instance == null) {
synchronized (Utils.class) {
_instance = new Utils();
}
}
return _instance;
}
You can also add the object reference in the ApplicationClass i.e. a class extended from Application class. your application class persist in memory until any Activity or Service is running. It will only killed after all the Activity and Service killed.
I think this is a better approach that Static field.
But this is also not Full-Proof. I am also searching for this problem.

Android Application life cycle and singelton

well most of us familiar with this pattern:
public class MySingeltone {
public String mSomeReferenceTypeData;
public int mSomeValueTypeData;
private static MySingeltone mInstance;
private MySingeltone() {
}
public static MySingeltone getInstance() {
if (mInstance == null) {
mInstance = new MySingeltone();
}
return mInstance;
}
}
my problem is that I've found recently that the mInstance don't equal null after activity using him been destroyed, or when the whole application suppose to be clause, for example:
public class SomeActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MySingeltone mySingeltone = MySingeltone.getInstance();
mySingeltone.mSomeReferenceTypeData = "some value";
}
}
when launching "SomeActivity" next time after closing the whole applications running activities (say 10 seconds after..) the mInstance still holds the same reference, with the same values on his fields.
why does it happening?
what am I missing?
when android garbage collecting static members belongs to application?
Since "mInstance" is a static variable it will not get null when you close your application. Closing of application doesn't means that your application got destroyed.
Also there is no concept of Closing your Android app. If you get out of your app it will not get destroyed at the same time. Android OS handles it internally when to close the app when it is no more in use. In case of memory shortage when android decides to destroy the app then this static variable will also got null.
You can not control when exactly Java objects become garbage collected. An object becomes eligible for garbage collection when there are no more (non-circular) references to it.
With Android, further, you can not control when your Activity gets removed from memory.
why does it happening?
what am I missing?
when android garbage collecting static members belongs to application?
Ok first, as others said, there is no close application concept on Android as the android OS manages lifecycle of your application process on their own.
Second, you did the wrong test - if instead of closing all apps you would do the opposite - that is - fill up memory by starting more and more apps, then eventually your application's memory would be cleaned up to be used by other applications and this includes all static mebers as well as instance members! then, you will see that the static variable WILL BE NULL as you expected.
They just "lazily" clean up memory, if there's enough memory then you application might never get cleaned up.
Actually, there is no way around it, as far as i know, there is no way to grauntee an object would not be cleaned up at any point from the device memory. in somecases it leads to bad behaviour. such as if the singleton does heavy processing on its creation, calling getInstance might get your UI stuck, or even make your app crash due to irresponsibleness.

Store shared object for all activities

I have a class:
public class DbAdapter {
private DbHelper dbHelper;
private SQLiteDatabase db;
private final Context context;
...
}
and i want have it available in all activities. The class provides access to my sqlite database.
What is the most elegant and neat way to do it? I thought about creating object in each activity (it should "connect" me to the same database, right?).
You can achieve it extending the Application class. Google has this to say about it:
Base class for those who need to
maintain global application state. You
can provide your own implementation by
specifying its name in your
AndroidManifest.xml's
tag, which will cause that class to be
instantiated for you when the process
for your application/package is
created.
There is normally no need to subclass
Application. In most situation, static
singletons can provide the same
functionality in a more modular way.
If your singleton needs a global
context (for example to register
broadcast receivers), the function to
retrieve it can be given a Context
which internally uses
Context.getApplicationContext() when
first constructing the singleton.
I have done it myself like this:
public class App extends Application {
private DbHelper dbHelper;
#Override
public void onCreate() {
super.onCreate();
dbHelper = new DbHelper(this);
}
public SQLiteDatabase getDatabase(){
return dbHelper.getWritableDatabase();
}
#Override
public void onTerminate() {
super.onTerminate();
dbHelper.close();
}
}
Then you just access it calling getApplicationContext.getDatabase()
You may take a look at the Singleton Pattern, it gives the opportunity to make a class have only one object created and to make this object accessible from everywhere. Hope this helps.
I think the best way to implement this is to use Service. The Service will keep reference to DbAdapter and all your activities will connect to the Service. When activity is connected to the service it'll keep the reference to it and every time it needs db access it'll use to get the DbAdapter. Using this approach you'll have control over your db connection. If no activities are connected to the service than no one is using the db connection and you can free it.
Have a look at ContentProviders. They're made for accessing data. And regardless of all the emphasis on "sharing data between applications" in the link, they don't have to be public - you can use them as a centralized way to access data in your app.
This blog entry on 'Writing Your Own ContentProvider' shows some code for setting up a ContentProvider that works within one application.

Categories

Resources