gpt4 book ai didi

android - 加载程序在某些配置更改期间无法保留自身

转载 作者:IT老高 更新时间:2023-10-28 23:15:24 25 4
gpt4 key购买 nike

根据 http://developer.android.com/guide/components/loaders.html 的说法,loader 的优点之一是,它能够在配置更改期间保留其数据。

They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.

但是,它并不适用于所有场景。

我举一个简单的例子。它是一个 FragmentActivity,它承载着一个 FragmentFragment 本身拥有 AsyncTaskLoader

以下 3 个场景运行良好。

首次启动期间(正常)

1个loader被创建,loadInBackground被执行一次。

简单旋转时(OK)

没有创建新的加载器,也没有触发 loadInBackground

启动子 Activity ,按下后退按钮(确定)

没有创建新的加载器,也没有触发 loadInBackground

但是,在以下场景中。

启动子 Activity -> 旋转 -> 按下后退按钮(错误)

此时调用了旧加载器的onReset。旧的装载机将被销毁。将创建新的加载器,并再次触发新加载器的 loadInBackground

我期望的正确行为是,不会创建新的加载器。

loader相关代码如下。我在Android 4.1模拟器下运行代码。

package com.example.bug;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MainFragment extends Fragment implements LoaderManager.LoaderCallbacks<Integer> {
private static class IntegerArrayLoader extends AsyncTaskLoader<Integer> {

private Integer result = null;

public IntegerArrayLoader(Context context) {
super(context);
Log.i("CHEOK", "IntegerArrayLoader created!");
}

@Override
public Integer loadInBackground() {
Log.i("CHEOK", "Time consuming loadInBackground!");
this.result = 123456;
return result;
}

/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(Integer integer) {
super.onCanceled(integer);
}

/**
* Handles a request to stop the Loader.
* Automatically called by LoaderManager via stopLoading.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}

/**
* Handles a request to start the Loader.
* Automatically called by LoaderManager via startLoading.
*/
@Override
protected void onStartLoading() {
if (this.result != null) {
deliverResult(this.result);
}

if (takeContentChanged() || this.result == null) {
forceLoad();
}
}

/**
* Handles a request to completely reset the Loader.
* Automatically called by LoaderManager via reset.
*/
@Override
protected void onReset() {
super.onReset();

// Ensure the loader is stopped
onStopLoading();

// At this point we can release the resources associated with 'apps'
// if needed.
this.result = null;
}
}

@Override
public Loader<Integer> onCreateLoader(int arg0, Bundle arg1) {
Log.i("CHEOK", "onCreateLoader being called");
return new IntegerArrayLoader(this.getActivity());
}

@Override
public void onLoadFinished(Loader<Integer> arg0, Integer arg1) {
result = arg1;

}

@Override
public void onLoaderReset(Loader<Integer> arg0) {
// TODO Auto-generated method stub

}

public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
return v;
}

// http://stackoverflow.com/questions/11293441/android-loadercallbacks-onloadfinished-called-twice
@Override
public void onResume()
{
super.onResume();

if (result == null) {
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
} else {
// Restore from previous state. Perhaps through long pressed home
// button.
}
}

private Integer result;
}

完整的源代码可以从https://www.dropbox.com/s/n2jee3v7cpwvedv/loader_bug.zip下载

这可能与 1 个 Unresolved Android 错误有关:https://code.google.com/p/android/issues/detail?id=20791&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/DbKL6PVyhLI

我想知道,这个错误有什么好的解决方法吗?

最佳答案

我的回答其实很直截了当。不要使用 AsyncTaskLoaders。因为您现在已经知道一些关于 AsyncTaskLoaders 的错误。

一个很好的组合是一个可保留的 (setRetainInstance(true) in onActivityCreated()) fragment 与 AsyncTask。以同样的方式工作。只需要稍微重构一下代码。


来自 OP 的消息

虽然作者没有提供任何代码示例,但这是最接近可行的解决方案。我不使用作者提出的解决方案。相反,我仍然依赖 AsyncTaskLoader 来完成所有必要的加载任务。解决方法是,我将依靠一个额外的保留 fragment 来确定是否应该重新连接/创建加载器。这是整个想法的骨架代码。据我所知,效果很好。

@Override
public void onActivityCreated(Bundle savedInstanceState) {
...

dataRetainedFragment = (DataRetainedFragment)fm.findFragmentByTag(DATE_RETAINED_FRAGMENT);
// dataRetainedFragment can be null still...
}

@Override
public void onResume() {
...
if (this.data == null) {
if (dataRetainedFragment != null) {
// Re-use!
onLoadFinished(null, dataRetainedFragment);
} else {
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
} else {
}
}

@Override
public void onLoadFinished(Loader<Data> arg0, Data data) {
this.data = data;

if (this.dataRetainedFragment == null) {
this.dataRetainedFragment = DataRetainedFragment.newInstance(this.data);
FragmentManager fm = getFragmentManager();
fm.beginTransaction().add(this.dataRetainedFragment, DATE_RETAINED_FRAGMENT).commitAllowingStateLoss();
}

关于android - 加载程序在某些配置更改期间无法保留自身,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15897547/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com