装载机无法在某些配置更改保留自己 [英] Loader unable to retain itself during certain configuration change

查看:165
本文介绍了装载机无法在某些配置更改保留自己的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据<一href="http://developer.android.com/guide/components/loaders.html">http://developer.android.com/guide/components/loaders.html,关于装载机的好处之一是,它能够在配置更改,以保持其数据。

According to http://developer.android.com/guide/components/loaders.html, one of the nice thing about loader is that, it is able to retain its data during configuration change.

他们是在自动重新连接到最后加载程序的指针   配置更改后重新创建。因此,它们不需要   重新查询他们的数据。

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.

但是,它不能在所有情况下工作良好。

However, it doesn't work well in all scenarios.

我采取以下简单的例子。这是一个 FragmentActivity ,这是主持片段。该片段本身欠 AsyncTaskLoader

I take a following simple example. It is a FragmentActivity, which is hosting a Fragment. The Fragment itself owes the AsyncTaskLoader.

以下3个方案工作pretty的好。

The following 3 scenarios work pretty well.

1加载器创建的,而 loadInBackground 被执行一次。

1 loader is created, and loadInBackground is executed once.

没有新的装载机正在创建和 loadInBackground 不被触发。

No new loader is being created and loadInBackground is not being triggered.

没有新的装载机正在创建和 loadInBackground 不被触发。

No new loader is being created and loadInBackground is not being triggered.

然而,在下面的情形。

在那个时候,老装载机的 onReset 被调用。旧的装载机将被销毁。新的Loader将创建新加载的 loadInBackground 将被再次触发。

At that time, old loader's onReset is called. Old loader will be destroyed. New loader will be created and new loader's loadInBackground will be triggered again.

没有新的装载机将被创建正确的行为我很期待。

装载机与code是如下。我跑下的Andr​​oid 4.1模拟器的code。

The loader related code is as follow. I run the code under Android 4.1 emulator.

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;
}

完整源$ C ​​$ C可以从<一个下载href="https://www.dropbox.com/s/n2jee3v7cpwvedv/loader_bug.zip">https://www.dropbox.com/s/n2jee3v7cpwvedv/loader_bug.zip

这可能与1未解Android的错误:<一href="https://$c$c.google.com/p/android/issues/detail?id=20791&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars">https://$c$c.google.com/p/android/issues/detail?id=20791&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

This might be related to 1 unsolved Android bug : https://code.google.com/p/android/issues/detail?id=20791&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

<一个href="https://groups.google.com/forum/?fromgroups=#!topic/android-developers/DbKL6PVyhLI">https://groups.google.com/forum/?fromgroups=#!topic/android-developers/DbKL6PVyhLI

我想知道,有没有什么好的解决办法对这个bug?

推荐答案

我的答案很简单的实际。不要使用AsyncTaskLoaders。因为关于AsyncTaskLoaders一些错误,你现在知道了。

My answer is quite straight forward actually. Don't use AsyncTaskLoaders. Because a few bugs regarding AsyncTaskLoaders you knew it by now.

有一个很好的结合将是一个可保留(setRetainInstance(真)的onActivityCreated())片段,AsyncTask的。以同样的方式。只要有重组℃的位$ C $。

A good combination would be a retainable (setRetainInstance(true) in onActivityCreated()) fragment with AsyncTask. Works the same way. Just have to restructure the code a bit.

虽然笔者不提供任何code为例,这是最近的可行的解决方案。我不使用建议的作者的解决方案。相反,我还是靠 AsyncTaskLoader 所需的全部装载任务。解决方法是这样的,我会依靠一个额外的保留片段,以确定我是否应该重新连接/创建装载机。该是对整个构思骨架code。作品pretty的很好,到目前为止,只要我可以告诉。

Although the author doesn't provide any code example, this is the closest workable solution. I do not use the author proposed solution. Instead, I still rely on AsyncTaskLoader for all the necessary loading task. The workaround is that, I will rely on an additional retained fragment, to determine whether I should reconnect/create loader. The is the skeleton code on the whole idea. Works pretty well so far as long as I can tell.

@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();            
    }

这篇关于装载机无法在某些配置更改保留自己的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆