源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

详细讲解Android中使用LoaderManager加载数据的方法

  • 时间:2020-05-03 02:19 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:详细讲解Android中使用LoaderManager加载数据的方法
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) {
 
  }
}

[b]LoaderManager与生命周期 [/b]Activity和Fragment都拥有getLoaderManager的方法,其实Fragment的getLoaderManager去获取的就是Activity所管理的众多LoaderManager之一。 [b]1.Who标签 [/b]先来看一下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 甚至更大的深度。 [b]2.LoaderManager状态量mLoadersStarted [/b]在开篇分析的时候分析过LoaderManager内部保存了一个mStarted状态,很多操作会根据这个状态做不同处理。通过上边的分析也能看出,Fragment中获取LoaderManager最终是通过Activity获取的,在LoaderManager构造时,就将一个状态量mLoadersStarted传递了进去,这个状态量交给LoaderManager自行管理。 而无论是Fragment还是Activity,都有mLoadersStarted这样一个状态量,在onStart生命周期后为true,onStop后为false。所以在onStart生命周期后做initLoader操作就会使Loader一经初始化就开始运行了。 [b]3.Fragment和Activity的生命周期 [/b]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。 [b]4.LoaderManager的生命周期 [/b]因为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生命周期时再给我。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部