好多用户反馈说app在华为9.0系统上无法打开APP,于是自己运行没问题,然后从应用市场下载下来安装果然GG
问题排查看到的奔溃日志如下:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bdqn.kegongchang/xxxx.ui.activity.ActivitySplash}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.FragmentController.attachHost(android.app.Fragment)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3300)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3484)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:86)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2123)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main
从奔溃日志中可以看到应该是在ActivityThread
的performLaunchActivity
方法中调用FragmentController.attachHost
方法FragmentController
为空造成的空指针,由于是9.0我们查看9.0的源码,首先看看ActivityThread
的performLaunchActivity
方法中奔溃位置
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
2809 ActivityInfo aInfo = r.activityInfo;
2810 if (r.packageInfo == null) {
2811 r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
2812 Context.CONTEXT_INCLUDE_CODE);
2813 }
2814
2815 ComponentName component = r.intent.getComponent();
2816 if (component == null) {
2817 component = r.intent.resolveActivity(
2818 mInitialApplication.getPackageManager());
2819 r.intent.setComponent(component);
2820 }
2821
2822 if (r.activityInfo.targetActivity != null) {
2823 component = new ComponentName(r.activityInfo.packageName,
2824 r.activityInfo.targetActivity);
2825 }
2826
2827 ContextImpl appContext = createBaseContextForActivity(r);
2828 Activity activity = null;
2829 try {
2830 java.lang.ClassLoader cl = appContext.getClassLoader();
2831 activity = mInstrumentation.newActivity(
2832 cl, component.getClassName(), r.intent);
2833 StrictMode.incrementExpectedActivityCount(activity.getClass());
2834 r.intent.setExtrasClassLoader(cl);
2835 r.intent.prepareToEnterProcess();
2836 if (r.state != null) {
2837 r.state.setClassLoader(cl);
2838 }
2839 } catch (Exception e) {
2840 if (!mInstrumentation.onException(activity, e)) {
2841 throw new RuntimeException(
2842 "Unable to instantiate activity " + component
2843 + ": " + e.toString(), e);
2844 }
2845 }
2846
2847 try {
2848 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
2849
2850 if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
2851 if (localLOGV) Slog.v(
2852 TAG, r + ": app=" + app
2853 + ", appName=" + app.getPackageName()
2854 + ", pkg=" + r.packageInfo.getPackageName()
2855 + ", comp=" + r.intent.getComponent().toShortString()
2856 + ", dir=" + r.packageInfo.getAppDir());
2857
2858 if (activity != null) {
2859 CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
2860 Configuration config = new Configuration(mCompatConfiguration);
2861 if (r.overrideConfig != null) {
2862 config.updateFrom(r.overrideConfig);
2863 }
2864 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
2865 + r.activityInfo.name + " with config " + config);
2866 Window window = null;
2867 if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
2868 window = r.mPendingRemoveWindow;
2869 r.mPendingRemoveWindow = null;
2870 r.mPendingRemoveWindowManager = null;
2871 }
2872 appContext.setOuterContext(activity);
2873 activity.attach(appContext, this, getInstrumentation(), r.token,
2874 r.ident, app, r.intent, r.activityInfo, title, r.parent,
2875 r.embeddedID, r.lastNonConfigurationInstances, config,
2876 r.referrer, r.voiceInteractor, window, r.configCallback);
2877
2878 if (customIntent != null) {
2879 activity.mIntent = customIntent;
2880 }
2881 r.lastNonConfigurationInstances = null;
2882 checkAndBlockForNetworkAccess();
2883 activity.mStartedActivity = false;
2884 int theme = r.activityInfo.getThemeResource();
2885 if (theme != 0) {
2886 activity.setTheme(theme);
2887 }
2888
2889 activity.mCalled = false;
2890 if (r.isPersistable()) {
2891 mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
2892 } else {
2893 mInstrumentation.callActivityOnCreate(activity, r.state);
2894 }
2895 if (!activity.mCalled) {
2896 throw new SuperNotCalledException(
2897 "Activity " + r.intent.getComponent().toShortString() +
2898 " did not call through to super.onCreate()");
2899 }
2900 r.activity = activity;
2901 }
2902 r.setState(ON_CREATE);
2903
2904 mActivities.put(r.token, r);
2905
2906 } catch (SuperNotCalledException e) {
2907 throw e;
2908
2909 } catch (Exception e) {
2910 if (!mInstrumentation.onException(activity, e)) {
2911 throw new RuntimeException(
2912 "Unable to start activity " + component
2913 + ": " + e.toString(), e);
2914 }
2915 }
2916
2917 return activity;
2918 }
2919
从最后面的catch
可以看到奔溃的位置应该是在2847下面其中某行,这里就不卖关子奔溃的具体位置是在2873行的activity.attach
方法中,我们进去看看
final void attach(Context context, ActivityThread aThread,
7045 Instrumentation instr, IBinder token, int ident,
7046 Application application, Intent intent, ActivityInfo info,
7047 CharSequence title, Activity parent, String id,
7048 NonConfigurationInstances lastNonConfigurationInstances,
7049 Configuration config, String referrer, IVoiceInteractor voiceInteractor,
7050 Window window, ActivityConfigCallback activityConfigCallback) {
7051 attachBaseContext(context);
7052
7053 mFragments.attachHost(null /*parent*/);
7054
7055 mWindow = new PhoneWindow(this, window, activityConfigCallback);
7056 mWindow.setWindowControllerCallback(this);
7057 mWindow.setCallback(this);
7058 mWindow.setOnWindowDismissedCallback(this);
7059 mWindow.getLayoutInflater().setPrivateFactory(this);
7060 if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
7061 mWindow.setSoftInputMode(info.softInputMode);
7062 }
7063 if (info.uiOptions != 0) {
7064 mWindow.setUiOptions(info.uiOptions);
7065 }
7066 mUiThread = Thread.currentThread();
7067
7068 mMainThread = aThread;
7069 mInstrumentation = instr;
7070 mToken = token;
7071 mIdent = ident;
7072 mApplication = application;
7073 mIntent = intent;
7074 mReferrer = referrer;
7075 mComponent = intent.getComponent();
7076 mActivityInfo = info;
7077 mTitle = title;
7078 mParent = parent;
7079 mEmbeddedID = id;
7080 mLastNonConfigurationInstances = lastNonConfigurationInstances;
7081 if (voiceInteractor != null) {
7082 if (lastNonConfigurationInstances != null) {
7083 mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
7084 } else {
7085 mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
7086 Looper.myLooper());
7087 }
7088 }
7089
7090 mWindow.setWindowManager(
7091 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
7092 mToken, mComponent.flattenToString(),
7093 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
7094 if (mParent != null) {
7095 mWindow.setContainer(mParent.getWindow());
7096 }
7097 mWindowManager = mWindow.getWindowManager();
7098 mCurrentConfig = config;
7099
7100 mWindow.setColorMode(info.colorMode);
7101
7102 setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
7103 enableAutofillCompatibilityIfNeeded();
7104 }
7105
7106 private void enableAutofillCompatibilityIfNeeded() {
7107 if (isAutofillCompatibilityEnabled()) {
7108 final AutofillManager afm = getSystemService(AutofillManager.class);
7109 if (afm != null) {
7110 afm.enableCompatibilityMode();
7111 }
7112 }
7113 }
我们看到在7053行找到了奔溃的位置,那么mFragments
他是什么,他在什么时候初始化的
832 final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
在activity
的832行看到他是个成员变量activity创建的时候一起创建了,按道理说这里应该不可能为空啊,到这里没有其他思路了,我们还有一个APP没问题,想到能不能看看有啥区别,最终发现是集成的FragmentActivity
而我们奔溃的是APP是继承与actiivity
这个项目比较老,有没有可能是这问题,于是看看FragmentActivity
protected void onCreate(@Nullable Bundle savedInstanceState) {
323 mFragments.attachHost(null /*parent*/);
324
325 super.onCreate(savedInstanceState);
326
327 NonConfigurationInstances nc =
328 (NonConfigurationInstances) getLastNonConfigurationInstance();
329 if (nc != null) {
330 mViewModelStore = nc.viewModelStore;
331 }
332 if (savedInstanceState != null) {
333 Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
334 mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
335
336 // Check if there are any pending onActivityResult calls to descendent Fragments.
337 if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
338 mNextCandidateRequestIndex =
339 savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
340 int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
341 String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
342 if (requestCodes == null || fragmentWhos == null ||
343 requestCodes.length != fragmentWhos.length) {
344 Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
345 } else {
346 mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
347 for (int i = 0; i < requestCodes.length; i++) {
348 mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
349 }
350 }
351 }
352 }
353
354 if (mPendingFragmentActivityResults == null) {
355 mPendingFragmentActivityResults = new SparseArrayCompat<>();
356 mNextCandidateRequestIndex = 0;
357 }
358
359 mFragments.dispatchCreate();
360 }
在FragmentActivity
我们发现他调用mFragments.attachHost(null /*parent*/);
是在onCreate
中,而activity
是在attch
中,他初始化FragmentController
也是在创建的时候初始化的,看到这里应该没啥区别了,就是初始化时机不一样,到此问题原因分析完了,但是具体怎么导致的确实没找到,我们换成FragmentActivity
成功解决,这里目前只能说是华为room存在一定适配问题。