Data loading mechanism in Android-Loader (1)

Loader Introduction

Loader is rarely used in normal development, but if you look at the source code of system applications, you will find that many system applications use Loader. This article briefly introduces Loader in Android.

Loader has been introduced since android3.0. It makes it easy to load data asynchronously in an activity or fragment
. Loader has the following characteristics:

1. They are valid for every Activity and Fragment.
2. They provide the ability to load data asynchronously.
3. They monitor every move of the data source and deliver new results when the content changes.
4. When recreated due to configuration changes, they are automatically reconnected to the previous loader's cursor, so there is no need to
requery the data.

The data source of Loader can be disk, database, ContentProvider, network or another process.
The Loader can get and send the result data to the receiver without blocking the main thread. (asynchronous)

The core classes provided by Loader technology are:
LoaderManager : Used to manage Loader, an Activity or Fragment can only have one
LoaderManager.
LoaderManager.LoaderCallbacks : Used to interact with the LoaderManager, where
Loader objects can be created.
AsyncTaskLoader : an abstract class, a Loader that can load data asynchronously. It seems that it is also implemented internally through
AsynTask. You can inherit it to build your own Loader, or use an existing subclass. For example,
you can use CursorLoader to query the database asynchronously.

Usage of CursorLoader

1. Scenarios of CursorLoader
For example, if a text message comes, the text message database changes, and the user does not leave the text message list interface, the
newly arrived text message data should be updated to the UI interface in real time.

2. Usage of CursorLoader

Step 1: Get the LoaderManager object
You can get the LoaderManager through the getLoaderManager() method of the Activity or Fragment,
LoaderManager lm = getLoaderManager();

Step 2: Initialize Loader
lm .initLoader(intid, Bundle args, LoaderManager.LoaderCallbacks callback);

Parameter description:
id : the ID used to identify the Loader. An Activity or Fragment can only have one LoaderManager,
but can have multiple Loaders, which are distinguished by ID. When creating a new Loader, if a Loader with the same ID is found
, the Loader will be reused instead of recreated.
args : Parameters passed to the new Loader, which can be received in the onCreateLoader method in the callback interface object
, or null if not needed.
Callback : callback interface. Called by LoaderManager to report and monitor Loader events.
^Implementation (method in LoaderManager.LoaderCallBacks):

    // 返回一个 Loader 对象.
    // id:Loader 被创建时,用户分配的 Id 标识;LoaderManager.initLoader 参数一。如
    // 果发现已经有相同 ID 的 Loader 就会复用该 Loader,而不会重新创建。
    // args:接收从 LoaderManager.initLoader 传递的参数二。
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    
    
        Log.e(TAG, "onCreateLoader id=" + id);
        //返回一个 Loader。我们先接触 Android 封装好的 CursorLoader。很简单。一句话搞定
        return new CursorLoader(MainActivity.this, Uri.parse("content://sms"), null, null,
                null, null);
    }

    // 如果数据库有数据更新,并且数据加载完毕会调用该方法。(如果用户跳转到其他界面,再回到当当前界面的时候,如果数据库有数据更新,该方法会在 OnResume 之后调用)
    // loader:来自于 onCreateLoader()方法返回值.
    // data:创建的 loader 加载数据的结果.
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    
    
        //替换适配器的游标。
        simpleCursorAdapter.swapCursor(data);
        Log.e(TAG, "onLoadFinished ");
    }


    // 当一个已创建的 Loader 被重置从而使其数据无效时,此方法被调用。
    //当 Activity 或 Fragment 被销毁的时候调用。
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    
    
        simpleCursorAdapter.swapCursor(null);//释放 Cursor 资源
        Log.e(TAG, "onLoaderReset ");
    }

`
^ restartLoader(int id, Bundle args, LoaderCallbacks callbacks)
Use the restartLoader(intid, Bundle args, LoaderManager.LoaderCallbacks callback)
method to update data and initialize one. If there is a Loader with the same id, the Loader will be reused and cleared If there is no data in the original Loader, create a new one. This method is generally used when data needs to be updated. For example, in the following example, when searching for key changes, this method needs to be called to re-query data asynchronously.
The following example uses CursorLoader to query system SMS contacts and SMS content, and displays them in
ListView. A SearchView is placed on the ListView of activity_main to
query contacts based on the name keywords of the contacts.

example

The specific implementation code:

public class MainActivity extends AppCompatActivity {
    
    
    private SearchView searchView;
    private static ContentResolver contentResolver;
    private ListView lv_show;
    private SimpleCursorAdapter simpleCursorAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        searchView = (SearchView) findViewById(R.id.searchView);
        lv_show = (ListView) findViewById(R.id.lv_show);
        simpleCursorAdapter = new SimpleCursorAdapter(this, R.layout.view_list_item, null
                , new String[]{
    
    Telephony.Sms.ADDRESS, Telephony.Sms.BODY}
                , new int[]{
    
    R.id.tv_address, R.id.tv_body},
                SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        lv_show.setAdapter(simpleCursorAdapter);
        //监听 SearchView 的文本查询监听
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    
    
            //文本提交的时候
            @Override
            public boolean onQueryTextSubmit(String query) {
    
    
                return true;//ture 自己处理。false 自己处完成后丢给系统处理
            }

            //文本改变的时候调用
            @Override
            public boolean onQueryTextChange(String newText) {
    
    
                //重新加载 Loader
                Bundle bundle = new Bundle();
                bundle.putString("keyword", newText);
                getLoaderManager().restartLoader(1, bundle, callbacks);
                return true;//ture 自己处理。false 自己处完成后丢给系统处理
            }
        });
        contentResolver = getContentResolver();
        //得到 LoaderManager,初始化 Loader
        getLoaderManager().initLoader(1, null, callbacks);
    }

    private LoaderManager.LoaderCallbacks<Cursor> callbacks = new LoaderManager.LoaderCallbacks<Cursor>() {
    
    
        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    
    
            if (args == null)
                return new CursorLoader(MainActivity.this, Uri.parse("content://sms"), null, null,
                        null, null);
            else {
    
    
                String keyword = args.getString("keyword");
                //包含 keyword 关键字的联系人都查询出来
                return new CursorLoader(MainActivity.this, Uri.parse("content://sms"), null,
                        Telephony.Sms.ADDRESS + " like ?",
                        /
                        new String[]{
    
    "%" + keyword + "%"}
					,null);
            }
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    
    
            //数据更新
            simpleCursorAdapter.swapCursor(data);
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
    
    
            //释放 Cursor 资源
            simpleCursorAdapter.swapCursor(null);
        }
    };
}

Layout code for MainActivity:
activity_main.xml

<?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.let.loader.MainActivity">```

    <SearchView
        android:id="@+id/searchView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#acb5bc"
        android:iconifiedByDefault="true"
        android:queryHint="查询的关键字" />

    <ListView
        android:id="@+id/lv_show"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Item layout code of ListView
view_list_item.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_address"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center" />

    <TextView
        android:id="@+id/tv_body"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center" />
</LinearLayout>	

Let's take a look at the renderings:

AsyncTaskLoader loads local data
1 Comparison between AsyncTaskLoader and CursorLoader
AsyncTaskLoader is an abstract Loader. He uses AsyncTask to offload data loading tasks to other
threads. Almost all useful Loader classes we create are subclasses of AsyncTaskLoader, such as
CursorLoader.
2 Usage of AsyncTaskLoader
Step 1: Create a static inner class to inherit from AsyncTaskLoader. Note: It must be a static inner class.
Step 2: The subclass must rewrite onStartLoading(); and call the forceLoad(); method, indicating that
the data is forced to be loaded. Otherwise the data will not be displayed.
Step 3: Execute the database query in the loadInBackground() method to return a Cursor;
note: a content observer must be registered for the Cursor object here, otherwise the database data changes and the Cursor
data will not be updated.

//cursor.registerContentObserver(mObserver);ForceLoadContentObserver

And this observer (ForceLoadContentObserver) object can only be created in the AsyncTaskLoader subclass construction
method, you can refer to the CursorAdapter packaged in Android...
Afterwards: other uses are similar to CursorLoader.

Guess you like

Origin blog.csdn.net/qq_36162336/article/details/128508234