添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

onActivityResult中创建Fragment

一个异常的分析

A activity跳转到B activity,然后又返回到A activity,在A activity的onActivityResult中,给A添加一个Fragment,由于在Fragment的onCreateView方法中有个异常,导致了崩溃

07-15 15:48:44.699  3430  3430 D AndroidRuntime: Shutting down VM
07-15 15:48:44.702  3430  3430 E AndroidRuntime: FATAL EXCEPTION: main
07-15 15:48:44.702  3430  3430 E AndroidRuntime: Process: com.sohu.sohuvideo, PID: 3430
07-15 15:48:44.702  3430  3430 E AndroidRuntime: java.lang.RuntimeException: Unable to resume activity {com.sohu.sohuvideo/com.sohu.sohuvideo.ui.BuyVipActivity}: java.lang.NullPointerException: uriString
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3992)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4024)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1926)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:106)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:214)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6990)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: Caused by: java.lang.NullPointerException: uriString
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.net.Uri$StringUri.<init>(Uri.java:490)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.net.Uri$StringUri.<init>(Uri.java:480)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.net.Uri.parse(Uri.java:452)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at com.sohu.sohuvideo.paysdk.ui.dialog.ActivityCommodityPayResultDialogFragment.onCreateView(ActivityCommodityPayResultDialogFragment.java:159)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentController.execPendingActions(FragmentController.java:447)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at androidx.fragment.app.FragmentActivity.onResume(FragmentActivity.java:458)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at com.sohu.sohuvideo.ui.BaseActivity.onResume(BaseActivity.java:285)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at com.sohu.sohuvideo.ui.BuyVipActivity.onResume(BuyVipActivity.java:316)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1412)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.Activity.performResume(Activity.java:7611)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3984)
07-15 15:48:44.702  3430  3430 E AndroidRuntime: 	... 11 more

只是单纯解决这个异常很简单。不过,这边文章想说的是,我们可以从堆栈信息中了解一些知识。
从B Activity返回到A activity是先执行A的onActivityResult然后是onResume方法,在onActivityResult中把Fragment添加到A activity中的。
那为啥Fragment的onCreateView的执行过程是从Activity的onResume方法开始的呢?
这个就要从我们使用的Fragment commit方式说起了,我们采用的是commitAllowingStateLoss,commitAllowingStateLoss和commit方式都不是及时的,是主线程异步的,主线程异步指的是不在当前消息的执行体内,而是在Looper的下一个消息执行体内,而且会把之前所有提交还没执行的commit都执行。这个可以从源码中知道

* Schedules the execution when one hasn't been scheduled already. This should happen * the first time {@link #enqueueAction(OpGenerator, boolean)} is called or when * a postponed transaction has been started with * {@link Fragment#startPostponedEnterTransition()} @SuppressWarnings("WeakerAccess") /* synthetic access */ void scheduleCommit() { synchronized (mPendingActions) { boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty(); boolean pendingReady = mPendingActions.size() == 1; if (postponeReady || pendingReady) { mHost.getHandler().removeCallbacks(mExecCommit); mHost.getHandler().post(mExecCommit); updateOnBackPressedCallbackEnabled(); private Runnable mExecCommit = new Runnable() { @Override public void run() { execPendingActions(true); * Only call from main thread! boolean execPendingActions(boolean allowStateLoss) { ensureExecReady(allowStateLoss); boolean didSomething = false; while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) { mExecutingActions = true; try { removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop); } finally { cleanupExec(); didSomething = true; updateOnBackPressedCallbackEnabled(); doPendingDeferredStart(); mFragmentStore.burpActive(); return didSomething;

如果按照真是按照上面讲的逻辑执行的话,执行逻辑应该是Handler的callback方法,mHost.getHandler()是new出来的一个Handler,不是ActivityThread$H这个handler,大家想想,平时new一个handler执行一个runnable是一个怎么样的调用堆栈。
可是,实际情况走的却是onResume,这个就需要看看onResume源码了

* Dispatch onResume() to fragments. Note that for better inter-operation * with older versions of the platform, at the point of this call the * fragments attached to the activity are <em>not</em> resumed. @Override protected void onResume() { super.onResume(); mResumed = true; mFragments.noteStateNotSaved(); mFragments.execPendingActions();

看到没,也调用了execPendingActions方法。同时也说明了一个问题,onActivityResult和onResume是在一个消息的执行体内,因为如果不在,就很难保证是先执行onResume还是先执行mExecCommit。而且我们也知道commit是主线程异步,也不只是绝对的。

把commitAllowingStateLoss换成commitNowAllowingStateLoss,让Fragment立即执行

07-15 16:22:23.291  6176  6176 E AndroidRuntime: FATAL EXCEPTION: main
07-15 16:22:23.291  6176  6176 E AndroidRuntime: Process: com.sohu.sohuvideo, PID: 6176
07-15 16:22:23.291  6176  6176 E AndroidRuntime: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { (has extras) }} to activity {com.sohu.sohuvideo/com.sohu.sohuvideo.ui.BuyVipActivity}: java.lang.NullPointerException: uriString
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.ActivityThread.deliverResults(ActivityThread.java:4588)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.ActivityThread.handleSendResult(ActivityThread.java:4630)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1926)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:106)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:214)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6990)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: Caused by: java.lang.NullPointerException: uriString
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.net.Uri$StringUri.<init>(Uri.java:490)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.net.Uri$StringUri.<init>(Uri.java:480)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.net.Uri.parse(Uri.java:452)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at com.sohu.sohuvideo.paysdk.ui.dialog.ActivityCommodityPayResultDialogFragment.onCreateView(ActivityCommodityPayResultDialogFragment.java:159)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1356)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1434)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1497)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2169)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1992)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1818)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at com.sohu.sohuvideo.paysdk.ui.dialog.ActivityCommodityPayResultDialogFragment$Builder.create(ActivityCommodityPayResultDialogFragment.java:109)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at com.sohu.sohuvideo.ui.BuyVipActivity.activityCommodityPaySuccess(BuyVipActivity.java:2055)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at com.sohu.sohuvideo.ui.BuyVipActivity.onActivityResult(BuyVipActivity.java:1246)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.Activity.dispatchActivityResult(Activity.java:7801)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	at android.app.ActivityThread.deliverResults(ActivityThread.java:4581)
07-15 16:22:23.291  6176  6176 E AndroidRuntime: 	... 11 more

这个堆栈一看,就知道Fragment的操作在onActivityResult的方法内就直接执行了。这个很好理解

你真的懂 Fragment 吗?—— AndroidX Fragment 核心原理分析
Fragment 的过去、现在和将来
【背上Jetpack之Fragment】从源码角度看 Fragment 生命周期 AndroidX Fragment1.2.2源码分析

正确创建Fragment的时机

这个章节涉及的问题是在onActivityResult中创建Fragment,有个问题是,在onActivityResult(或onResume)时机的时候,activity的state还没有恢复(activity可能被系统销毁了),commit Fragment就会报错。
下面这两篇文章就讨论了这个问题
"Failure Delivering Result " - onActivityForResult
Fragment Transactions & Activity State Loss

Fragment State Loss

fragment state loss这个问题,在使用fragment的时候,总是会时不时遇到。让你不再俱怕Fragment State Loss进行了深入的分析

onBackPressed不能乱用

onBackPressed是响应到返回键的时候调用的,里面有对Fragment的退栈处理。
所以,在实际使用中,得明确需求,你是想模拟back键呢还是想关闭activity,如果只是想关闭activity,直接调finish。自己开发中,有在网络接口回调中,想关闭activity,结果调用的是onBackPressed,结果出现两类错误,一类错误是,java.lang.IllegalStateException Can not perform this action after onSaveInstanceState 这是因为,在低版本上,onBackPressed做退栈处理的时候,没有想检查activity的state导致的,二类错误是java.lang.NullPointerException Attempt to invoke virtual method 'android.os.Handler android.app.FragmentHostCallback.getHandler()' on a null object reference

根本问题是,应该调用finish,却调用onBackPressed

Android Fragment的生命周期和Activity类似,实际可能会涉及到数据传递,onSaveInstanceState的状态保存,FragmentManager的管理和Transaction,切换的Animation。 我们首先简单的介绍一下Fragment的生命周期。 大致上,从名字就可以判断出每个生命周期是干嘛的。 AppCompatActivity就是FragmentActivity的子类,如果想使用Fragment,是要继承FragmentActivity,因为考虑到兼容的问题,我们要使用getSupportFragmentManager,而这个方法是Fragm Unable to start activity ComponentInfo{Activity}:java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 完全分析与解决方案 java.lang.IllegalStateException: FragmentManager is already executing transactionsIllegalStateException:非法状态异常FragmentManager is already executing transactions:FragmentManger 已经执行了事务的操作也就是说你的Fragment中... 主activity 包含的fragment的listview为空导致 原被 包含的fragment的onCreateView代码 public class RuzhangFragment extends Fragment{ private ListView rulistView1 = null;//收入界面的listview private List<RuZhang> ruzhanglist = null;// 记录消息集合 public View onCreateView(LayoutInflat 先说结论:使用Fragment时,要声明一个无参的构造函数,否则在状态恢复时会出现crash 因为当Fragment因为某种原因重新创建时,会调用到onCreate方法传入之前保存的状态,在instantiate方法中通过反射无参构造函数创建一个Fragment,并且为Arguments初始化为原来保存的值,而此时如果没有无参构造函数就会抛出异常,造成程序崩溃。 java.lang.RuntimeException: Unable to s 1、布局中加入一个 2、查到原因Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f0e0096, tag null, or parent id 0xffffffff with another fragment for 疑难问题android.os.BadParcelableException ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState 问题分析 问题描述 -----------------------Crash 1 Message----------------------- 完整log: logcat.txt 02-20 21:08:32.727 E/AndroidRuntime(32306 我遇到一个问题,我找不到任何解释.我有一个FragmentActivity,它使用TabManager显示片段,如下所示:public class WorkOrderFormTabFragmentActivity extends FragmentActivity {TabHost mTabHost;TabManager mTabManager;@Overrideprotected void onC... 本文讲的是安卓开发常用工具和第三方库汇总,我的名字叫 Ryan Cooke 我在 Pinterest 的核心体验团队工作。今天在这里我会谈论各种 Android 库:它们各自的优点,缺点和其他相关知识。目的是高效地概述尽可能多的库,这样,当你遇到一个问题的时候,你知道这是不是个已经解决的问题?什么样的方案更好?同时也能帮助你避免那些陷阱。 选择正确的... 这段时间稍微断更了一段时间,因为我在准备面试。经过两次面试后,有一些比较深刻的认识。对于大厂来说,除了对专业知识考究之外,对算法也尤为看重。 简单的说一下情况,字节已经拿到offer,腾讯所有的面面试已经通过了,也应该有offer了。字节一共4面:3面技术,1面hr;腾讯5次技术面,1次hr面。其中5面是2个面试官上阵。 总的来说腾讯的面试确实强度更高更加持久。字节是分开一次1个小时面试的。而腾讯1、2面是一次一小时,而3面和4面是连续面试一口气高强度的面试2小时,5面则是2个面试官轮流提问。腾 本文虽然冠名『车载』但涉及到的知识点是所有Android APP开发通用的 本文基于 AndroidX Fragment library 编写,阅读本文需要有一定Fragment使用基础 写这篇博客的原因是最近和同事交流某个项目中遇到问题时,发现我们对Fragment使用方式相比4-5年前几乎.