Ensure Android app runs in a single process - java

We've recently started running into crashes in our Android app due to the app being open in multiple processes. Several different errors point towards that. For instance this error:
com.google.firebase.database.DatabaseException: Failed to gain
exclusive lock to Firebase Database's offline persistence. This
generally means you are using Firebase Database from multiple
processes in your app. Keep in mind that multi-process Android apps
execute the code in your Application class in all processes, so you
may need to avoid initializing FirebaseDatabase in your Application
class. If you are intentionally using Firebase Database from multiple
processes, you can only enable offline persistence (i.e. call
setPersistenceEnabled(true)) in one of them.
We are also seeing similar errors from SQLite and H2. This is a new issue and we have not explicitly allowed multiple processes to run. Nothing in our AndroidManifest.xml specifies a custom android:process attribute.
I suspect that some third party library is causing this. How do I identify the root cause of the multiple processes and how do I prevent it?
Another of our apps is connecting to this app via a ContentProvider. At first I thought that it having android:multiprocess="true" was the culprit but changing it to "false" did not help. I still suspect that the other app is somehow triggering the creation of a new process. This is how to the ContentProvider is defined:
<provider
android:name=".DegooContentProvider"
android:authorities="${applicationId}.DegooContentProvider"
android:exported="true"
android:protectionLevel="signature"
android:multiprocess="false">
</provider>

You can check in your applicaition class if there is foreign process. Here is an example:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
if (!isMainProcess()) {
// Do not call thread unsafe logic. Just return
return;
}
// Thread unsafe logic.
...
}
private boolean isMainProcess() {
int pid = android.os.Process.myPid();
ActivityManager manager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
String currentProcName = processInfo.processName;
if (processInfo.pid == pid) {
if (TextUtils.equals(currentProcName, BuildConfig.APPLICATION_ID)) {
return true;
}
}
}
return false;
}
}

Looks like you are calling the method setPersistenceEnabled() multiple times.
Ensure it is not. You can do this in a several ways.
The preferred method will be to place it only in the onCreate() method of the default Application class if you are extending one.
Another solution will be to place it in the static block of any class.
static {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Or you can even set a static boolean variable say, inFirebaseInstanceInitialized and call setPersistenceEnabled() only if it is not true already.

Related

Android How to Inject application into class where context is not present?

I have an android application
#HiltAndroidApp
class MyApp extends Application {
static MyApp app;
static MyApp getApp() {
return app;
}
#Override
public void onCreate() {
super.onCreate();
app = this;
}
}
and I am trying to use it inside a class
class AppStateUsingClass {
public void mymethod() {
MyApp app = MyApp.getApp();
//use app
}
}
Now I can access the app where I don't have the context but I am not sure if its correct way of doing.
My understanding is that the application life cycle is through out app start and stop, therefore its lives as a Singleton so it shall be fine but not sure.
Isn't there any simpler cleaner API to access app, I have app state in MyApp class which I would like to access where context is absent?
Any suggestions are highly appreciated?
What you are doing is a fairly common pattern, and shouldn't really cause problems.
The application class can be treated as a singleton that is alive as long as any part of your application is alive.
The docs specifically state that this class is used to hold application state.
However, depending your actual design, the kind of state information you want to hold and where you want to access it, you may want to create your own singleton, independent of the application class and use that.
Or, you may want to initialize your AppStateUsingClass with a state object passed in the constructor.
This is a design decision, and if you want more opinions on it, create a working code example and post it on https://codereview.stackexchange.com

Android - getRunningservices(ActivityManager) deprecated

I want to know MyService.java is working or not?
I create this method:
private boolean isServiceAlive(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
it works fine but manager.getRunningServices() is deprecated from API 26. So have we another good solution(method) to get a list of the services that are currently running?
Despite it doesn't answer your question, I think you still can use this method for your own services:
For backwards compatibility, it will still return the caller's own services.
If you'd just like to remove the deprecation warning, use #SuppressWarnings("deprecation")
Welcome to Android O
Another Annoying bug of android Oreo, there is just Deprecated annotation and there is no other way to do this. but maybe in the past android developers decide to create alternative function.
For now as Document says continue to use getRunningServices and use #SuppressWarnings("deprecation") above of your function to get rid of warning.
As of Build.VERSION_CODES.O, this method is no longer available to third party applications. For backwards compatibility, it will still return the caller's own services.
Here's what you do. If the services you are using are within your own application, just make a singleton that has a boolean variable for started or stopped. When the service starts, make sure to update that variable.
public class SingletonServiceManager {
public static boolean isMyServiceRunning = false;
}
The above is literally all i use for a small singleton class, later, in some other class, where you want to know if the service is running...
if(SingletonServiceManager.isMyServiceRunning == true){
// do something
}
You just have to manage where and when this value is updated. For instance, set it to true when you start the service (inside the service). Then, update the boolean to false when you stop the service (from inside the service)

Reasons for objects becoming null in Extended Application class

In my android application, I have extended Application class. I am having some meta data which I do not want to re-initialize again and again. I initialize them in Application class and then use them.
private SampleSettings getSettings(){
return sampleSettings;
}
public class SampleApplication extends Application {
public void onCreate(){
super.onCreate();
sampleSettings = getSettingsFromDB();
}
}
Here getSettings returns null in some cases when accessed in application using applicationContext.
Sometime I am getting null pointer exception for such properties. I have seen when the app goes to background it occurs but not frequently.
My understanding is that those values should not become as long as application is started.
What am I missing which is causing them to become null?
Thanks
Your process does not live forever. When you are not in the foreground, your process may be terminated at any time by Android, to free up system RAM for other apps.
A custom Application object, or any static fields, are only for caching and other in-flight data. Your app needs to be able to start up, from any activity, lazy-initializing all of that as needed.

Start Application with flags

I have an application:
public class TestApplication extends Application {
#Override
public void attachBaseContext(Context context){
if (SomeGlobalState.doStuff) {
doStuff();
}
}
}
I'd like to do some set up of this application in the attachBaseContext that can change dependent on a flag I can pass that isn't always passed, so I don't want to add it to the metadata of the manifest.
Is there something in the Android framework that I don't know about where I can pass "Intent-like" extras to an Application or am I going to have to do something hackish to let it know that I want its state to change?
Is there something in the Android framework that I don't know about where I can pass "Intent-like" extras to an Application
No, but you don't need it.
or am I going to have to do something hackish to let it know that I want its state to change?
If the state is persistent -- and your question suggests that it is -- just use a SharedPreferences for that state. The Application can retrieve those and use them. And, if the Application needs to proactively take steps on a state change, the Application can register a listener for SharedPreferences changes.
If the state is not persistent -- meaning that the app always starts in state A and may switch to states B-Z based on runtime work -- just call a method on the Application at the point of the state change. The Application can hold onto the state in a data member.
To do this without a file, you can use adb shell setprop <propname> <value> and then in your attachBaseContext you can do something like this
Process proc = Runtime.getRuntime().exec(new String[]{"/system/bin/getprop", MY_PROPERTY});
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String propertyValue = reader.readLine();
Then you can verify that propertyValue is equal to whatever you were expecting. Great for testing.

Android Application class - lifecycle of field members

I have Android application and own Application derived class holding some internal data.
Among other there are some string fields. The problem is that if I put the application in foreground, work on other application, switch back to my app again, the app may be restarted because it got killed by system. Unfortunatelly the Application object seems not to be created again because the onCreate method of application object doesn't get called and all fields are set to null. My Activity gets recreated but all Application's object fields are null. When is the Application.onCreate method called? How to handle it?
there is no onCreate that you can register to.in later API's there's a way to register to the Activity lifecycle functions. and then you can do what ever you want.
basically, what you should do is use SharedPrefrences for storing information.
what I would do is:
class MyApp extends Application {
private static String someResource = null;
public static String getSomeResource(Context context) {
if(someResource == null) {
SharedPrefrences prefs = (SharedPrefrences)
context.getSystemService(Context.SHARED_PREFRENCES);
someResource = prefs.getString(SOME_RESOURCE, null);
}
return someResource;
}
Application onCreate() will called only for one time during its life-cycle, i.e.. only when application is started.
As suggested by thepoosh below answer is valid ,if your application is killed,still the data is saved in shared preference.

Categories

Resources