简体   繁体   中英

android:process causes my MyApplication's onCreate method to be called twice. How can I prevent the code running twice?

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

  • We just need a way to store a boolean variable that indicates the 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

  • The app must declare Read/Write external storage permissions and asking runtime permissions as well. By the way, it confuses users when the first time they open the app.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM