我很难解决崩溃,该崩溃要么是由于我自己由于缺乏知识而导致的错误实现,要么是 AOSP 代码(我认为不太可能......)。 它似乎只发生在 Android 13 上,我主要在我没有的三星设备(Galaxy S23+/S22+/S22 Ultra/S21 FE 5G)上得到它(在 OPPO Reno5、小米 12 和小米 11T 上也发生过 1 次)。 这是堆栈跟踪:
Non-fatal Exception: java.lang.NullPointerException
Attempt to invoke virtual method 'com.android.server.wm.ActivityRecord com.android.server.wm.WindowContainer.getActivity(java.util.function.Predicate)' on a null object reference
android.os.Parcel.createExceptionOrNull (Parcel.java:3029)
android.os.Parcel.createException (Parcel.java:3007)
android.os.Parcel.readException (Parcel.java:2990)
android.os.Parcel.readException (Parcel.java:2932)
android.app.IActivityTaskManager$Stub$Proxy.startActivities (IActivityTaskManager.java:2816)
android.app.Instrumentation.execStartActivitiesAsUser (Instrumentation.java:1876)
android.app.Instrumentation.execStartActivities (Instrumentation.java:1823)
android.app.Activity.startActivities (Activity.java:6096)
android.app.Activity.startActivities (Activity.java:6069)
.SplashActivity.startMain (SplashActivity.java:149)
我已经在 AOSP 代码中进行了搜索,以了解
WindowContainer
如何在 null
中成为 IActivityTaskManager.startActivities
,其实现似乎是 ActivityTaskManagerService.startActivities
,但很难深入了解 AOSP 代码...我也尝试过搜索 WindowContainer.getActivity
用法,但交叉引用似乎不适用于此文件...我还按照文档通过 repo
cmd 克隆了存储库,但我没有找到文件...所以我被卡住了:/
我已经实现了
SplashActivity
处理主启动器意图以及任何后台通知和深层链接点击,启动正确的活动或堆栈。
当我需要启动 list -> details
堆栈时,我只遇到崩溃。
这是它的最小综合代码:
public final class SplashActivity {
private boolean resumed;
@Override
protected void onStart() {
super.onStart();
fetchAsyncData(SplashActivity::onDataFetched())
}
@Override
protected void onPostResume() {
super.onPostResume();
resumed = true;
}
@Override
protected void onPause() {
super.onPause();
resumed = false;
}
public void onDataFetched() {
String res1, res2;
// some code to parse either a deep link or background notification, ending in populated res1 & res2 or not
// do not start any activity if not resumed (user goes back to home/other app/kills the app)
if (resumed) {
if (res1 != null && res2 != null) {
Intent intent = getIntent();
Bundle extras = intent.getExtras();
Intent listIntent = new Intent(this, ListActivity.class);
// forward extras/flags to new root intent
listIntent.putExtras(extras != null ? extras : new Bundle());
listIntent.addFlags(intent.getFlags());
Intent detailsIntent = new Intent(this, DetailsActivity.class);
detailsIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
detailsIntent.putExtra("res1", res1);
detailsIntent.putExtra("res2", res2);
startActivities(new Intent[]{listIntent, detailsIntent});
finish();
}
else {
// start other activities
}
}
}
}
以下是
SplashActivity
、ListActivity
和 DetailsActivity
在 AndroidManifest.xml
中的声明方式:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity
android:name=".SplashActivity"
android:launchMode="singleInstance"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:autoVerify="true" tools:targetApi="m">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="example.com"
android:pathPattern="/res1/.*/res2/.*" />
</intent-filter>
</activity>
<activity
android:name=".ListActivity"
android:exported="true"
android:launchMode="singleTop" />
<activity
android:name=".DetailsActivity"
android:launchMode="singleTop"
android:exported="true"
android:parentActivityName=".ListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ListActivity" />
</activity>
</application>
</manifest>
我已经更新了上面的代码以使用
TaskStackBuilder
来代替,因为看起来我之前已经这样实现过,但是改变了它,我不知道为什么......
我会让你知道这是否修复了崩溃(再次?),假设 startActivities
方法已被弃用:/
public void onDataFetched() {
String res1, res2;
// some code to parse either a deep link or background notification,
// ending in populated res1 & res2 or not
// do not start any activity if not resumed
// (user goes back to home/other app/kills the app)
if (resumed) {
if (res1 != null && res2 != null) {
Intent intent = getIntent();
Bundle extras = intent.getExtras();
Intent detailsIntent = new Intent(context, DetailsActivity.class);
detailsIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
detailsIntent.putExtra("res1", res1);
detailsIntent.putExtra("res2", res2);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntentWithParentStack(detailsIntent);
// forward extras/flags to list intent
// automatically added as new root because
// declared as parent activity of DetailsActivity in AndroidManifest.xml
Intent listIntent = stackBuilder.editIntentAt(0);
if (listIntent != null)
{
listIntent.putExtras(extras != null ? extras : new Bundle());
listIntent.addFlags(intent.getFlags());
}
stackBuilder.startActivities();
finish();
}
else {
// start other activities
}
}
}