使用AsyncTaskLoader加载数据

AsyncTaskLoader 是在Android 3.0加入了,需要兼容更低版本可以使用V4包,AsyncTaskLoader只能在FragmentActivity上使用,并且生命周期跟随ActivityonStart()onStop()onDestory(),内部线程使用AsyncTask和 v4包中使用ModernAsyncTask,如果使用的AsyncTask默认Executor 不会是的SERIAL_EXECUTOR(一次只能执行一个任务)。

1.AsyncTaskLoader的优缺点

优点:使用AsyncTask执行数据请求,如果当前在Activity关闭后还没有执行完成,那么Activity的就会被持有,因而导致内存泄漏,通常我们的做法是在Activity或者Fragment中的onDestory()方法中做一些数据清理工作,以及引用持有的清理工作,而AsyncTaskLoader 有生命周期的管理则会帮我们处理好这些。

缺点:我们只能在Activity或者Fragment中使用,并且不能使用AsyncTask的progress

2.Loader生命周期管理

AsyncTaskLoader最终通过LoaderManager 进行生命周期管理,数据分发以及回调,在Activity中有一个LoaderManager mLoaderManager实例,我们在Activity或者Fragment 中调用getLoaderManager()创建出这个实例。
mLoaderManager在Activity中生命周期的管理分别是:

1.onStart()

    protected void onStart() {
     if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
     mCalled = true;

    if (!mLoadersStarted) {
        mLoadersStarted = true;
        if (mLoaderManager != null) {
            mLoaderManager.doStart();
        } else if (!mCheckedForLoaderManager) {
            mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
        }
        mCheckedForLoaderManager = true;
    }

    getApplication().dispatchActivityStarted(this);
    }

2.performStop()

   final void performStop() {
        mDoReportFullyDrawn = false;
        if (mLoadersStarted) {
            mLoadersStarted = false;
            if (mLoaderManager != null) {
                if (!mChangingConfigurations) {
                    mLoaderManager.doStop();
                } else {
                    mLoaderManager.doRetain();
                }
            }
        }

3.performDestroy()

 final void performDestroy() {
        mDestroyed = true;
        mWindow.destroy();
        mFragments.dispatchDestroy();
        onDestroy();
        if (mLoaderManager != null) {
            mLoaderManager.doDestroy();
        }
        if (mVoiceInteractor != null) {
            mVoiceInteractor.detachActivity();
        }
    }

3.使用AsyncTaskLoader

1. 在Activity中实现LoaderManager.LoaderCallbacks<D>

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<ApplicationInfo>> {

2. 实现三个方法:
     @Override
      public Loader<List<ApplicationInfo>> onCreateLoader(int id, Bundle args) {

        //args 是getSupportLoaderManager().initLoader传过来的数据
        Log.e("branch", "onCreateLoader");

        return new AppListLoader(this);
      }

      @Override
      public void onLoadFinished(Loader<List<ApplicationInfo>> loader, List<ApplicationInfo> data) {


        Log.e("branch", "onLoadFinished-》 " + data);

        mListApps = data;

        mApplistAdapter.notifyDataSetChanged();

        if (progressDialog != null) {
          progressDialog.dismiss();
        }
      }

      @Override
      public void onLoaderReset(Loader<List<ApplicationInfo>> loader) {

        Log.e("branch", "onLoaderReset");
        if (progressDialog != null) {
          progressDialog.dismiss();
        }

        mListApps = null;
        mApplistAdapter.notifyDataSetChanged();

      }

onCreateLoader 方法中创建我们的Loader,在Activity的onCreate()或者其他地方调用方法中调用Loader init 方法,如

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startLoad();
      }

     
      private void startLoad() {

        progressDialog = new ProgressDialog(this);
        progressDialog.show();

        getSupportLoaderManager().initLoader(1, null, this);
        

      }

当你想放弃上一次的数据是,可以使用getLoaderManager().restartLoader(0, null, this);

    public boolean onTextChanged(String newText) {
        // Called when the action bar search text has changed.  Update
        // the search filter, and restart the loader to do a new query
        // with this filter.
        getLoaderManager().restartLoader(0, null, this);
        return true;
    }

这样写完我们的Loader就开始加载数据了

4.AppListLoader的实现

继承 AsyncTaskLoader ,实现以下几个方法

    public class AppListLoader extends AsyncTaskLoader<List<ApplicationInfo>> {

      List<ApplicationInfo> mApps;

      PackageManager mPm;

      public AppListLoader(Context context) {
        super(context);

        // Retrieve the package manager for later use; note we don't
        // use 'context' directly but instead the save global application
        // context returned by getContext().
        mPm = getContext().getPackageManager();
      }

      /**
       * This is where the bulk of our work is done.  This function is called in a background thread and
       * should generate a new set of data to be published by the loader.
       */
      @Override
      public List<ApplicationInfo> loadInBackground() {
        // Retrieve all known applications.
        List<ApplicationInfo> apps = mPm.getInstalledApplications(
            PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS | PackageManager.GET_META_DATA);
        if (apps == null) {
          apps = new ArrayList<ApplicationInfo>();
        }

        // Done!
        return apps;
      }

      /**
       * Called when there is new data to deliver to the client.  The super class will take care of
       * delivering it; the implementation here just adds a little more logic.
       */
      @Override
      public void deliverResult(List<ApplicationInfo> apps) {
        if (isReset()) {
          // An async query came in while the loader is stopped.  We
          // don't need the result.
          if (apps != null) {
            onReleaseResources(apps);
          }
        }
        List<ApplicationInfo> oldApps = mApps;
        mApps = apps;

        if (isStarted()) {
          // If the Loader is currently started, we can immediately
          // deliver its results.
          super.deliverResult(apps);
        }

        // At this point we can release the resources associated with
        // 'oldApps' if needed; now that the new result is delivered we
        // know that it is no longer in use.
        if (oldApps != null) {
          onReleaseResources(oldApps);
        }
      }

      /**
       * Handles a request to start the Loader.
       */
      @Override
      protected void onStartLoading() {
        if (mApps != null) {
          // If we currently have a result available, deliver it
          // immediately.
          deliverResult(mApps);
        }

        if (takeContentChanged() || mApps == null) {
          // If the data has changed since the last time it was loaded
          // or is not currently available, start a load.
          forceLoad();
        }
      }

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

      /**
       * Handles a request to cancel a load.
       */
      @Override
      public void onCanceled(List<ApplicationInfo> apps) {
        super.onCanceled(apps);

        // At this point we can release the resources associated with 'apps'
        // if needed.
        onReleaseResources(apps);
      }

      /**
       * Handles a request to completely reset the Loader.
       */
      @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.
        if (mApps != null) {
          onReleaseResources(mApps);
          mApps = null;
        }

      }

      /**
       * Helper function to take care of releasing resources associated with an actively loaded data
       * set.
       */
      protected void onReleaseResources(List<ApplicationInfo> apps) {
        // For a simple List<> there is nothing to do.  For something
        // like a Cursor, we would close it here.
      }

    }

5.效果图

效果图
效果图

6.demo

源码

Apk

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 1 背景## 在Android中任何耗时的操作都不能放在UI主线程中,所以耗时的操作都需要使用异步实现。同样的,在...
    我是昵称阅读 1,199评论 0 3
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 在干嘛,在睡觉,好的睡吧。 在干嘛,在上班,好的上吧。 在干嘛,在吃饭,好的吃吧。 在干嘛,在喝水,好的喝吧。 在...
    李婵亦阅读 1,206评论 0 0
  • 淅淅零零,来来往往,自使江头,娑落络路。
    嗨馮先生阅读 165评论 0 0
  • 说也奇怪,不知什么时候脖圆食堂里流传起这样一首歌谣。 面坨坨,搅团团从小就想江湖里转搅啊搅,转啊转漏成鱼鱼把大侠变...
    稀饭被注册了阅读 170评论 0 0