Loader简介

        以下所述内容参考自:http://developer.android.com/guide/components/loaders.html

        为了在ActivityFragment中更方便的异步加载数据,从Android 3.0版本(API Level 11)开始引入LoaderLoader的特点有:每个ActivityFragment都可以使用Loader;它提供的是异步加载数据的方式;它监听数据源的改变并在数据内容改变时分发新的数据结果;在某个配置改变后Loader被重新创建时,会自动重新连接到最近使用过的Loader的游标处,因此就不需要重新查询加载数据。

在应用程序中使用Loader时,有一些类和接口通常会使用到,主要有以下:

LoaderManager是与某个特定的ActivityFragment关联的抽象类,可以管理一个或多个Loader实例。它的作用是在ActivityFragment的生命周期过程中辅助应用程序完成一些需要长时间运行的操作。它最通常的是与一个CursorLoader实例结合使用,但也可以使用自定义的Loader类实例来加载其他相应类型的数据。

LoaderManager.LoaderCallbacksLoaderManager交互的一个回调接口,例如可以在其回调函数onCreateLoader()创建一个新的Loader实例。

Loader执行异步加载数据的抽象类,通常使用的是它的子类CursorLoader,但也可以使用自定义的Loader子类。当Loader处于活动状态时,应该监听相应数据源的改变并在数据内容改变时分发新的数据结果。

AsyncTaskLoader使用一个AsyncTask来执行操作的抽象Loader类。

CursorLoaderAsyncTaskLoader的一个子类,因此使用了一个后台线程来异步加载数据。主要用于加载ContentProvider中的数据,并与查询返回的Cursor对象相关联。相比在ActivityFragment中直接使用其他API函数来加载数据,它由于使用了后台线程来执行这些操作,不会阻塞UI线程,因此是加载ContentProvider数据的最佳方式。

        应用程序中使用Loader加载数据通常包括以下内容:一个ActivityFragment;一个LoaderManager;一个CursorLoader用于加载ContentProvider中的数据,当然也可以通过自己创建的一个Loader类的子类或AsyncTaskLoader类的子类来加载其他类型的数据;实现LoaderManager.LoaderCallbacks接口,在这个接口中创建并管理Loader对象;显示出Loader加载的数据内容,例如可以使用SimpleCursorAdapter来显示;要加载的数据源,例如在使用CursorLoader时的数据源是一个ContentProvider

通常在ActivityonCreate()函数或FragmentonActivityCreated()函数中初始化Loader对象实例,使用语句:getLoaderManager().initLoader(0, null, this);  initLoader()函数的第一个参数是一个标识Loader对象的ID,这个语句中用的ID0;第二个参数是一个可选参数,第三个参数是一个实现了LoaderManager.LoaderCallbacks接口的对象,由于在相应ActivityFragment中实现了这个接口,所以这个语句用的参数是thisinitLoader()执行后,Loader对象就初始化完成了并处于活动状态,且有两种可能的结果:如果第一个参数中使用的ID号正与其他已创建的Loader对象关联,那么就直接使用那个已创建的Loader对象;如果ID号没有被其他Loader使用,就触发LoaderManager.LoaderCallbacks接口中的onCreateLoader()函数,在这个函数中需要实现创建并返回新的Loader对象的代码。在这两种结果中,第一种不会调用onCreateLoader()函数而第二种会调用,但紧接着当数据加载完成后,无论两者中的哪种情况,都会调用LoaderManager.LoaderCallbacks接口中的onLoadFinished()函数。onCreateLoader()函数中返回的Loader对象不需要直接去引用,LoaderManager会自动管理这个Loader对象并维护它相关联的数据。

        如果需要丢弃Loader中加载的数据并重新加载,例如一个号码快速查询程序,输入号码内容改变时,查询出的结果也应该立即更新,就需要重新加载数据,在这种情况下就可以使用语句getLoaderManager().restartLoader(0, null, this);  来重新开始加载新的数据,执行此语句后,LoaderManager.LoaderCallbacks接口中的onCreateLoader()onLoadFinished()函数也会依次被调用。

        在上面提到的onLoadFinished()函数,其功能主要是将Loader加载的Cursor对象数据保存下来,例如在用一个SimpleCursorAdapter对象保存Cursor数据时使用以下代码:

SimpleCursorAdapter mAdapter

. . .

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

    // Swap the new cursor in.  (The framework will take care of closing the

    // old cursor once we return.)

    mAdapter.swapCursor(data);

}

swapCursor()函数的功能即将data数据绑定到mAdapter中,执行此函数后,如果之前绑定过旧的data数据,则旧的data数据会自动回收掉。LoaderManager.LoaderCallbacks接口中还有一个回调函数onLoaderReset(),当ActivityFragmentDestroyed后会调用此函数(如果只是被Stopped则不会调用此函数),因此可以在此函数中回收释放Loader加载的Cursor对象,如下代码所示:

public void onLoaderReset(Loader<Cursor> loader) {

    // This is called when the last Cursor provided to onLoadFinished()

    // above is about to be closed.  We need to make sure we are no

    // longer using it.

    mAdapter.swapCursor(null);

}

这里在swapCursor()函数中传入参数null,即将mAdapter绑定到null,之前使用过的数据即会被系统自动回收释放了。

      下面通过一个例子演示Loader的使用,程序的功能是显示出手机上的联系人姓名及号码,当在搜索框中输入搜索的联系人姓名或号码的部分内容后,显示出与内容相匹配的联系人,下面列出程序主要文件内容,包括manifest文件和源代码文件(没有使用布局文件),共2个文件:

\AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.study.loader"

    android:versionCode="1"

    android:versionName="1.0" >

    <uses-sdk

        android:minSdkVersion="11"

        android:targetSdkVersion="15" />

    <!-- 要读取联系人数据,需要加入以下权限声明 -->

         <uses-permission android:name="android.permission.READ_CONTACTS"/>

    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:label="@string/title_activity_main" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

</manifest>

 

\src\com\study\loader\MainActivity.java:

package com.study.loader;

 

import android.net.Uri;

import android.os.Bundle;

import android.provider.ContactsContract.CommonDataKinds;

import android.provider.ContactsContract.Contacts;

import android.app.Activity;

import android.app.FragmentManager;

import android.app.ListFragment;

import android.content.CursorLoader;

import android.content.Loader;

import android.database.Cursor;

import android.text.TextUtils;

import android.util.Log;

import android.view.Menu;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.view.View;

import android.widget.LinearLayout;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.SearchView;

import android.widget.SearchView.OnQueryTextListener;

import android.widget.SimpleCursorAdapter;

import android.app.LoaderManager;

 

public class MainActivity extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        FragmentManager fm = getFragmentManager();

        // Create the list fragment and add it as our sole content.

        if (fm.findFragmentById(android.R.id.content) == null) {

            CursorLoaderListFragment list = new CursorLoaderListFragment();

            fm.beginTransaction().add(android.R.id.content, list).commit();

        }

    }

 

    public static class CursorLoaderListFragment extends ListFragment

             implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {

                   // This is the Adapter being used to display the list's data.

                   SimpleCursorAdapter mAdapter;

 

                   // If non-null, this is the current filter the user has provided.

                   String mCurFilter;

 

                   @Override

                   public void onActivityCreated(Bundle savedInstanceState) {

                       super.onActivityCreated(savedInstanceState);

 

                       // Give some text to display if there is no data.  In a real

                       // application this would come from a resource.

                       setEmptyText("No phone numbers");

               

                       // We have a menu item to show in action bar.

                       setHasOptionsMenu(true);

 

                       // Create an empty adapter we will use to display the loaded data.

                       mAdapter = new SimpleCursorAdapter(getActivity(),

                               android.R.layout.simple_list_item_2, null,

                               new String[] { CommonDataKinds.Phone.DISPLAY_NAME, CommonDataKinds.Phone.NUMBER },

                               new int[] { android.R.id.text1, android.R.id.text2 }, 0);

                       setListAdapter(mAdapter);

 

                       // Prepare the loader.  Either re-connect with an existing one,

                       // or start a new one.

                       getLoaderManager().initLoader(0, null, this);

                   }

 

                   @Override

                   public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

                       // Place an action bar item for searching.

                       MenuItem item = menu.add("Search");

                       item.setIcon(android.R.drawable.ic_menu_search);

                       item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

                       SearchView sv = new SearchView(getActivity());

                       sv.setOnQueryTextListener(this);

                       item.setActionView(sv);

                   }

 

                   public boolean onQueryTextChange(String newText) {

                       // Called when the action bar search text has changed.  Update

                       // the search filter, and restart the loader to do a new query

                       // with this filter.

                       mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;

                       getLoaderManager().restartLoader(0, null, this);

                       return true;

                   }

 

                   public boolean onQueryTextSubmit(String query) {

                       // Don't care about this.

                       return true;

                   }

 

                   @Override public void onListItemClick(ListView l, View v, int position, long id) {

                       // Insert desired behavior here.

                       Log.i("FragmentComplexList", "Item clicked: " + id);

                   }

 

                   // These are the Contacts rows that we will retrieve.

                   static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {

                            CommonDataKinds.Phone._ID,

                            CommonDataKinds.Phone.DISPLAY_NAME,

                            CommonDataKinds.Phone.NUMBER,

                   };

 

                   public Loader<Cursor> onCreateLoader(int id, Bundle args) {

                       // This is called when a new Loader needs to be created.  This

                       // sample only has one Loader, so we don't care about the ID.

                       // First, pick the base URI to use depending on whether we are

                       // currently filtering.

                            Uri baseUri;

                       if (mCurFilter != null) {

                           baseUri = Uri.withAppendedPath(CommonDataKinds.Phone.CONTENT_FILTER_URI,

                                   Uri.encode(mCurFilter));

                       } else {

                           baseUri = CommonDataKinds.Phone.CONTENT_URI;

                       }

 

                       // Now create and return a CursorLoader that will take care of

                       // creating a Cursor for the data being displayed.

                       String select = "((" + CommonDataKinds.Phone.DISPLAY_NAME + " NOTNULL) AND ("

                               + CommonDataKinds.Phone.HAS_PHONE_NUMBER + "=1) AND ("

                               + CommonDataKinds.Phone.DISPLAY_NAME + " != '' ))";

                       return new CursorLoader(getActivity(), baseUri,

                               CONTACTS_SUMMARY_PROJECTION, select, null,

                               CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC");

                   }

                  

                   public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

                       // Swap the new cursor in.  (The framework will take care of closing the

                       // old cursor once we return.)

                       mAdapter.swapCursor(data);

                   }

                  

                   public void onLoaderReset(Loader<Cursor> loader) {

                       // This is called when the last Cursor provided to onLoadFinished()

                       // above is about to be closed.  We need to make sure we are no

                       // longer using it.

                       mAdapter.swapCursor(null);

                   }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值