天天看點

Android Loader 異步加載資料注意

Loader的概念:

裝載器從android3.0開始引進。它使得在activity或fragment中異步加載資料(資料庫的資料,包括本地資料庫,包括共享資料庫)變得簡單。

裝載器具有如下特性:

  • 它們對每個Activity和Fragment都有效;
  • 他們提供了異步加載資料的能力;
  • 它擁有一個資料改變通知機制,當資料源做出改變時會及時通知。 也就是可以監聽資料源,一旦資料源發生變化,Loader會感覺這些變化;
  • 當Cursor 發生變化時,會自動加載資料,是以并不需要再重新進行資料查詢。
  • android設計Loader的初衷是想讓大家像CursorLoader的做法一樣,通過loader去維護資料,每次啟動loader時先檢查有沒有舊的資料并把舊的資料先deliver給使用者,然後再考慮要不要重新加載新的資料。

裝載器API概述:

Class/Interface 說明
LoaderManager

一個抽象類,關聯到一個Activity或Fragment,管理一個或多個裝載器的執行個體。這幫助一個應用管理那些與Activity或Fragment的生命周期相關的長時間運作的的操作。最常見的方式是與一個CursorLoader一起使用,然而應用是可以随便寫它們自己的裝載器以加載其它類型的資料。

每個activity或fragment隻有一個LoaderManager。但是一個LoaderManager可以擁有多個裝載器。

LoaderManager.LoaderCallbacks 一個用于用戶端與LoaderManager互動的回調接口。例如,你使用回調方法onCreateLoader()來建立一個新的裝載器。onCreate, onFinish,onRestart
Loader(裝載器) 一個執行異步資料加載的抽象類。它是裝載器的基類。你可以使用典型的CursorLoader,但是你也可以實作你自己的子類。一旦裝載器被激活,它們将監視它們的資料源并且在資料改變時發送新的結果。
AsyncTaskLoader 提供一個AsyncTask來執行異步加載工作的抽象類。(可以處理任何的資料源,當然可以處理cursor)
CursorLoader AsyncTaskLoader的子類,它查詢ContentResolver然後傳回一個Cursor。這個類為查詢cursor以标準的方式實作了裝載器的協定,它的遊标查詢是通過AsyncTaskLoader在背景線程中執行,進而不會阻塞界面。使用這個裝載器是從一個ContentProvider異步加載資料的最好方式。相比之下,通過fragment或activity的API來執行一個被管理的查詢就不好了。

LoaderManager.LoaderCallbacks主要回調方法:

  1. onCreateLoader() :初始化并傳回一個新的Loader

    當你試圖去操作一個裝載器時(比如,通過initLoader()),會檢查是否指定ID的裝載器已經存在.如果它不存在,将會觸發LoaderManager.LoaderCallbacks 的方法onCreateLoader();

  2. onLoadFinished():當一個裝載器完成了它的裝載過程後被調用

    這個方法是在前面已建立的裝載器已經完成其加載過程後被調用.這個方法保證會在應用到裝載器上的資料被釋放之前被調用;

  3. onLoaderReset() :當一個裝載器被重置而其資料無效時被調用

    所謂Loader的重置,就是指Loader對象還保留,隻是清除Loader中的資料,是以onLoaderReset()方法相當于Loader的銷毀方法。是以在onLoaderReset()方法中會找到即将釋放的資料的引用,并移除這些引用。移除引用後,GC才可以清除這些資料。

    當一個已建立的裝載器被重置進而使其資料無效時,此方法被調用.此回調使你能發現什麼時候資料将被釋放。你可以釋放對它的引用。

示例代碼:

3.1 CursorLoader異步加載資料(聯系人):

package com.noonecode.cursorloaderdemo;

import android.app.Activity;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ListView;

/**
 * 查詢手機聯系人,用CursorLoader
 * 
 * CursorLoader一般用于查詢資料庫,ContentProvider執行耗時操作時使用
 * 
 * @author NoOneCode
 *
 */
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {

    private ListView mLvShow;
    private SimpleCursorAdapter adapter;
    private LoaderManager loaderManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLvShow = (ListView) findViewById(R.id.lv_show);

        adapter = new SimpleCursorAdapter(this, R.layout.contacts_item, null//
                , new String[] { "_id", "display_name" }//
                , new int[] { R.id.tv_id, R.id.tv_name }//
                , SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        mLvShow.setAdapter(adapter);
        // 擷取LoaderManager
        loaderManager = getLoaderManager();
        loaderManager.initLoader(, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        if (id == ) {
            return new CursorLoader(this, ContactsContract.RawContacts.CONTENT_URI,
                    new String[] { "_id", "display_name" }, null, null, "_id asc");
        }
        return null;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);
    }
}
           

3.2 AsyncTaskLoader異步加載資料(聯系人)

package com.noonecode.asynctaskloaderdemo;

import android.app.Activity;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.AsyncTaskLoader;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {

    private ListView mLvShow;
    private SimpleCursorAdapter adapter;
    private LoaderManager loaderManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLvShow = (ListView) findViewById(R.id.lv_show);
        adapter = new SimpleCursorAdapter(this, R.layout.contacts_item, null//
                , new String[] { "_id", "display_name" }//
                , new int[] { R.id.tv_id, R.id.tv_name }//
                , SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        mLvShow.setAdapter(adapter);
        loaderManager = getLoaderManager();
        loaderManager.initLoader(, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new MyLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);
    }


    public static class MyLoader extends AsyncTaskLoader<Cursor> {

        public MyLoader(Context context) {
            super(context);
        }

        @Override
        protected void onStartLoading() {
            super.onStartLoading();
            forceLoad();
        }

        @Override
        public Cursor loadInBackground() {
            ContentResolver resolver = getContext().getContentResolver();
            Cursor cursor = resolver.query(ContactsContract.RawContacts.CONTENT_URI,
                    new String[] { "_id", "display_name" }, null, null, null);
            return cursor;
        }

        @Override
        protected void onStopLoading() {
            super.onStopLoading();
        }
    }
}
           

注意

  • 本例主要講解使用Loader異步加載資料過程,加載聯系人其他資訊不在本例研究範圍之内,如有需求,請檢視我的這篇文章 Android ContentResolver ContactsContract 擷取手機聯系人資訊
  • 本例查詢的手機聯系人資訊需要讀取聯系人的權限:

本例不複雜,有源碼需求請留言!