应用程序从错误的活动重新启动

时间:2015-04-07 17:18:44

标签: android

这是一个非常难题:

我打开我的应用。它启动一个活动,作为一个启动画面(ASplashscreen),在其中我从本地存储(JSON文件夹)加载一些raw数据并将其存储在singleton object的内存中(静态的)。完成此过程后,它会自动移动到主要活动(AMain

我按home button退出应用程序并运行其他应用程序,游戏等。当我重新打开我的应用程序时,应用程序在onCreate的{​​{1}}方法内崩溃,因为它尝试使用AMain中的部分数据,但数据为singleton object。因此它会在null时抛出NullPointerException。 它似乎重新启动AMain而不是ASplashscreen,因此singleton没有机会重新初始化。

这种情况在多次尝试中随机发生......

我有两个假设......

  1. 我的第一个假设,也就是我对Android操作系统的了解,当我运行其他应用程序(尤其是游戏)时,其中一个需要大量内存,因此操作系统从内存中释放了我的应用程序为了腾出空间,singleton datagarbage collected

  2. 我还假设当gc从内存中删除了我的单例时,操作系统仍保留了一些与当前运行活动的“状态”相关的数据,所以它至少知道它有在关闭应用之前,AMain活动已开启。这可以解释为什么重新打开AMain活动而不是ASplashscreen

  3. 我是对的吗?还是有另一种解释为什么我得到这个例外?欢迎任何建议/澄清。

    此外,处理此问题的最佳方法是什么?我的方法是每当我尝试使用它时检查单例数据的存在,如果它是null,那么基本上只是重新启动应用程序。这使得它通过ASplashscreen,因此JSON被初始化,一切正常。

    编辑根据要求,这是我的AndroidManifest

     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="com.android.vending.BILLING"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    
    <application
        android:name=".global.App"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:theme="@style/AppTheme">
    
        <!--SPLASH SCREEN-->
        <activity
            android:name=".activities.ASplashscreen"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
    
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    
        <!--MAIN-->
        <activity
            android:name=".activities.AMain"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme"/>
    
        <!--MENU-->
        <activity
            android:name=".activities.AMenu"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme"/>
    
        <!--HELP-->
        <activity
            android:name=".activities.AHelp"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme"/>
    
        <!--ADMOB-->
        <activity
            android:name="com.google.android.gms.ads.AdActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
            android:theme="@android:style/Theme.Translucent"/>
    
        <!--FACEBOOK LOGIN ACTIVITY (SDK)-->
        <activity
            android:name="com.facebook.LoginActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme"/>
    
        <!--This meta-data tag is required to use Google Play Services.-->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>
    
        <!--FACEBOOK STUFF-->
        <meta-data
            android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/facebook_app_id"/>
    
        <!--GOOGLE PLUS-->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>
    
        <!--CRASHLYTICS-->
        <meta-data
            android:name="com.crashlytics.ApiKey"
            android:value="9249....."/>
    
    </application>
    

    如果你们真的想要它,这里是ASplashscreen

    的内容
    /**
     * @author MAB
     */
    public class ASplashscreen extends ABase implements IIosLikeDialogListener {
    
        private final float SHEEP_WIDTH_FRAC = 0.8f;
    
        private final int SPLASHSCREEN_DELAY_MS = 500;
    
        //View references
        private View sheep_image;
    
        /** The timestamp recorded when this screen came into view. We'll used this to determine how much we'll need to keep the splash screen awake */
        private long mStartTimestamp;
    
        private IosLikeDialog mDialog;
    
        private IabHelper mIabHelper;
    
        // Listener that's called when we finish querying the items and subscriptions we own
        IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
            public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
    
                // Have we been disposed of in the meantime? If so, quit.
                if (mIabHelper == null) {
                    System.out.println("=== IAB INVENTORY PROBLEM :: WE'VE BEEN DISPOSED");
                    displayAppStoreUnavailableDialog();
                    return;
                }
    
                // Is it a failure?
                if (result.isFailure()) {
                    displayAppStoreUnavailableDialog();
                    System.out.println("=== IAB INVENTORY PROBLEM :: FAILED TO QUERY INVENTORY :: " + result);
                    return;
                }
    
                //Sync our static stuff with the app store
                HSounds.instance().populate(ASplashscreen.this, inventory);
                HLights.instance().populate(ASplashscreen.this, inventory);
    
                //Store the stuff locally just to be sure
                HStorage.persistObjectToFile(ASplashscreen.this, HVersions.SOUNDS);
                HStorage.persistObjectToFile(ASplashscreen.this, HVersions.LIGHTS);
    
                System.out.println("=== SUCCESSFULLY SYNCED WITH STORE !");
    
                jumpToMainActivity();
    
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.a_splashscreen);
    
            init();
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
    
            if (mIabHelper != null) {
                mIabHelper.dispose();
            }
            mIabHelper = null;
        }
    
        @Override
        public void onIosLikeDialogBtnsClick(int btnStringResID) {
            if (btnStringResID == IosLikeDialog.BTN_OK) {
                jumpToMainActivity();
            }
        }
    
        private void init() {
            //Get view references
            sheep_image = findViewById(R.id.splashscreen_sheep);
    
            mStartTimestamp = System.currentTimeMillis();
    
            VersionTracking.setVersions(this);
    
            //Set the width of the sheep
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) sheep_image.getLayoutParams();
            params.width = (int) ((float) UScreen.getScreenWidthInPortrait(this) * SHEEP_WIDTH_FRAC);
            sheep_image.setLayoutParams(params);
    
            mDialog = new IosLikeDialog()
                    .with(findViewById(R.id.ios_like_dialog_main_container))
                    .listen(this);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
    
                    parseJsons();
    
                    //Get the filler bar values from shared prefs
                    HBrightness.instance().retrieveFromPersist(ASplashscreen.this);
                    HSensorAndTimer.instance().retrieveFromPersist(ASplashscreen.this);
    
                    WsBuilder.build(ASplashscreen.this).getGift(new ResponseListener<EGift>() {
                        @Override
                        public void onSuccess(EGift gifts) {
                            long now = System.currentTimeMillis();
                            SimpleDateFormat fmt = new SimpleDateFormat(HJsonDataBase.GIFT_DATE_FORMAT);
                            Date start;
                            Date end;
    
                            //Handle the gifts
                            if (gifts != null && gifts.data != null && gifts.responseOK()) {
                                //Go through the SOUNDS and check if we need to set them as gifts, if not reset them
                                for (ESound sound : HSounds.instance().getValues().getSounds()) {
                                    String sku = sound.getSku(ASplashscreen.this);
                                    sound.giftStart = null;
                                    sound.giftEnd = null;
                                    for (String giftSku : gifts.data.inapps) {
                                        if (giftSku.equals(sku)) {
                                            sound.giftStart = gifts.data.start_date;
                                            sound.giftEnd = gifts.data.end_date;
                                            break;
                                        }
                                    }
                                    //Check if redeemed gift expired and if so, reset the dates
                                    checkSoundGiftExpired(sound, fmt, now);
                                }
                                //Go through the LIGHTS and check if we need to set them as gifts, if not reset them
                                for (ELight light : HLights.instance().getValues().getLights()) {
                                    String sku = light.getSku(ASplashscreen.this);
                                    light.giftStart = null;
                                    light.giftEnd = null;
                                    for (String giftSku : gifts.data.inapps) {
                                        if (giftSku.equals(sku)) {
                                            light.giftStart = gifts.data.start_date;
                                            light.giftEnd = gifts.data.end_date;
                                            break;
                                        }
                                    }
                                    //Check if redeemed gift expired and if so, reset the dates
                                    checkLightGiftExpired(light, fmt, now);
                                }
                                //Persist the data in the local storage
                                HStorage.persistObjectToFile(ASplashscreen.this, HVersions.SOUNDS);
                                HStorage.persistObjectToFile(ASplashscreen.this, HVersions.LIGHTS);
                            }
    
                            //Run the IAB helper now
                            runIabHelper();
                        }
    
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            //This might mean we're in offline mode, so check if the gifts expired
                            checkAllLightsGiftExpired();
                            checkAllSoundsGiftExpired();
    
                            //Run the IAB helper now
                            runIabHelper();
                        }
                    }, getPackageName());
                }
            });
        }
    
        /**
         * This is run on a non-UI thread !!
         */
        private void parseJsons() {
    
            /**
             * Versions
             */
            parseVersions();
    
    
            /**
             * BACKGROUND
             */
            parseBackgrounds();
            try {
                validateBackgrounds();
            } catch (NullPointerException e) {
                removeBackgroundsFile();
                parseBackgrounds();
            }
    
            /**
             * LIGHTS
             */
            parseLights();
            try {
                validateLights();
            } catch (NullPointerException e) {
                removeLightsFile();
                parseLights();
            }
    
            /**
             * SOUNDS
             */
            parseSounds();
            try {
                validateSounds();
            } catch (NullPointerException e) {
                removeSoundsFile();
                parseSounds();
            }
    
        }
    
        private void parseVersions() {
            InputStream in = getResources().openRawResource(R.raw.versions);
            EVersions versions = null;
            try {
                versions = UGson.jsonToObject(in, EVersions.class);
            } catch (Exception e) {
                System.out.println("==== PARSE ERROR :: VERSIONS :: " + e.getMessage());
                e.printStackTrace();
                return;
            }
            HVersions.instance().setValues(this, versions);
        }
    
        private void parseBackgrounds() {
            //Get the version of he JSONS at which we've last updated them from the "raw" folder
            int lastVersionBckgnds = UPersistent.getInt(ASplashscreen.this, HVersions.SHARED_PREF_LAST_JSONS_VERSION_BCKGNDS, 0);
    
            InputStream in;
            //If there are no files in local storage OR there's a new version of the JSON files that we need to retrieve
            if (!HStorage.fileExists(ASplashscreen.this, HStorage.FILE_JSON_BACKGROUNDS) ||
                    HVersions.instance().shouldUpdateFromResources(HVersions.BACKGROUNDS, lastVersionBckgnds)) { //Update from raw folder
                in = getResources().openRawResource(R.raw.backgrounds);
            } else { //Update from local storage
                in = HStorage.getInputStreamForFile(ASplashscreen.this, HStorage.FILE_JSON_BACKGROUNDS);
            }
            EBackgrounds bckgnds = null;
            try {
                bckgnds = UGson.jsonToObject(in, EBackgrounds.class);
            } catch (Exception e) {
                System.out.println("==== PARSE ERROR :: BACKGROUNDS :: " + e.getMessage());
                e.printStackTrace();
            }
            HBackgrounds.instance().setValues(this, bckgnds);
        }
    
        private void parseLights() {
            //Get the version of he JSONS at which we've last updated them from the "raw" folder
            int lastVersionLights = UPersistent.getInt(ASplashscreen.this, HVersions.SHARED_PREF_LAST_JSONS_VERSION_LIGHTS, 0);
    
            InputStream in;
            //If there are no files in local storage OR there's a new version of the JSON files that we need to retrieve
            if (!HStorage.fileExists(ASplashscreen.this, HStorage.FILE_JSON_LIGHTS) ||
                    HVersions.instance().shouldUpdateFromResources(HVersions.LIGHTS, lastVersionLights)) { //Update from raw folder
                in = getResources().openRawResource(R.raw.lights);
            } else { //Update from local storage
                in = HStorage.getInputStreamForFile(ASplashscreen.this, HStorage.FILE_JSON_LIGHTS);
            }
            ELights lights = null;
            try {
                lights = UGson.jsonToObject(in, ELights.class);
            } catch (Exception e) {
                System.out.println("==== PARSE ERROR :: LIGHTS :: " + e.getMessage());
                e.printStackTrace();
            }
            if (lights != null) {
                HLights.instance().setValues(this, lights);
            }
        }
    
        private void parseSounds() {
            int lastVersionSounds = UPersistent.getInt(ASplashscreen.this, HVersions.SHARED_PREF_LAST_JSONS_VERSION_SOUNDS, 0);
    
            InputStream in;
            //If there are no files in local storage OR there's a new version of the JSON files that we need to retrieve
            if (!HStorage.fileExists(ASplashscreen.this, HStorage.FILE_JSON_SOUNDS) ||
                    HVersions.instance().shouldUpdateFromResources(HVersions.SOUNDS, lastVersionSounds)) { //Update from raw folder
                in = getResources().openRawResource(R.raw.sounds);
            } else { //Update from local storage
                in = HStorage.getInputStreamForFile(ASplashscreen.this, HStorage.FILE_JSON_SOUNDS);
            }
            ESounds sounds = null;
            try {
                sounds = UGson.jsonToObject(in, ESounds.class);
            } catch (Exception e) {
                System.out.println("==== PARSE ERROR :: SOUNDS" + e.getMessage());
            }
            if (sounds != null) {
                HSounds.instance().setValues(this, sounds);
            }
        }
    
        private void validateBackgrounds() throws NullPointerException {
            if (HBackgrounds.instance().getValues() == null) {
                throw new NullPointerException();
            }
            if (HBackgrounds.instance().getValues().getBackgrounds() == null) {
                throw new NullPointerException();
            }
        }
    
        private void validateLights() throws NullPointerException {
            if (HLights.instance().getValues() == null) {
                throw new NullPointerException();
            }
            if (HLights.instance().getValues().getLights() == null) {
                throw new NullPointerException();
            }
        }
    
        private void validateSounds() throws NullPointerException {
            if (HSounds.instance().getValues() == null) {
                throw new NullPointerException();
            }
            if (HSounds.instance().getValues().getSounds() == null) {
                throw new NullPointerException();
            }
        }
    
        private void removeBackgroundsFile() {
            HStorage.deleteFile(this, HStorage.FILE_JSON_BACKGROUNDS);
        }
    
        private void removeLightsFile() {
            HStorage.deleteFile(this, HStorage.FILE_JSON_LIGHTS);
        }
    
        private void removeSoundsFile() {
            HStorage.deleteFile(this, HStorage.FILE_JSON_SOUNDS);
        }
    
        private void runIabHelper() {
    
            //If there's no network connection, then ... sorry
            if (!UNetwork.isNetworkAvailable(this)) {
                displayAppStoreUnavailableDialog();
                System.out.println("=== IAB ERROR :: NO NETWORK");
                return;
            }
    
            try {
                mIabHelper = new IabHelper(ASplashscreen.this, CIab.IAB_PUBLIC_KEY);
                mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
                    @Override
                    public void onIabSetupFinished(IabResult result) {
                        if (!result.isSuccess()) {
                            // Oh noes, there was a problem.
                            System.out.println("=== IAB ERROR :: CONNECTION :: " + result);
                            displayAppStoreUnavailableDialog();
                            return;
                        }
    
                        //Obtain and create the list of skus from both the LIGHTS and the SOUNDS handlers
                        List<String> skus = new ArrayList<String>();
                        skus.addAll(HSounds.instance().createSkuList(ASplashscreen.this, true));
                        skus.addAll(HLights.instance().createSkuList(ASplashscreen.this, true));
    
                        //Get the inventory
                        try {
                            mIabHelper.queryInventoryAsync(true, skus, mGotInventoryListener, new Thread.UncaughtExceptionHandler() {
                                @Override
                                public void uncaughtException(Thread thread, Throwable ex) {
                                    //                            Crashlytics.logException(ex);
                                    System.out.println("=== IAB ERROR :: query inventory crashed :: " + ex.getMessage());
                                    displayAppStoreUnavailableDialog();
                                }
                            });
                        } catch (IllegalStateException e) {
                            displayAppStoreUnavailableDialog();
                        }
                    }
                });
            } catch (NullPointerException e1) {
                //            Crashlytics.logException(e1);
                System.out.println("=== IAB ERROR :: query inventory crashed :: " + e1.getMessage());
                displayAppStoreUnavailableDialog();
            } catch (IllegalArgumentException e2) {
                //            Crashlytics.logException(e2);
                System.out.println("=== IAB ERROR :: query inventory crashed :: " + e2.getMessage());
                displayAppStoreUnavailableDialog();
            }
        }
    
        private void displayAppStoreUnavailableDialog() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (mDialog == null) {
                        return;
                    }
                    mDialog.reset()
                            .header(R.string.inapp_store_unavailable_header)
                            .subheader(R.string.inapp_store_unavailable_subheader)
                            .btnOK()
                            .show();
                }
            });
        }
    
        private void jumpToMainActivity() {
    
            int timePassed = (int) (System.currentTimeMillis() - mStartTimestamp);
    
            int delay = (timePassed > SPLASHSCREEN_DELAY_MS) ? 0 : (SPLASHSCREEN_DELAY_MS - timePassed);
    
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
    
                    //In case we need to display the tutorial, then do so
                    if (AHelp.shouldDisplayTutorial(ASplashscreen.this)) {
                        CrashReport.log("ASplashscreen -> AHelp");
                        Intent i = new Intent(ASplashscreen.this, AHelp.class);
                        i.putExtra(AHelp.BUNDLE_SHOW_TUTORIAL, true);
                        startActivity(i);
                        finish();
                        overridePendingTransition(R.anim.anim_slide_in_from_bottom, R.anim.anim_stay_put);
                        return;
                    } else { //Otherwise continue with normal flow
                        CrashReport.log("ASplashscreen -> AMain");
                        Intent i = new Intent(ASplashscreen.this, AMain.class);
                        i.putExtra(AMain.BUNDLE_DEBUGGING_CAME_FROM_SPLASHSCREEN, true);
                        startActivity(i);
                        finish();
                    }
    
                }
            }, delay);
        }
    
        private void checkAllSoundsGiftExpired() {
            SimpleDateFormat fmt = new SimpleDateFormat(HJsonDataBase.GIFT_DATE_FORMAT);
            long now = System.currentTimeMillis();
    
            for (ESound sound : HSounds.instance().getValues().getSounds()) {
                if (sound != null) {
                    checkSoundGiftExpired(sound, fmt, now);
                }
            }
        }
    
        private void checkAllLightsGiftExpired() {
            SimpleDateFormat fmt = new SimpleDateFormat(HJsonDataBase.GIFT_DATE_FORMAT);
            long now = System.currentTimeMillis();
    
            for (ELight light : HLights.instance().getValues().getLights()) {
                if (light != null) {
                    checkLightGiftExpired(light, fmt, now);
                }
            }
        }
    
        private void checkSoundGiftExpired(ESound sound, SimpleDateFormat fmt, long now) {
            if (UString.stringsExist(sound.giftExpireStart, sound.giftExpireEnd)) {
                try {
                    Date start = fmt.parse(sound.giftExpireStart);
                    Date end = fmt.parse(sound.giftExpireEnd);
                    if (now < start.getTime() || end.getTime() < now) {
                        sound.giftExpireStart = null;
                        sound.giftExpireEnd = null;
                    }
                } catch (ParseException e) {
                    //Do nothin'
                }
            }
        }
    
        private void checkLightGiftExpired
                (ELight light, SimpleDateFormat fmt, long now) {
            if (UString.stringsExist(light.giftExpireStart, light.giftExpireEnd)) {
                try {
                    Date start = fmt.parse(light.giftExpireStart);
                    Date end = fmt.parse(light.giftExpireEnd);
                    if (now < start.getTime() || end.getTime() < now) {
                        light.giftExpireStart = null;
                        light.giftExpireEnd = null;
                    }
                } catch (ParseException e) {
                    //Do nothin'
                }
            }
        }
    
    }
    

5 个答案:

答案 0 :(得分:7)

使用单身时,应该只使用getInstane方法return instance,因此您可以将支票放入其中,如下所示:

public static SingletonClass getInstance() {
    if(instance == null) {
        instance = StaticMethodToLoadInstance();
    }
    return instance;
}

我猜您可以将所有数据加载代码放在静态StaticMethodToLoadInstance()内。

<强>已更新

是的,加载数据可能会花费很多时间,因此可以使用其他方法。首先,创建自己的界面:

public static interface OnInstanceLoadedListener {
    public void onIntsanceLoaded(SingletonClass instance);
}

然后通过以下方式更改getInstance

public static void getInstance(final OnInstanceLoadedListener listener, Activity context) {
    final ProgressDialog dialog = null;
    if(instance == null) {//if there should be loading
        dialog = StaticMethodToCreateProgressDialog(context);
        dialog.show();
    }
    new Thread(new Runnable() {
        @Override
        public void run() {
            if(instance == null) {
                instance = StaticMethodToLoadInstance();
            }
            context.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    listener.onIntsanceLoaded(instance);
                    if(dialog != null && dialog.isShowing())
                        dialog.dismiss();
                }
            });
        }
    }).start();
}

您的getInstance用法从

更改
SingletonClass object = SingletonClass.getInstance();
String data = object.getData();

getInstance(new OnInstanceLoadedListener() {
    @Override
    public void onIntsanceLoaded(SingletonClass instance) {
        String data = instance.getData();
    }
}, YourActivityClass.this);

通过这种方式,您的数据将异步加载。是的,它看起来更难,但它可以显示进度对话框 - 用户可以看到应用程序仍在工作。

答案 1 :(得分:7)

这是非常标准的Android行为。当您的应用程序在后台时,无论出于何种原因,它都可以随时被杀死。 Android只会杀死托管您应用的操作系统进程。

当用户返回您的应用程序(或重新启动您的应用程序)时,Android意识到它之前已经杀死了您的应用程序,因此它创建了一个新的操作系统进程来托管您的应用程序,然后它实例化Application实例你的应用程序,然后它实例化任务堆栈中最顶层的Activity(即:应用程序进入后台时屏幕上显示的Activity),然后调用onCreate()那个Activity使Activity可以自我恢复。 Android将最新保存的Activity实例状态作为Bundle参数传递给onCreate()。通过这种方式,Activity有机会恢复自己。

您的Activity崩溃了,因为它依赖于之前应该设置的数据。在Android杀死然后重新创建应用程序的操作系统进程的情况下,这些数据就消失了。

有多种方法可以解决这个问题,其中一种方法已经使用过:

  • 在所有活动的onCreate()中,检查&#34; app初始化&#34;已使用public static变量或单例执行。如果尚未完成初始化,您知道应用程序的进程已被终止并重新创建,您需要将用户重定向到根Activity(即:重新启动应用程序)或执行此操作立即在onCreate()。{/ p>

  • Activity中进行初始化
  • onSaveInstanceState()中保存所需的数据,并将其还原到onCreate()和/或onRestoreInstanceState()或两者中。

  • 不要将这些数据保存在内存中。将其保存在数据库或其他基于非内存的持久性结构中。

注意:一般情况下,您不应使用launchMode="singleTask"。在大多数情况下,这是不必要的,并且通常会导致比解决的问题更多的问题。这与您遇到的进程终止/重新创建问题无关,但您仍应避免使用特殊启动模式singleTasksingleInstance。只有在创建HOME屏幕替换时才需要这些。

答案 2 :(得分:3)

解决方案:

  • 您不应将启动活动设置为singleTask,这意味着活动堆栈的根,而您的MainActivity应将singleTask设置为root。

  • 当你的应用程序回到前台时,在onCreate(...)中,你应该在使用它们之前检查单例类的静态引用(如果不是null),如果为null则跳回到你的启动活动(意味着重新加载和恢复)数据到静态引用中)。换句话说,如果系统回收静态引用,则只需重新启动应用程序。

希望这有帮助!

答案 3 :(得分:2)

嗯,在我看来,有两种方法可以改善你当前的重启式应用程序方法(你的方法还可以,但有点脏):

1)摆脱ASplashscreen,将加载逻辑移至某个帮助程序类,并安排从MainActivity加载数据,同时在Activity布局上显示您的启动。如果您对RelativeLayout使用MainActivity,则可以通过在视图层次结构的底部添加"match_parent"参数的不可见视图(以重叠其他视图)并在必要时使其可见来轻松实现此目的。与两个Activities和app重新启动相比,这更干净。

2)制作单身Parcelable并将其存储在onSaveInstanceState() MainActivity中。 (当然,你的单身人士凭借这种方法不再是单身人士)。在这种情况下,Android会将您的数据与MainActivity一起保存,并在OnCreate()中恢复后,所有内容都将到位。这比将其保存到SharedPreferences更简洁。

答案 4 :(得分:2)

我猜您的JSON数据采用以下格式。

{ 
    a : "A",
    b : "B",
    c : "C"
}

现在您可以拥有一个名为JsonData的类,其结构如下,

public class JsonData {
   public String a;
   public String b;
   public String c;
}

现在,您可以使用gson库将您的json数据转换为Java对象。

现在创建一个类似ObjectHolder的类,其结构如下。

public class ObjectHolder {
    public static JsonData jsonData;
}

将转换后的对象存储在ObjectHolder.jsonData中。现在,您可以随时在整个项目中访问此对象。

注意:当您从null清除应用时,此对象将变为resent apps list

这种方法对我有用,所以我希望这对你也有帮助。