Android異步處理之AsyncTaskLoader簡單使用


簡介

不管是在Android應用開發還是Android平台開發中,異步處理通常是最基本的coding要求。如果你還在主線程中寫一些數據庫,網絡請求,讀寫本地文件等操作的話那說明你還不是一個合格的Android程序員。

通常情況下我們使用的最多的Android異步處理方法是AsyncTaskHandler,但今天要給大家帶來的是大家不常使用的AsyncTaskLoader的使用方法。

AsyncTaskLoader從名字看出來它似乎和AsyncTask有關系,看一下Google官方是怎么給AsyncTaskLoader下定義的:

Abstract Loader that provides an AsyncTask to do the work

果然是樣,AsyncTaskLoader是使用一個AsyncTask來進行異步處理的。那么問題來了,既然都有了AsyncTask了為什么還要搞出來一個AsyncTaskLoader呢?

其實AsyncTaskLoader遠沒有大家想的那么簡單。說的通俗一點,如果把AsyncTask比作一台烤面包機的話,那么AsyncTaskLoader就是操作烤面包機的面包師。AsyncTask如同烤面包機接受命令完成面包的烤制任務,一旦任務完成它就停止了工作。然而AsyncTaskLoader如同面包師一樣要根據顧客的需求來使用烤面包機。顧客會不停的光顧,那么面包師就會不停的使用烤面包機烤面包。

具體事例

下面我們就通過烤面包機和面包師的例子來演示一下AsyncTaskLoader的使用方法。

首先肯定少不了面包師(Baker):

package com.example.asyncloaderdemo;

import java.util.ArrayList;
import java.util.List;

import android.content.AsyncTaskLoader;
import android.content.Context;

public class Baker extends AsyncTaskLoader<List<Bread>> {

    // 用於查詢當前需要多少個面包
    BakeryCallback mCallback;

    //面包房回調,用於獲得當面面包需求量
    interface BakeryCallback {
        int getNeededBreads();
    }

    public Baker(Context context, BakeryCallback callback) {
        super(context);
        mCallback = callback;
    }

    @Override
    public List<Bread> loadInBackground() {
        List<Bread> breads = new ArrayList<Bread>();
        //獲得當前需要做的面包
        int needs = mCallback.getNeededBreads();
        for (int i = 0; i < needs; i++) {
            //制作面包,耗時操作
            breads.add(new Bread());
        }
        //面包制作完成
        return breads;
    }

    @Override
    public void deliverResult(List<Bread> data) {
        super.deliverResult(data);
    }

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

    @Override
    protected void onStopLoading() {
        cancelLoad();
    }

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

面包師有了,面包房(Bakery)也不能少

package com.example.asyncloaderdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

public class Bakery extends BroadcastReceiver {

    final Baker mBaker;
    
    public static String CUSTOMER_ACTION = "com.example.asyncloaderdemo.new_customer" ;

    public Bakery(Baker baker) {
        mBaker = baker;
        IntentFilter filter = new IntentFilter(CUSTOMER_ACTION);
        baker.getContext().registerReceiver(this, filter);
    }

    @Override public void onReceive(Context context, Intent intent) {
        //通知面包師來客人了,要做面包了。
        mBaker.onContentChanged();
    }

}

面包房和面包師都有了,還缺一個場景(MainActivity)

package com.example.asyncloaderdemo;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.example.asyncloaderdemo.Baker.BakeryCallback;

import android.support.v7.app.ActionBarActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Intent;
import android.content.Loader;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends ActionBarActivity {

    private LoaderCallbacks<List<Bread>> mCallbacks;
    //面包房
    private Bakery mBakery;
    //面包師
    private Baker mBaker;
    //面包需求量
    private int mNeededBreads;
    //唯一標識
    private final int mLoaderId = 42;

    private BakeryCallback mBreadCallback = new BakeryCallback() {
        @Override
        public int getNeededBreads() {
            return mNeededBreads;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mNeededBreads = 0;
        mBaker = new Baker(this, mBreadCallback);
        mBakery = new Bakery(mBaker);
        mCallbacks = new LoaderCallbacks<List<Bread>>() {

            @Override
            public Loader<List<Bread>> onCreateLoader(int id, Bundle args) {
                if (mBaker == null) {
                    mBaker = new Baker(MainActivity.this, mBreadCallback);
                }
                return mBaker;
            }

            @Override
            public void onLoadFinished(Loader<List<Bread>> loader, List<Bread> data) {
                mNeededBreads = 0 ;
                //面包師完成面包烤制
                Log.d("scott", "sell " + data.size() + " breads") ;
            }

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

            }
        };
        //面包師開始工作
        getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
        //顧客開始上門
        mockCustomer();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mBakery);
    }

    //模擬源源不斷的顧客需求
    private void mockCustomer(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(3000);
                        Random random = new Random();
                        mNeededBreads =random.nextInt(10);
                        Intent intent = new Intent(Bakery.CUSTOMER_ACTION);
                        sendBroadcast(intent);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

接下來我們來看一下程序運行結果:
面包房運行結果
通過上圖並結合代碼可以看出來每隔三秒就會有新的顧客上門,顧客上門后面包房通知面包師需要做面吧哦了,接着面包師就會在后台不停的開始使用面包機(AsyncTask)做面包。

總結

說到這里可能有些同學有疑問了,我怎么從頭到尾都沒有開到AsyncTask的影子呢?你當然看不到,這就是AsyncTaskLoader設計精妙之處,它做到了讓你唯一需要考慮的就是烤面包(異步處理)這個事物邏輯,而不需要考慮異步處理本身的實現上。同時這也充分體現了設計模式中的單一職責最少知道原則。

使用場景

AsyncTaskLoader一般使用在數據源處於不斷更新並且請求刷新數據源是個耗時操作的情況下還需要UI去同步更新相關數據的場景(這句話怎么這么拗口)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM