从通知意图开始时保持活动状态

时间:2016-01-23 13:48:12

标签: android android-intent android-notifications

我有一个应用程序,它以一个Activity开始,在显示主Activity之前加载东西。通常启动应用程序MyApplication - > MyLoadingActivity - > MyMainActivity。在MyMainActivity中有一个带有RecyclerViews和其他内容的ViewPager。导航到应用程序中的其他活动以及从应用程序中的其他活动导航时,MyMainActivity中的状态已正确保存和恢复,但是当从通知启动MyMainActivity时,所有状态都会被清除,因为Android重新启动该活动。

通知是从服务检查来自远程服务器的更新创建的。找到更新后,新数据将存储在SQLite数据库中,并创建有关此数据的通知。单击此通知时,MyMainActicity已启动,但状态丢失。

关注official guide,以下是我在服务中创建通知的方法:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
    .setSmallIcon(R.drawable.foo)
    .setAutoCancel(true)
    .setContentTitle("title")
    .setContentText("text")
    .setStyle(new NotificationCompat.BigTextStyle().bigText("A long text will go here if we are on Lollipop or above."));

Intent notifyIntent = new Intent(context, MyMainActivity.class);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

PendingIntent notifyPendingIntent = PendingIntent.getActivity(context, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(notifyPendingIntent);

NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(666, builder.build());

我尝试以各种方式组合Intent.FLAG_***,但我无法使其正常工作。我无法弄清楚这一点,因此这个问题。

打开通知时我想要达到的目的是:

  1. 如果应用程序未运行,请正常启动应用程序并转至MyMainActivity
  2. 如果应用程序正在运行并且MyMainActivity处于活动状态,请将其带到具有现有状态的前面并运行几行代码。
  3. 如果应用程序正在运行且另一个Activity正在运行,请返回MyMainActivity,最好使用现有堆栈。大多数其他活动都是MyMainActivity的孩子。
  4. 使用当前代码会发生什么:

    1. 使用Intent.FLAG_ACTIVITY_NEW_TASK创建一个MyMainActivity实例,该实例具有空状态,即使其描述状态为
    2.   

      使用此标志时,如果某个任务已在运行该活动   你现在开始,然后一个新的活动将不会开始;   相反,当前的任务将被简单地带到前面   屏幕显示它最后的状态。

      1. 在创建新Intent.FLAG_ACTIVITY_CLEAR_TASK后,在现有onDestroy()上使用MyMainActivity次来电MyMainActivity。这没什么用。
      2. 我尝试过其他一些事情:

        一个。正如应用程序here所述,将Intent设置为应用程序正常启动,不起作用。

        B中。标志的各种组合无法提供所需的行为。

        ℃。 Stackoverflow上有各种其他答案。

        供参考,这是我的清单文件:

        <?xml version="1.0" encoding="utf-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.my.app"
            android:versionCode="1"
            android:versionName="1.0" >
        
            <uses-sdk
                android:minSdkVersion="11"
                android:targetSdkVersion="22" />
        
            <uses-permission android:name="android.permission.INTERNET"/>
            <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
            <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        
            <application
                android:allowBackup="true"
                android:icon="@drawable/ic_launcher"
                android:label="@string/my_app_name"
                android:theme="@style/MyTheme"
                android:name=".MyApplication" >
                <activity
                    android:name=".activities.MyLoadingActivity"
                    android:icon="@drawable/ic_launcher"
                    android:screenOrientation="portrait" >
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN" />
                        <category android:name="android.intent.category.LAUNCHER" />
                    </intent-filter>
                </activity>
                <activity
                    android:name=".activities.MyMainActivity"
                    android:icon="@drawable/ic_launcher"
                    android:label="@string/my_app_name"
                    android:screenOrientation="portrait" >
                </activity>
                <activity
                    android:name=".activities.AnotherActivity"
                    android:label="@string/aa_title"
                    android:icon="@drawable/ic_launcher"
                    android:parentActivityName=".activities.MyMainActivity"
                    android:screenOrientation="portrait">
                    <meta-data
                        android:name="android.support.PARENT_ACTIVITY"
                        android:value=".activities.MyMainActivity" >
                    </meta-data>
                </activity>
        
                <!-- More children activities of MyMainActivity here -->
        
                <receiver android:name=".services.ScheduleUpdateReciever">
                    <intent-filter>
                        <action android:name="android.intent.action.BOOT_COMPLETED" />
                        <action android:name="com.my.app.action.ScheduleUpdateReceiver"/>
                    </intent-filter>
                </receiver>
                <receiver android:name=".services.StartUpdateReceiver" />
        
                <service android:enabled="true" android:name=".services.UpdateService" />
        
            </application>
        
        </manifest>
        

        更新:保存/恢复

        以下是MyMainActivity的保存和恢复方式。我意识到这可能需要一些清洁。也许它与问题有关。为简洁起见,省略了该类的其他部分。如上所述,在应用程序内部导航时,所有保存和恢复都可以正常工作。

        private ShoppingList mShoppingList;
        private FilteredRecipes mFilteredRecipes;
        private MainFragment mMainFragment;
        
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_activity_layout);
        
            // Start the Broadcast receiver that creates notifications if new data is found.
            startService(new Intent(this, ScheduleUpdateReciever.class));
            sendBroadcast(new Intent(SCHEDULE_UPDATE_RECEIVER_BROADCAST));
        
            // Setup Toolbar, NavigationView, DrawerLayout etc. here. No state restored for these widgets.
        
            if (mShoppingList == null)
            {
                mShoppingList = new ShoppingList(this);
            }
        
            if (mFilteredRecipes == null)
            {
                mFilteredRecipes = new FilteredRecipes(this);
            }
        
            if (savedInstanceState == null)
            {
                mMainFragment = new MainFragment();
            }
            else
            {
                restoreState(savedInstanceState);
            }
        
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.content_frame, mMainFragment, FragmentConstants.MAIN_FRAGMENT_TAG)
                    .commit();
        
        
        }
        
        @Override
        protected void onSaveInstanceState(Bundle outState)
        {
            super.onSaveInstanceState(outState);
        
            // These calls adds stuff directly to the Bundle instance, be it basic variables, lists or Parcelable classes.
            mShoppingList.onSaveInstanceState(outState);
            mFilteredRecipes.onSaveInstanceState(outState);
            getSupportFragmentManager().putFragment(outState, SAVE_RESTORE_MAIN_FRAGMENT, mMainFragment);
        }
        
        
        private void restoreState(Bundle savedInstanceState)
        {
            // These calls restores stuff directly from the Bundle instance, be it basic variables, lists or Parcelable classes.
            mShoppingList.onRestoreInstanceState(savedInstanceState);
            mFilteredRecipes.onRestoreInstanceState(savedInstanceState);
            mMainFragment = (MainFragment) getSupportFragmentManager().getFragment(savedInstanceState, SAVE_RESTORE_MAIN_FRAGMENT);
        }
        

1 个答案:

答案 0 :(得分:0)

来自android文档:http://developer.android.com/reference/android/content/Intent.html

关于FLAG_ACTIVITY_CLEAR_TOP:

  

如果设置,则正在启动的活动已在运行中   当前任务,然后而不是启动它的新实例   活动,其上的所有其他活动将被关闭   这个意图将作为一个传递到(现在在顶部)旧活动   新的意图。

关于FLAG_ACTIVITY_SINGLE_TOP:

  

如果设置,则如果活动已在运行,则不会启动该活动   历史堆栈的顶部。

这听起来几乎是你想要实现的目标。试试这个:

notifyIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

编辑:

您正在使用savedInstanceState保存活动中的数据,我建议您不要使用此方法,因为它不可靠,您可以从文档(http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState%28android.os.Bundle%29)推断出onSaveInstanceState ()根本无法调用:

  

不要将此方法与活动生命周期回调混淆,例如   onPause(),在放置活动时始终调用   背景或正在破坏的路上,或onStop()   在破坏之前召集。 onPause()和onStop()的一个例子   被调用,而不是这个方法是用户导航回来的时候   活动B到活动A:没有必要打电话   B上的onSaveInstanceState(Bundle)因为那个特定的实例会   永远不会被恢复,所以系统避免调用它。一个例子   调用onPause()而不是onSaveInstanceState(Bundle)是什么时候   活动B在活动A前面启动:系统可以避免   在活动A上调用onSaveInstanceState(Bundle),如果它没有被杀死   在B的生命周期中,因为A的用户界面的状态   将保持不变。

您应该使用更持久的方式来存储键/值信息,例如sharedPreferences或数据库,并在onCreate方法中检索这些值。这里有更多相关信息:http://developer.android.com/training/basics/data-storage/index.html

您还可以在此处查看我的答案:https://stackoverflow.com/a/35023304/5837758,以便您轻松使用sharedPreferences。