- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我一直在使用这种模式。这是一个非常人为的 AsyncTask + 进度指示器示例:
new AsyncTask<Void, Void, Void>() {
WeakReference<MyFragment> weakFragment = new WeakReference<MyFragment>(MyFragment.this);
@Override
protected void onPreExecute() {
Fragment fragment = weakFragment.get();
if(fragment != null) fragment.getView().findViewById(R.id.progress).setVisibility(View.VISIBLE);
}
@Override
protected Document doInBackground(Void... params) {
Fragment fragment = weakFragment.get();
if(fragment == null) return null;
// Do something ...
}
@Override
protected void onPostExecute() {
Fragment fragment = weakFragment.get();
if(fragment != null) fragment.getView().findViewById(R.id.progress).setVisibility(View.GONE);
}
}.execute();
它在方向更改时工作正常,但是当我从后台弹出 fragment 时,我注意到 fragment 是非空的并且 fragment.getView() 是空的。这显然会导致崩溃。你们使用什么方法?我似乎无法在网上找到完美的解决方案。重要说明,这是在 fragment 中,我在其 onActivityCreated(...) 中对该 fragment 调用 setRetainInstance(true);
。
最佳答案
AsyncTask
是一个异步任务,这意味着您通常不知道它何时完成以及何时调用 onPostExecute()
。 .我认为你的问题就在这里。当你旋转你的设备时,你的异步任务还没有完成,你的 fragment View 被销毁并很快重新创建,而异步任务仍然在工作线程上,当它完成它的工作时,你的 fragment 有一个 View 和 getView
的返回值不是 null
.但是如果旋转时间很长,你会得到 null
因为AsyncTask
已完成,但您的 fragment 没有任何 View 。现在这种情况恰好发生在你的后台当你将你的 fragment 推到后台时,它的 View 被销毁(look at the picture)但 fragment 本身没有( fragment 从后台返回到布局)。现在你的 AsyncTask
完成并调用您的 fragment
getView
方法,它没有任何 view
所以你会得到NPE
.
我的解决方案:
首先你应该使用WeakReference<ProgressBar>
而不是 WeakReference<MyFragment>
在onPostExecute()
检查它是否为 null,如果为 null,则什么也不做,因为如果它不是 null,则默认值是不可见的调用 setVisibility(View.GONE)
.
更新:
the fragment is alive but the view has been dealloc'd. Is this possible?
是的,只需查看链接中的图 2。当 fragment 处于 Activity 状态时(绿色框)the fragment added to back stack
fragment 转到 onPause
, onStop
onDestroyView。然后,当 fragment 从返回堆栈中弹出时,它会直接转到 onCreateView
。带有此文本的箭头链接:the fragment returns to the layout from backstack
.
为了确认我的回答,您可以创建一个 AsyncTask
并调用SystemClock.sleep(30000)
在你的里面doInbackground
.现在您可以毫无异常(exception)地将您的 fragment 插入后台堆栈并将其从后台堆栈弹出,因为 asynctask 尚未完成以及何时调用 onPostExecute()
。您的 fragment 已经有一个 View 。
您可以看到的另一个好东西是 setRetainInstance
This can only be used with fragments not in the back stack.
因此,当您将 fragment 插入后退堆栈时,它可能会完全销毁,而您可能会在弹出时获得新的 fragment 引用。但是当你使用 setRetainInstance(true);
对于配置更改,您的 fragment 在 Activity 重新创建时保留,这意味着它是相同 fragment 和onCreate
没有被调用。这是一件非常非常重要的事情,因为如果你开始你的 AsyncTask
在 onCreate
方法,当您将 fragment 插入后退堆栈并将其弹出时,您可能有一个新 fragment ,这意味着 onCreate
方法运行,另一个 AsyncTask
被解雇了。这意味着您无法控制调用 AsyncTask
的号码。所以要当心内存泄漏!
关于android - AsyncTask、Fragments、Views 和 Backstacks,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26432439/
简短版本: 我有 5 个 fragment ,均由 replace 添加到容器中方法(A -> B -> C -> D -> E),现在我想从我的backStack(C)中删除第3个 fragment
我正在开发一个 Android 应用程序,遇到了一个涉及 Fragments 和 FragmentTransactions 的错误。我创建了一个示例应用程序来演示该问题。这是我正在做的: add Fr
在两个 fragment 上使用导航组件,我的应用程序当前在 navigateUp() 时销毁了一个 fragment 被调用(使用 setupActionBarWithNavController()
我在做navigation component codelab。 在10部分中,我们添加了Deeplink小部件。 我将目的地替换为R.id.flow_step_two_dest val cust
我无法解决 BackStack 的问题。我有 3 个由 Activity 管理的 fragment : 我使用这段代码的 fragment 之间的导航: private void showFragme
过去几天我一直在处理一个问题,但似乎没有找到答案。 描述:我有一个包含抽屉导航的主要 Activity 。抽屉导航的每个项目(单击时)都会创建一个 fragment 。在该 fragment 中,有一
对于我的应用程序,某些 fragment 要求用户在显示之前在对话框中输入 PIN。我有一个 BaseFragment 类,如果需要 pin,我的所有其他 fragment 都会扩展该类。我现在的问题
我有一个包含单个 Activity 的应用程序,该 Activity 使用菜单抽屉进行导航。每次单击菜单抽屉中的项目时,我都会用一个新 fragment 替换显示的 fragment 并将其添加到后台
我试图在调用方法时加载新 fragment 。此方法创建一个新 fragment 并“替换”另一个 fragment : private void showTestFragment(Fragment
您好,如何清除 fragment 回栈我使用下面的逻辑它不起作用... for(int i = 0; i < mFragmentManager.getBackStackEntryCount(); ++
我的导航图有 auth包含 LoginFragment 和 SignUpFragment 的子图: [...] 我想检查这两个目的地中的任何一个当前是否在后台。但不是单独检查每个
我的 ViewPager 有 3 个选项卡。 Tab(3) 包含 2 个 fragment (A) --> (B)。 Tab(1) Tab(2) Tab(3) --> (B) --> (C) 我在Ta
我不确定为什么这不起作用,我查看了文档,看起来这应该可行。 DetailFragment newFragment = new DetailFragment(); FragmentTransaction
我想检查 BackStack 是否为空。我有这样的东西: List l2 = getFragmentManager().getFragments(); if(l2 == null){
概览 您好,我目前正在尝试开发一款采用新 Material 设计和兼容 API15 的 Android 应用程序。这次我想通过在 Activity 中替换它们来仅使用一个 Activity 和多个 f
我在后台堆栈中有 fragment ,这些 fragment 是使用 addtobackstack 函数添加的。当我在不使用 addtobackstack 函数的情况下添加一个 fragment 然后
当用户点击状态栏中的通知时,我正在使用 FCM 显示 fragment 。 当前的应用程序流是这个 MainActivity( fragment A -> fragment B -> fragment
在我的 Activity 中,我正在加载 fragment 并在用户单击项目时将它们添加到后台堆栈。这工作正常,后台加载也很好。 不幸的是,当我旋转设备时, Activity 是空白的。我已经在 SO
我有一个 FragmentActivity,当用户在应用程序中导航时,我用用户选择的 fragment 替换当前 fragment ,并将事务添加到后台堆栈。一切正常,用户可以通过按后退按钮返回到之前
我的 Activity 中有以下代码: public void categoryClicked(int categoryId, String categoryName) {
我是一名优秀的程序员,十分优秀!