I am aware that if I use android:process
in the manifest then the class that extends Application will be called twice. Once, for the app and a second time for the new process.
The problem is I have code in MyApplication (extends Application) which should not be called twice. I want to have a separate process but I only want the code in MyApplication#onCreate to ever be ran once per load.
I tried setting a flag in Shared Preferences but it doesn't work, probably because of the different processes issue
Any ideas?
Root cause
From SharedPreferences documentation:
Note: This class does not support use across multiple processes.
That explains why your SharePreferences
does not work.
Solution 1: Using Context.MODE_MULTI_PROCESS , but it is deprecated in API level 23
public static final int MODE_MULTI_PROCESS
This constant was deprecated in API level 23.
MODE_MULTI_PROCESS does not work reliably in some versions of Android, and furthermore does not provide any mechanism for reconciling concurrent modifications across processes. Applications should not attempt to use it. Instead, they should use an explicit cross-process data management approach such as ContentProvider.
Solution 2: Using ContentProvider
2.1. Write your own ContentProvider
onCreate()
method of MyApplication
is called for the first time or not, using this solution seems inefficient. 2.2. Use pre-defined ContentProvider
from Android
Solution 3: We can use the below flow to implement
Declare a BroadcastReceiver
that runs in the same process as your app. Because they run on the same process, so they have the same process id.
The component (activity, service, receiver, provider) that runs on a separate process (private or global), so they will have a different process id.
Implementation
Step 1. Create a class that extends from BoardcastReceiver
, named AppReceiver
.
public class AppReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Messenger messenger = intent.getParcelableExtra(MyApplication.EXTRA_MESSENGER);
int processId = intent.getIntExtra(MyApplication.EXTRA_PROCESS_ID, -1);
boolean isOnCreateCalledFirstTime = processId == Process.myPid();
Message message = Message.obtain();
message.arg1 = isOnCreateCalledFirstTime ? 1 : 0;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Step 2. Add that class to AndroidManifest.xml
<receiver
android:name=".AppReceiver"
android:enabled="true"
android:exported="true" />
Step 3. Modify your MyApplication
class
public class MyApplication extends Application {
public static final String EXTRA_MESSENGER = "EXTRA_MESSENGER";
public static final String EXTRA_PROCESS_ID = "EXTRA_PROCESS_ID";
@Override
public void onCreate() {
super.onCreate();
Intent intent = new Intent();
String pkg = getPackageName();
intent.setComponent(new ComponentName(pkg, pkg + ".AppReceiver"));
Handler handler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
boolean isOnCreateCalledFirstTime = msg.arg1 != 0;
if (isOnCreateCalledFirstTime) {
// TODO: First time onCreate() is called
} else {
// TODO: Next time onCreate() is called
}
return true;
}
});
Messenger messenger = new Messenger(handler);
intent.putExtra(EXTRA_MESSENGER, messenger);
intent.putExtra(EXTRA_PROCESS_ID, Process.myPid());
sendBroadcast(intent);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.