Android Loader 異步加載詳解二:探尋Loader內(nèi)部機制
轉(zhuǎn)載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/70259914
本文出自【趙彥軍的博客】
Android Loader 異步加載詳解一:基礎概念
Android Loader 異步加載詳解二:探尋Loader內(nèi)部機制
在上一篇文章中,講解了 Loader 的基本概念。這一篇將會用實戰(zhàn)的方式來探尋 Android Loader的內(nèi)部機制。我們準備做一個 讀取手機短信的例子。廢話不多說,直接上效果圖:
所有的代碼都在:https://github.com/zyj1609wz/Loader
實例源碼
package com.app.loader.sms;
import android.app.LoaderManager;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import com.app.loader.R;
public class SmsActivity extends AppCompatActivity {private int loaderId =
0 ;
private ListView lv;
private SimpleCursorAdapter adapter;
private LoaderManager.LoaderCallbacks loaderCallbacks ;
private EditText editText ;
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_sms );Log.e(
"loader",
"activity onCreate: ");lv = (ListView) findViewById( R.id.listview );adapter =
new SimpleCursorAdapter(
this,R.layout.sms_listview_item ,
null,
new String[]{
"address",
"body"},
new int[]{R.id.address, R.id.body},SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);lv.setAdapter(adapter);loaderCallbacks =
new MyCallback() ;getLoaderManager().initLoader( loaderId ,
null, loaderCallbacks );editText = (EditText) findViewById( R.id.editText );findViewById( R.id.start).setOnClickListener(
new View.OnClickListener() {
@Overridepublic void onClick(View v) {String tag = editText.getText().toString() ;Bundle bundle =
new Bundle();bundle.putString(
"key", tag );getLoaderManager().restartLoader( loaderId , bundle, loaderCallbacks );}});findViewById( R.id.init).setOnClickListener(
new View.OnClickListener() {
@Overridepublic void onClick(View v) {getLoaderManager().initLoader( loaderId ,
null, loaderCallbacks );}});}class MyCallback implements LoaderManager.LoaderCallbacks<Cursor> {
@Overridepublic Loader
onCreateLoader(
int id, Bundle args) {SmsLoader loader =
new SmsLoader( SmsActivity.
this , args);Log.e(
"loader",
"onCreateLoader: ");
return loader ;}
@Overridepublic void onLoadFinished(Loader<Cursor> loader, Cursor data) {Log.e(
"loader",
"onLoadFinished: ");adapter.changeCursor( data );}
@Overridepublic void onLoaderReset(Loader loader) {Log.e(
"loader",
"onLoaderReset: ");adapter.swapCursor(
null);}}
@Overrideprotected void onResume() {Log.e(
"loader",
"activity onResume: ");
super.onResume();}
@Overrideprotected void onPause() {Log.e(
"loader",
"activity onPause: ");
super.onPause();}
@Overrideprotected void onDestroy() {Log.e(
"loader",
"activity onDestroy: ");
super.onDestroy();}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.app.loader.MainActivity"><EditText
android:id="@+id/editText"android:layout_width="match_parent"android:layout_height="50dp"android:hint="請你輸入過濾關鍵詞"/><Button
android:id="@+id/start"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="開始查詢"/><Button
android:id="@+id/init"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="開始執(zhí)行 init方法"/><ListView
android:id="@+id/listview"android:layout_width="match_parent"android:layout_height="match_parent"></ListView></LinearLayout>
- SmsLoader 類繼承 AsyncTaskLoader
package com.app.loader.sms;
import android.content.AsyncTaskLoader;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
/*** Created by ${zhaoyanjun} on 2017/4/19.*/public
class SmsLoader extends AsyncTaskLoader<Cursor> {private Bundle bundle;
private Uri uri = Uri.parse(
"content://sms");
private String []colums = {
"_id",
"address",
"body"};public SmsLoader(Context context , Bundle bundle ) {
super(context);
this.bundle = bundle;}
@Overridepublic Cursor loadInBackground() {String selection =
null;String[] selectionArgs =
null;
if (bundle!=
null) {selection =
"body like ? ";selectionArgs =
new String[]{
"%"+bundle.getString(
"key")+
"%"};}Cursor cursor = getContext().getContentResolver().query(uri, colums, selection , selectionArgs,
null);Log.e(
"loader",
"loadInBackground: ");
return cursor;}
@Overrideprotected void onStartLoading() {
super.onStartLoading();forceLoad();Log.e(
"loader",
"onStartLoading: ");}
}
測試
- 第一次 Activity 啟動 Log 日志分析 :
com.app.loader E/loader: activity onCreate:
com.app.loader E/loader: onCreateLoader:
com.app.loader E/loader: onStartLoading:
com.app.loader E/loader: loadInBackground:
com.app.loader E/loader: onLoadFinished:
可以看到 第一次調(diào)用 initLoader() 方法后
getLoaderManager().initLoader( loaderId ,
null, loaderCallbacks );
首先 調(diào)用 LoaderCallbacks 中的 onCreateLoader 來創(chuàng)建一個 Loader 對象,然后調(diào)用 SmsLoader 中的 onStartLoading方法。然后調(diào)用 SmsLoader 中的 loadInBackground 開始執(zhí)行 異步任務。最后在 LoaderCallbacks 中 onLoadFinished 方法中回調(diào)。
- 點擊 “開始執(zhí)行 Init 方法” 按鈕,Log 分析
點擊 “開始執(zhí)行 Init 方法”按鈕后,開始執(zhí)行
getLoaderManager().initLoader( loaderId ,
null, loaderCallbacks );
Log 日志為:
com.app.loader E/loader: onLoadFinished:
這里只回調(diào)了 onLoadFinished 的方法,把異步操作產(chǎn)生的數(shù)據(jù)給傳遞出來。請注意,這里沒有走 loadInBackground 方法,說明此時 onLoadFinished 回傳的數(shù)據(jù),是舊數(shù)據(jù),也就是上一次異步產(chǎn)生的數(shù)據(jù)。
但是有時我們想丟棄舊數(shù)據(jù)然后重新開始創(chuàng)建一個新Loader,這可怎么辦呢?別擔心,要丟棄舊數(shù)據(jù)調(diào)用restartLoader()即可。
點擊 開始查詢按鈕 ,會執(zhí)行下面的代碼
String tag = editText
.getText()
.toString() ;
Bundle bundle
= new Bundle();
bundle
.putString(
"key",
tag );
getLoaderManager()
.restartLoader( loaderId , bundle, loaderCallbacks );
Log 日志:
com.app.loader E/loader: onCreateLoader:
com.app.loader E/loader: onStartLoading:
com.app.loader E/loader: loadInBackground:
com.app.loader E/loader: onLoadFinished:
通過日志可以看出 restartLoader重新執(zhí)行了 onCreateLoader 創(chuàng)建了一個新的 Loader 對象; loadInBackground 丟棄了舊數(shù)據(jù),重新加載了新數(shù)據(jù) , 并且回調(diào) onLoadFinished 。
在測試的時候,我發(fā)現(xiàn)當前 Activity 從后臺到前臺的時候,調(diào)用順序如下:
com.app.loader E/loader: onStartLoading:
com.app.loader E/loader: activity onResume:
com.app.loader E/loader: loadInBackground:
com.app.loader E/loader: onLoadFinished:
可以看到當前界面從后臺到前臺的過程中,Loader 會自動調(diào)異步任務,并且回調(diào)新的數(shù)據(jù)。
當前 Activity 銷毀的時候,調(diào)用順序如下:
com.app.loader E/loader: activity onPause:
com.app.loader E/loader: activity onDestroy:
com.app.loader E/loader: onLoaderReset:
可以看到 LoaderCallbacks 的 onLoaderReset 方法會回調(diào)。
當 onLoaderReset 方法被調(diào)用的時候,代表 這個 Loader 正在被重置,此時的數(shù)據(jù)不可用。應用程序應該在這一點上刪除對Loader數(shù)據(jù)的任何引用。
比如:
@Overridepublic void onLoaderReset(Loader loader) {Log.e(
"loader",
"onLoaderReset: ");adapter.swapCursor(
null);}
參考文檔:
官方文檔
使用CursorLoader執(zhí)行查詢?nèi)蝿?/p>
Android應用Loaders全面詳解及源碼淺析
Android之Loader介紹
總結
以上是生活随笔為你收集整理的Android Loader 异步加载详解二:探寻Loader内部机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。