从通知中恢复应用程序和堆栈

我想恢复我的应用程序从一个状态栏通知,以完全相同的方式当用户点击其图标在启动程序。

也就是说: 我希望堆栈处于与用户离开它之前相同的状态。

在通知上设置挂起意图时的问题是它总是针对特定的活动。我不想这样。我需要重新启动应用程序,就像启动程序一样。

所以如果用户在活动 A 中,我想恢复活动 A。如果他已经从活动 A 启动了活动 B,那么当用户点击通知时,我希望显示 B,并且还原堆栈,这样当用户点击 B 中的后退按钮时,A 可以恢复。

还有几个类似题目的问题,但都没有解决我的问题。

35940 次浏览

可能有一个更简单的方法,但是你可以存储数据在 sqlite 数据库,每当你重新启动应用程序,无论你保存到数据库的状态是什么,你可以检索和设置你的值,他们需要在哪里。

只需使用 Android 在启动应用程序时使用的相同意图过滤器:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

由于您创建的从通知栏打开 ActivityIntent与用于启动应用程序的 Android 相同,因此将显示先前打开的 Activity,而不是创建一个新的 Activity

这很简单 打开清单文件并在活动属性中设置属性启动模式 单人秀

创建一个活动,然后设置类别和相应的标志..。 这是我的工作方式,我必须这样做,因为我这样做是为了支持 < em > Api lvl 8

intent.addCategory(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClass(this, YourActivity.class);


intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT|
Intent.FLAG_ACTIVITY_SINGLE_TOP);


PendingIntent pi = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);

和机器人清单

android:launchMode="singleTask"

所以这个技巧就是 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT和清单中设置的线条。

希望能帮到其他人。

我也遇到了同样的问题,并试图解决这个问题,就像@Grand 的回答:

final Intent notificationIntent = new Intent(context,YourActivity.class);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);

这是可行的,毫无疑问,但问题是当您将意图设置为 ACTION _ MAIN 时。那么您将无法将任何 bundle 设置为意图。我的意思是,您的原始数据将不会从目标活动接收到,因为 ACTION _ MAIN 不能包含任何额外的数据。

您可以将您的活动设置为 singleTask 并正常地调用您的意图,而不需要设置 ACTION _ MAIN 并从目标活动的 onNewInent ()方法接收意图。

但是请注意,如果调用 super.onNewInent (intant) ,那么将创建该活动的第二个实例。

<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.REORDER_TASKS" />


private void bringApplicationToForeground(){
ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);


if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {


List<ActivityManager.AppTask> tasksList = am.getAppTasks();
for (ActivityManager.AppTask task : tasksList){
task.moveToFront();
}
}else{


List<ActivityManager.RunningTaskInfo> tasksList = am.getRunningTasks(Integer.MAX_VALUE);
if(!tasksList.isEmpty()){
int nSize = tasksList.size();
for(int i = 0; i < nSize;  i++){
if(tasksList.get(i).topActivity.getPackageName().equals(getPackageName())){
am.moveTaskToFront(tasksList.get(i).id, 0);
}
}
}
}
}

对于您不想/不能硬编码启动器活动的情况,这个解决方案可以工作

Intent i = getPackageManager()
.getLaunchIntentForPackage(getPackageName())
.setPackage(null)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);


PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, i, 0);


return new NotificationCompat.Builder(context)
...
.setContentIntent(pendingIntent)
.build();

SetPackage (null)部分是关键在我的情况下,因为没有它的应用程序没有恢复到以前的任务。我将我的意图与 Android 启动器的意图进行了比较,发现 pkg 没有设置在那里,所以我想出了从意图中删除软件包名称的方法。

我的特殊情况是,通知是在一个库中创建的,因此我不能知道启动器活动是什么。

最终解决方案: 还原任务而不是特定活动的通知?

public class YourRootActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
    

if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
{
val extras = intent.extras // do stuffs with extras.
finish();
return;
}
// OtherWise start the app as usual
}
}