如果 launchmode 设置为 'singleTop',如何防止 pendingintent 重新创建 activity?
How to prevent pendingintent from recreating an activity if launchmode set to 'singleTop'?
我在使用 Packagemanager 安装我的应用程序更新时遇到了一些问题。我的应用程序是为我公司的内部使用而设计的,因此我们不能使用 Google Play 来处理这些更新。因此在启动应用程序后,它会快速检查版本并下载更新(如果有)。
这是我在 activity 中尝试过的(该文件是同一应用程序的下载版本和较新版本)
public void installNewApkVersion(File file){
PackageInstaller.Session session = null;
try{
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
addApkToInstallSession(session, file);
// Create an install status receiver.
Context context = LoginActivity.this;
Intent intent = new Intent(context, LoginActivity.class);
intent.setAction(ACTION_INSTALL_COMPLETE);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();
// Commit the session (this will start the installation workflow).
session.commit(statusReceiver);
} catch(IOException e){
throw new RuntimeException("Couldn't install package", e);
} catch (RuntimeException e){
if(session != null){
session.abandon();
}
throw e;
}
}
为了让它起作用,我必须像这样覆盖 onNewIntent:
@Override
protected void onNewIntent(Intent intent) {
Bundle extras = intent.getExtras();
boolean isloggedin = pref.getBoolean("Loggedin", false);
if (ACTION_INSTALL_COMPLETE.equals(intent.getAction())) {
int status = extras.getInt(PackageInstaller.EXTRA_STATUS);
String message = extras.getString(PackageInstaller.EXTRA_STATUS_MESSAGE);
switch (status) {
case PackageInstaller.STATUS_PENDING_USER_ACTION:
// This test app isn't privileged, so the user has to confirm the install.
Intent confirmIntent = (Intent) extras.get(Intent.EXTRA_INTENT);
startActivity(confirmIntent);
break;
case PackageInstaller.STATUS_SUCCESS:
Log.w(TAG, "Install finished successfully");
break;
case PackageInstaller.STATUS_FAILURE:
Toast.makeText(this, "Install failed!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed - status failure.");
break;
case PackageInstaller.STATUS_FAILURE_ABORTED:
Toast.makeText(this, "Install failure aborted!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Aborted.");
break;
case PackageInstaller.STATUS_FAILURE_BLOCKED:
Toast.makeText(this, "Install: failure blocked!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Blocked.");
break;
case PackageInstaller.STATUS_FAILURE_CONFLICT:
Toast.makeText(this, "Install: failure conflicted!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Found conflicts.");
break;
case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE:
Toast.makeText(this, "Install: incompatible!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Incompatible.");
break;
case PackageInstaller.STATUS_FAILURE_INVALID:
Toast.makeText(this, "Install: invalid!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Invalid.");
break;
case PackageInstaller.STATUS_FAILURE_STORAGE:
Toast.makeText(this, "Install failed: storage error! " + status + ", " + message,
Toast.LENGTH_SHORT).show();
Log.w(TAG, "Install failed. Storage error.");
break;
default:
Toast.makeText(this, "Unrecognized status received from installer: " + status,
Toast.LENGTH_SHORT).show();
Log.w(TAG, "Dont know what happened");
}
}
}
此 Activity 以 singleTop 模式运行以接收安装结果。它运行良好,除非用户在提示时取消它。
因为如果他们这样做,activity 将再次重新创建,而不是将结果传回 @onNewIntent 中的原始结果,从而在后台堆栈中产生相同 activity 的两个实例。
我怀疑这个问题发生在 android 7 上,当测试 android 10 时,而不是重新创建 activity 任务路由到 @onNewIntent (STATUS_FAILURE_ABORTED) 作为应该是。
如果用户中止安装,我如何捕获?
这样做的真正目的是防止用户使用旧版本的应用程序。
或者是否有办法以某种方式防止这种重复活动?
当 Activity
的新实例在 Android 7 上创建时,如果 Intent
包含软件包安装程序状态,您可以在 onCreate()
中执行此操作:
Intent x = getIntent(); // This contains the package installer status
x.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
startActivity(x);
finish();
这将完成 Activity
的新实例并恢复 Activity
的前一个实例并将 Intent
传递给前一个 [=] 的 onNewIntent()
11=].
注意:标志 FLAG_ACTIVITY_PREVIOUS_IS_TOP
告诉 Android 在决定如何处理 startActivity()
调用时它应该忽略当前最顶层的 Activity
。当您设置此标志时,您是在告诉 Android:“此 Activity
即将结束,因此在决定是否需要创建新实例或使用现有实例时不要考虑它”
这是一个 hack,但应该有效:-)
我在使用 Packagemanager 安装我的应用程序更新时遇到了一些问题。我的应用程序是为我公司的内部使用而设计的,因此我们不能使用 Google Play 来处理这些更新。因此在启动应用程序后,它会快速检查版本并下载更新(如果有)。
这是我在 activity 中尝试过的(该文件是同一应用程序的下载版本和较新版本)
public void installNewApkVersion(File file){
PackageInstaller.Session session = null;
try{
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
addApkToInstallSession(session, file);
// Create an install status receiver.
Context context = LoginActivity.this;
Intent intent = new Intent(context, LoginActivity.class);
intent.setAction(ACTION_INSTALL_COMPLETE);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();
// Commit the session (this will start the installation workflow).
session.commit(statusReceiver);
} catch(IOException e){
throw new RuntimeException("Couldn't install package", e);
} catch (RuntimeException e){
if(session != null){
session.abandon();
}
throw e;
}
}
为了让它起作用,我必须像这样覆盖 onNewIntent:
@Override
protected void onNewIntent(Intent intent) {
Bundle extras = intent.getExtras();
boolean isloggedin = pref.getBoolean("Loggedin", false);
if (ACTION_INSTALL_COMPLETE.equals(intent.getAction())) {
int status = extras.getInt(PackageInstaller.EXTRA_STATUS);
String message = extras.getString(PackageInstaller.EXTRA_STATUS_MESSAGE);
switch (status) {
case PackageInstaller.STATUS_PENDING_USER_ACTION:
// This test app isn't privileged, so the user has to confirm the install.
Intent confirmIntent = (Intent) extras.get(Intent.EXTRA_INTENT);
startActivity(confirmIntent);
break;
case PackageInstaller.STATUS_SUCCESS:
Log.w(TAG, "Install finished successfully");
break;
case PackageInstaller.STATUS_FAILURE:
Toast.makeText(this, "Install failed!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed - status failure.");
break;
case PackageInstaller.STATUS_FAILURE_ABORTED:
Toast.makeText(this, "Install failure aborted!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Aborted.");
break;
case PackageInstaller.STATUS_FAILURE_BLOCKED:
Toast.makeText(this, "Install: failure blocked!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Blocked.");
break;
case PackageInstaller.STATUS_FAILURE_CONFLICT:
Toast.makeText(this, "Install: failure conflicted!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Found conflicts.");
break;
case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE:
Toast.makeText(this, "Install: incompatible!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Incompatible.");
break;
case PackageInstaller.STATUS_FAILURE_INVALID:
Toast.makeText(this, "Install: invalid!", Toast.LENGTH_SHORT).show();
Log.w(TAG, "Installation failed. Invalid.");
break;
case PackageInstaller.STATUS_FAILURE_STORAGE:
Toast.makeText(this, "Install failed: storage error! " + status + ", " + message,
Toast.LENGTH_SHORT).show();
Log.w(TAG, "Install failed. Storage error.");
break;
default:
Toast.makeText(this, "Unrecognized status received from installer: " + status,
Toast.LENGTH_SHORT).show();
Log.w(TAG, "Dont know what happened");
}
}
}
此 Activity 以 singleTop 模式运行以接收安装结果。它运行良好,除非用户在提示时取消它。
因为如果他们这样做,activity 将再次重新创建,而不是将结果传回 @onNewIntent 中的原始结果,从而在后台堆栈中产生相同 activity 的两个实例。
我怀疑这个问题发生在 android 7 上,当测试 android 10 时,而不是重新创建 activity 任务路由到 @onNewIntent (STATUS_FAILURE_ABORTED) 作为应该是。
如果用户中止安装,我如何捕获?
这样做的真正目的是防止用户使用旧版本的应用程序。
或者是否有办法以某种方式防止这种重复活动?
当 Activity
的新实例在 Android 7 上创建时,如果 Intent
包含软件包安装程序状态,您可以在 onCreate()
中执行此操作:
Intent x = getIntent(); // This contains the package installer status
x.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
startActivity(x);
finish();
这将完成 Activity
的新实例并恢复 Activity
的前一个实例并将 Intent
传递给前一个 [=] 的 onNewIntent()
11=].
注意:标志 FLAG_ACTIVITY_PREVIOUS_IS_TOP
告诉 Android 在决定如何处理 startActivity()
调用时它应该忽略当前最顶层的 Activity
。当您设置此标志时,您是在告诉 Android:“此 Activity
即将结束,因此在决定是否需要创建新实例或使用现有实例时不要考虑它”
这是一个 hack,但应该有效:-)