国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

詳細講解Android中使用LoaderManager加載數據的方法

2019-12-12 06:31:49
字體:
來源:轉載
供稿:網友

Android的設計之中,任何耗時的操作都不能放在UI主線程之中。所以類似于網絡操作等等耗時的操作都需要使用異步的實現。而在ContentProvider之中,也有可能存在耗時的操作(當查詢的數據量很大的時候),這個時候我們也需要使用異步的調用來完成數據的查詢。

當使用異步的query的時候,我們就需要使用LoaderManager了。使用LoaderManager就可以在不阻塞UI主線程的情況下完成數據的加載。

(1)獲取loaderManger:activity.getLoaderManager()

(2)loaderManager的事件回調接口, LoaderManager.LoaderCallbacks<D>

下面是一個demo,從contentprovider中query數據添加到listview中,是異步執行的。

MySQLiteOpenHeleper.java:

package com.app.loadermanager;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper; public class MySQLiteOpenHelper extends SQLiteOpenHelper {   public static final String db_name = "test.db3";  public static final int version = 1;   public MySQLiteOpenHelper(Context context) {    super(context, db_name, null, version);  }   @Override  public void onCreate(SQLiteDatabase db) {     String create_sql = "create table tb_student(_id integer primary key autoincrement,name varchar(20),age integer)";    db.execSQL(create_sql);  }   @Override  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {   } }

MyContentProvider.java

package com.app.loadermanager; import android.content.ContentProvider;import android.content.ContentUris;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.net.Uri; public class MyContentProvider extends ContentProvider {   private MySQLiteOpenHelper helper = null;  private static final UriMatcher matcher = new UriMatcher(      UriMatcher.NO_MATCH);  private static final int students = 1;  static {    matcher.addURI("com.app.contentprovider", "tb_student", students);  }   @Override  public int delete(Uri arg0, String arg1, String[] arg2) {    return 0;  }   @Override  public String getType(Uri arg0) {    return null;  }   @Override  public Uri insert(Uri uri, ContentValues values) {    SQLiteDatabase db = helper.getWritableDatabase();    int flag = matcher.match(uri);    switch (flag) {    case students:      long id = db.insert("tb_student", null, values);      return ContentUris.withAppendedId(uri, id);    }    return null;  }   @Override  public boolean onCreate() {    helper = new MySQLiteOpenHelper(this.getContext());    return true;  }   @Override  public Cursor query(Uri uri, String[] projection, String selection,      String[] selectionArgs, String sortOrder) {    SQLiteDatabase db = helper.getWritableDatabase();    Cursor cursor=db.query("tb_student", projection, selection, selectionArgs, null, null, null);    return cursor;  }   @Override  public int update(Uri uri, ContentValues values, String selection,      String[] selectionArgs) {    return 0;  } }

MainActivity.java:

package com.app.loadermanager; import java.util.ArrayList; import android.annotation.SuppressLint;import android.app.Activity;import android.app.LoaderManager;import android.content.CursorLoader;import android.content.Loader;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.widget.ArrayAdapter;import android.widget.ListView; @SuppressLint("NewApi")public class MainActivity extends Activity implements    LoaderManager.LoaderCallbacks<Cursor> {   LoaderManager manager = null;  ListView listView = null;   @SuppressLint("NewApi")  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    listView = (ListView) this.findViewById(R.id.listview);    manager = this.getLoaderManager();    manager.initLoader(1000, null, this);  }   @Override  public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {    CursorLoader loader = new CursorLoader(this,        Uri.parse("content://com.app.contentprovider"), null, null,        null, null);    return loader;  }   @Override  public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {    ArrayList<String> al = new ArrayList<String>();    while (cursor.moveToNext()) {      String name = cursor.getString(cursor.getColumnIndex("name"));      al.add(name);    }    ArrayAdapter adapter=new ArrayAdapter(this,android.R.layout.simple_list_item_1,al);    listView.setAdapter(adapter);    adapter.notifyDataSetChanged();       }   @Override  public void onLoaderReset(Loader<Cursor> loader) {   }}

LoaderManager與生命周期
Activity和Fragment都擁有getLoaderManager的方法,其實Fragment的getLoaderManager去獲取的就是Activity所管理的眾多LoaderManager之一。

1.Who標簽
先來看一下Activity的getLoaderManager方法:

   LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {     if (mAllLoaderManagers == null) {       mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();     }     LoaderManagerImpl lm = mAllLoaderManagers.get(who);     if (lm == null) {       if (create) {         lm = new LoaderManagerImpl(who, this, started);         mAllLoaderManagers.put(who, lm);       }     } else {       lm.updateActivity(this);     }     return lm;   }

mAllLoaderManagers保存著一個Activity所擁有的所有LoaderManager,其key為String類型的who變量。若從Activity調用getLoaderManager,那么所得LoaderManager的who標簽為(root):

   public LoaderManager getLoaderManager() {     if (mLoaderManager != null) {       return mLoaderManager;     }     mCheckedForLoaderManager = true;     mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);     return mLoaderManager;   }

若從Fragment中使用getLoaderManager,則所得LoaderManager的who標簽會根據Fragment的層級不同而不同,在Activity中處于最頂級的Fragment的who標簽為:

android:fragment:X
X為序號。

而屬于Fragment的Fragment所活的的LoaderManager who標簽就成為了:

android:fragment:X:Y
甚至更大的深度。

2.LoaderManager狀態量mLoadersStarted
在開篇分析的時候分析過LoaderManager內部保存了一個mStarted狀態,很多操作會根據這個狀態做不同處理。通過上邊的分析也能看出,Fragment中獲取LoaderManager最終是通過Activity獲取的,在LoaderManager構造時,就將一個狀態量mLoadersStarted傳遞了進去,這個狀態量交給LoaderManager自行管理。

而無論是Fragment還是Activity,都有mLoadersStarted這樣一個狀態量,在onStart生命周期后為true,onStop后為false。所以在onStart生命周期后做initLoader操作就會使Loader一經初始化就開始運行了。

3.Fragment和Activity的生命周期
Fragment和Activity能夠對LoaderManager產生影響的生命周期是一樣的。

onStart

系統在onStart階段會獲取LoaderManager,如果成功獲取,則調用LoaderManager的doStart(),這里需要特別說明的是,雖然所有LoaderManager都是保存在Activity中,但是在Activity的onStart生命周期其也只是會獲取屬于自己的(root)標簽LoaderManager,而并不是將所有保存在mAllLoaderManagers里的Manager全部遍歷一遍。

onStop(performStop)

處于onStop生命周期,但是系統內部是通過performStop調用的。在這里,同樣會獲取屬于自己的LoaderManager,如果Activity是因為配置改變出發的onStop(旋轉屏幕),則調用LoaderManager的doRetain()接口,如果不是,就調用LoaderManager的doStop()接口。

onDestroy(performDestroy)

調用LoaderManager的doDestroy()接口銷毀LoaderManager。

4.LoaderManager的生命周期
因為LoaderManager與Fragment/Activity的生命周期緊密相連,所以想要用好LoaderManager就必須了解其自身的生命周期,這樣就能把握數據的完整變化規律了。

正常的從出生到銷毀:

doStart() -> doReportStart() -> doStop() -> doDestroy()
Activity配置發生變化:

doStart() -> doRetain() -> finishRetain() -> doReportStart() -> doStart() -> doStop() -> doDestroy()
Fragment在onDestroyView()之后還會執行LoaderManager的doReportNextStart(), 即:

doStart() -> doRetain() -> doReportNextStart() -> finishRetain() -> doReportStart() -> doStart() -> doStop() -> doDestroy()
doStart()會將LoaderManager中保存的所有Loader都啟動。最終是運行每一個Loader的onStartLoading()方法。只要是通過initLoader使用過的Loader都會記錄在LoaderManager的mLoaders中,那么問題來了:

怎樣在Fragment/Activity不銷毀的前提下從LoaderManager中移除某個使用過的Loader呢?
答案就是使用LoaderManager的接口去除指定ID的Loader:

public void destroyLoader(int id)
這樣就能在mLoaders中移除掉了,下次onStart的時候就沒有這個Loader什么事了。

doReportStart()。如果Fragment上一次在銷毀并重做,而且數據有效的話會在這里主動上報數據,最終走到callback的onLoadFinished中。
doStop()會停止mLoaders保存的所有Loader。最終是運行每一個Loader的onStopLoading()方法。
doDestroy()會清空所有有效和無效Loader,LoaderManager中不再存在任何Loader。
doRetain()會將LoaderManager的mRetaining狀態置位true,并且保存retain時LoaderInfo的mStarted狀態
finishRetain()如果之前所保存的mStarted與現在的不一樣而且新的狀態是停止的話,就停止掉這個Loader。否則若有數據并且不是要下次再上報(沒有call doReportNextStart)的話就上報給callback的onLoadFinished。
doReportNextStart(),根據第6條,已經能夠理解了。當Fragment執行到onDestroyView生命周期時,對自己的LoaderManager發出請求:即使現在有數據也不要進行上報,等我重做再到onStart生命周期時再給我。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 凤庆县| 胶州市| 黎川县| 崇义县| 蛟河市| 大丰市| 平泉县| 桃园县| 余庆县| 图片| 色达县| 延川县| 攀枝花市| 荔波县| 凤凰县| 白山市| 响水县| 金阳县| 巨鹿县| 丹寨县| 环江| 金沙县| 阿拉尔市| 汉寿县| 长寿区| 英超| 萍乡市| 满洲里市| 大新县| 丰都县| 三台县| 武陟县| 温州市| 乌兰浩特市| 汉沽区| 丹巴县| 中江县| 兴文县| 邛崃市| 周口市| 兴文县|