从API18开始,在Contact表中,新加了CONTACT_LAST_UPDATED_TIMESTAMP列,
* 表示该contact被更新的时间。
* 这个demo就演示了如何通过读取该列的值,获取某个时间段内对contact所做的修改。
* 在本例中使用了LoaderManager,前面我们已经学习了这个类,今天我们再来加深一下理解:
* LoaderManager用来负责管理与Activity或者Fragment联系起来的一个或多个Loaders对象。
* 每个Activity或者Fragment都有唯一的一个LoaderManager实例,用来启动、停止、保持、重启、
* 关闭它的Loaders。这些事件有时直接在客户端通过调用
* initLoader()/restartLoader()/destroyLoader()函数来实现。
* 那么,LoaderManager是如何实现对Loader的管理的呢?是通过LoaderCallBacks接口来实现的。
* 实现这个接口就要实现三个方法:ononCreateLoader()用于创建loader,onLoadFinished用于
* 在loader加载完毕时执行某些操作。onLoaderReset(),用于设置在loader重置时执行的一些操作。
activity_main.xml
<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"
android:padding="5dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:id="@+id/update"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:id="@+id/delete"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/display_result" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/listView"></ListView>
</LinearLayout>
MainActivity
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {
private static final int ID_DELETE_LOADER = 2;
private static final int ID_UPDATE_LOADER = 1;
private static final String PREF_KEY_CHANGE = "timestamp_changed";
private static final String PREF_KEY_DELETE = "timestamp_delete";
private static final String CLASS = "MainActivity";
private TextView mDisplayResult;
private ListView mList;
private LoaderManager mLM;
// 定义listView的适配器
private ChangeAdapter mAdapter;
private DeleteAdapter mDeleteAdapter;
private long msearchTime;
private Button update;
private Button delete;
/*
* 定义一个广播接收者用于处理当接收到创建联系人数据库时的操作。
* 当我们在设置-应用-联系人存储当中点击清除数据时,会将联系人的数据库清除
* 此时我们点击任意一个按钮都会先创建数据库
*/
private BroadcastReceiver mReceive=new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(MainActivity.this, "数据库被创建了!", 0).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLM = getLoaderManager();
mAdapter = new ChangeAdapter(this, null, 0);
mDeleteAdapter = new DeleteAdapter(this,null,0);
mDisplayResult = (TextView) findViewById(R.id.display_result);
mList = (ListView) findViewById(R.id.listView);
update = (Button) findViewById(R.id.update);
delete = (Button) findViewById(R.id.delete);
update.setText("Change Since" + getLastTimeStamp(PREF_KEY_CHANGE, 0));
delete.setText("Delete Since" + getLastTimeStamp(PREF_KEY_DELETE, 0));
update.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
updateClick();
}
});
delete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
deleteClick();
}
});
}
@Override
protected void onResume() {
super.onResume();
IntentFilter filter=new IntentFilter();
filter.addAction(ContactsContract.Intents.CONTACTS_DATABASE_CREATED);
registerReceiver(mReceive, filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceive);
}
protected void deleteClick() {
// 首先清空适配器中的数据
mDeleteAdapter.swapCursor(null);
// 移除updateLoader,因为我们在对该按钮的点击事件的处理过程中与updateLoader无关
mLM.destroyLoader(ID_UPDATE_LOADER);
// 重新启动updateLoader,让Activity实现LoaderCallBacks接口
mLM.restartLoader(ID_DELETE_LOADER, null, this);
}
/*
* 点击按钮时查询一定时间段内对contact所作的修改操作
*/
protected void updateClick() {
// 首先清空适配器中的数据
mAdapter.swapCursor(null);
// 移除deleteLoader,因为我们在对该按钮的点击事件的处理过程中与deleteLoader无关
mLM.destroyLoader(ID_DELETE_LOADER);
// 重新启动updateLoader,让Activity实现LoaderCallBacks接口
mLM.restartLoader(ID_UPDATE_LOADER, null, this);
}
// 根据Id获取相应的Loader实例
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case ID_UPDATE_LOADER:
return getUpdateLoader();
case ID_DELETE_LOADER:
return getDeleteLoader();
}
return null;
}
private Loader<Cursor> getUpdateLoader() {
// 定义要查询的列
String[] projection = new String[] { ContactsContract.Data._ID,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP };
msearchTime = getLastTimeStamp(PREF_KEY_CHANGE, 0);
// 设置查询条件,以从sharedpreferences当中取出的时间作为开始时间,数据表中最近一次
// 修改contact的时间作为结束时间,查询这段时间内对contact修改的记录。
String selection = ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP
+ " > ?";
// 定义查询的参数(代替?通配符)
String[] bindArgs = new String[] { msearchTime + "" };
return new CursorLoader(this, ContactsContract.Data.CONTENT_URI,
projection, selection, bindArgs,
ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP
+ " desc, " + ContactsContract.Data.CONTACT_ID
+ " desc");
}
private long getLastTimeStamp(String key, long time) {
SharedPreferences pref = getSharedPreferences(CLASS,
Context.MODE_PRIVATE);
return pref.getLong(key, time);
}
private Loader<Cursor> getDeleteLoader() {
String[] projection = new String[] {
ContactsContract.DeletedContacts.CONTACT_ID,
ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP };
msearchTime = getLastTimeStamp(PREF_KEY_DELETE, 0);
// 设置查询条件,以从sharedpreferences当中取出的时间作为开始时间,数据表中最近一次
// 修改contact的时间作为结束时间,查询这段时间内对contact修改的记录。
String selection = ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP
+ " > ?";
// 定义查询的参数(代替?通配符)
String[] bindArgs = new String[] { msearchTime + "" };
return new CursorLoader(this,
ContactsContract.DeletedContacts.CONTENT_URI, projection,
selection, bindArgs,
ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP
+ " desc");
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
long timeStamp = 0;
switch (loader.getId()) {
case ID_UPDATE_LOADER:
// 为textView设置文本
mDisplayResult.setText(data.getCount() + "Change(s) Since"
+ msearchTime);
// 设置适配器
mAdapter.swapCursor(data);
mList.setAdapter(mAdapter);
// 如果查询的结果集不为空,则取出第一条记录,即为最近一次修改的记录,因为我们设置了按降序排序
if (data.moveToNext()) {
timeStamp = data
.getLong(data
.getColumnIndex(ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP));
data.moveToPrevious();
}
if (timeStamp > 0) {
// 将该时间保存到sharepreferences当中
saveLastTimeStamp(PREF_KEY_CHANGE, timeStamp);
// 设置按钮的文本
update.setText("Changed Since" + timeStamp);
}
break;
case ID_DELETE_LOADER:
// 为textView设置文本
mDisplayResult.setText(data.getCount() + "Delete(s) Since"
+ msearchTime);
// 设置适配器
mDeleteAdapter.swapCursor(new DeleteCursorWrapper(data));
mList.setAdapter(mAdapter);
// 如果查询的结果集不为空,则取出第一条记录,即为最近一次修改的记录,因为我们设置了按降序排序
if (data.moveToNext()) {
timeStamp = data
.getLong(data
.getColumnIndex(ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP));
data.moveToPrevious();
}
if (timeStamp > 0) {
// 将该时间保存到sharepreferences当中
saveLastTimeStamp(PREF_KEY_DELETE, timeStamp);
// 设置按钮的文本
delete.setText("Delete Since" + timeStamp);
}
break;
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
switch (loader.getId()) {
case ID_UPDATE_LOADER:
mAdapter.swapCursor(null);
break;
case ID_DELETE_LOADER:
mDeleteAdapter.swapCursor(null);
break;
}
}
private void saveLastTimeStamp(String key, long time) {
SharedPreferences pref = getSharedPreferences(CLASS,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putLong(PREF_KEY_CHANGE, time);
editor.commit();
}
//CursorWrapper只是简单实现了Cursor接口,是直接对Cursor接口的包装而没有干其他事情
//方便我们实现某些方法实现功能的扩展
private class DeleteCursorWrapper extends CursorWrapper{
public DeleteCursorWrapper(Cursor cursor) {
super(cursor);
}
@Override
public int getColumnIndexOrThrow(String columnName)
throws IllegalArgumentException {
//如果发现不是ContactsContract.DeletedContacts.CONTACT_ID,则转化过来
if(columnName.equals("_id")){
return super.getColumnIndex(ContactsContract.DeletedContacts.CONTACT_ID);
}
return super.getColumnIndexOrThrow(columnName);
}
}
private class ChangeAdapter extends CursorAdapter {
public ChangeAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
// 创建并设置UI界面
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LinearLayout item = new LinearLayout(context);
item.addView(buildTextView(context));
item.addView(buildTextView(context));
item.addView(buildTextView(context));
return item;
}
// 为界面中的组件绑定数据
@Override
public void bindView(View view, Context context, Cursor cursor) {
LinearLayout item = (LinearLayout) view;
String id = cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.CONTACT_ID));
String name = cursor.getString(cursor
.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
String timeStamp = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Data.CONTACT_LAST_UPDATED_TIMESTAMP));
setText(item.getChildAt(0), id);
setText(item.getChildAt(1), name);
setText(item.getChildAt(2), timeStamp);
}
}
private class DeleteAdapter extends CursorAdapter {
public DeleteAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
// 创建并设置UI界面
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LinearLayout item = new LinearLayout(context);
item.addView(buildTextView(context));
item.addView(buildTextView(context));
return item;
}
// 为界面中的组件绑定数据
@Override
public void bindView(View view, Context context, Cursor cursor) {
LinearLayout item = (LinearLayout) view;
String id = cursor.getString(cursor
.getColumnIndex(ContactsContract.DeletedContacts.CONTACT_ID));
String timeStamp = cursor
.getString(cursor
.getColumnIndex(ContactsContract.DeletedContacts.CONTACT_DELETED_TIMESTAMP));
setText(item.getChildAt(0), id);
setText(item.getChildAt(2), timeStamp);
}
}
public void setText(View view, String text) {
TextView tv = (TextView) view;
tv.setText(text);
}
public View buildTextView(Context context) {
TextView view = new TextView(context);
view.setPadding(3, 3, 3, 3);
return view;
}
}