It is common to have Application
class as follow
public class WeNoteApplication extends MultiDexApplication {
public static WeNoteApplication instance() {
return me;
}
@Override
public void onCreate() {
super.onCreate();
me = this;
During normal circumstance, Application
's onCreate
will always be called before entry point Activity
's onCreate.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Normally, it will NOT be null.
android.util.Log.i("CHEOK", "WeNoteApplication -> " + WeNoteApplication.instance());
However, if I run the following command while the app is launched
c:\yocto>adb shell bmgr restore com.yocto.wenote
restoreStarting: 1 packages
onUpdate: 0 = com.yocto.wenote
restoreFinished: 0
done
The app will be closed. If, I tap on the app icon to launch again. This is what happens
Application
'sonCreate
is not executed!Activity
'sonCreate
is executed, andWeNoteApplication.instance()
isnull
I look at some Google's Android source code (WorkManager
for instance)
https://github.com/googlecodelabs/android-workmanager/issues/80
In their comment, they states that
// 1. The app is performing an auto-backup. Prior to O, JobScheduler could erroneously
// try to send commands to JobService in this state (b/32180780). Since neither
// Application#onCreate nor ContentProviders have run,...
It seems that, if backup related process is involved, Application
's onCreate
will not be executed!
Why it is so? Is this behavior ever documented some where?
Issue tracker
https://issuetracker.google.com/issues/138423608
Full example for bug demonstration
You can bypass your issue with this workaround.
The idea behind this is to create a custom BackupAgent
to receive notification of onRestoreFinished
event and then kill your process, so the next time you will open the app the system will create your custom Application class.
Usually using a custom BackupAgent
force you to implement the abstract methods onBackup
and onRestore
, which are used for key-value backup. Luckily if you specify android:fullBackupOnly
in the manifest, the system will use the file-based Auto Backup instead, as explained here.
First of all, create the custom BackupAgent
:
package com.yocto.cheok;
import android.app.ActivityManager;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import java.util.List;
public class CustomBackupAgent extends BackupAgent {
private Boolean isRestoreFinished = false;
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
//NO-OP - abstract method
}
@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
//NO-OP - abstract method
}
@Override
public void onRestoreFinished() {
super.onRestoreFinished();
isRestoreFinished = true;
}
@Override
public void onDestroy() {
super.onDestroy();
if (isRestoreFinished) {
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager != null) {
final List<ActivityManager.RunningAppProcessInfo> runningServices = activityManager.getRunningAppProcesses();
if (runningServices != null &&
runningServices.size() > 0 &&
runningServices.get(0).processName.equals("com.yocto.cheok")
) {
Process.killProcess(runningServices.get(0).pid);
}
}
}
}
}
then add android:backupAgent="com.yocto.cheok.CustomBackupAgent"
and android:fullBackupOnly="true"
to the Android manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yocto.cheok">
<application
android:name="com.yocto.cheok.CheokApplication"
android:allowBackup="true"
android:backupAgent="com.yocto.cheok.CustomBackupAgent"
android:fullBackupContent="@xml/my_backup_rules"
android:fullBackupOnly="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name="com.yocto.cheok.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Next time you will lunch the app after a restore you will get:
2019-07-28 22:25:33.528 6956-6956/com.yocto.cheok I/CHEOK: CheokApplication onCreate
2019-07-28 22:25:33.642 6956-6956/com.yocto.cheok I/CHEOK: In MainActivity, CheokApplication = com.yocto.cheok.CheokApplication@7b28a29