加載器: Android 3.0 中引入了加載器草戈,支持輕松在Activity或者片段中異步加載數(shù)據(jù)。
加載器的特征:
- 可用于每個 Activity和 Fragment炕婶。
- 支持異步加載數(shù)據(jù)姐赡。
- 監(jiān)控其數(shù)據(jù)源并在內(nèi)容變化時傳遞新的結(jié)果。
- 在某一配置更改后重建加載器時柠掂,會自動重新連接上一個加載器的游標项滑。 因此,它們無需重新查詢其數(shù)據(jù)涯贞。
好了枪狂,加載器的基本介紹就到這里,下面是本文的參考博客和資料鏈接宋渔。
下面就以兩個例子的代碼對加載器來進行說明州疾。
例子一,用listView顯示通話記錄皇拣。其主要源碼代參考博客,具體移步去參考严蓖。這里我就直接貼代碼了。
activity的布局文件:
<RelativeLayout 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"
tools:context=".MainActivity" >
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="學習加載其的使用" />
<Button
android:id="@+id/btn_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_text"
android:text="所有通話記錄" />
<Button
android:id="@+id/btn_incoming"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_text"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/btn_all"
android:text="撥入記錄" />
<Button
android:id="@+id/btn_outcoming"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/btn_all"
android:layout_marginTop="10dp"
android:text="播出記錄" />
<Button
android:id="@+id/btn_missed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/btn_incoming"
android:layout_below="@id/btn_all"
android:layout_marginTop="10dp"
android:layout_toRightOf="@id/btn_outcoming"
android:text="未接記錄" />
<Button
android:layout_below="@id/btn_all"
android:layout_toRightOf="@id/btn_missed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="nextView"
android:text="簡單版示例"/>
<View
android:id="@+id/line_layout"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="@id/btn_missed"
android:background="#000000" >
</View>
<ListView
android:id="@+id/lv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/line_layout"
android:clipToPadding="false"
android:divider="#ff553311"
android:dividerHeight="2dp"
android:fadingEdge="none"
android:paddingTop="10dp" />
</RelativeLayout>
listView的子布局文件,item_load.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/bt_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="#00000000"
android:contentDescription="yi"
android:src="@drawable/ic_playlist_play_black_24dp" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="2dp"
android:layout_toRightOf="@id/bt_icon"
android:textSize="23sp" />
<TextView
android:id="@+id/tv_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/tv_name"
android:layout_below="@id/tv_name"
android:layout_marginBottom="2dp"
android:textColor="#7f7f7f"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/tv_number"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/tv_number"
android:ellipsize="end"
android:textColor="#7f7f7f"
android:textSize="16sp" />
<ImageButton
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="#00000000"
android:contentDescription="er"
android:focusableInTouchMode="false"
android:src="@drawable/ic_delete_forever_black_24dp" />
<ImageButton
android:id="@+id/btn_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:layout_toLeftOf="@id/btn_delete"
android:background="#00000000"
android:contentDescription="san"
android:focusableInTouchMode="false"
android:src="@mipmap/ic_launcher" />
</RelativeLayout>
activity的源代碼:
package reoger.hut.openfiretest.activty;
import android.Manifest;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.CallLog;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import reoger.hut.openfiretest.R;
public class TestLoaderActivity extends AppCompatActivity implements View.OnClickListener {
private static final String[] CALLLOG_PROJECTION = new String[]{
CallLog.Calls._ID, CallLog.Calls.NUMBER, CallLog.Calls.CACHED_NAME,
CallLog.Calls.TYPE, CallLog.Calls.DATE};
private ListView mListView;
private MyCursorAdapter mAdapter;
private MyLoaderListener mLoader = new MyLoaderListener();
private static final int ALL = 0; // 默認顯示所有
private static final int INCOMING = CallLog.Calls.INCOMING_TYPE; // 來電
private static final int OUTCOMING = CallLog.Calls.OUTGOING_TYPE; // 拔號
private static final int MISSED = CallLog.Calls.MISSED_TYPE; // 未接
private int mCallLogShowType = ALL;
private boolean m_FinishLoaderFlag = false; // 第一次加載完成
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_loader);
initWidgets();
getLoaderManager().initLoader(0, null, mLoader);
}
private void initWidgets() {
mListView = (ListView) findViewById(R.id.lv_list);
Button btn = (Button) findViewById(R.id.btn_all);
btn.setOnClickListener(this);
btn = (Button) findViewById(R.id.btn_incoming);
btn.setOnClickListener(this);
btn = (Button) findViewById(R.id.btn_outcoming);
btn.setOnClickListener(this);
btn = (Button) findViewById(R.id.btn_missed);
btn.setOnClickListener(this);
mAdapter = new MyCursorAdapter(TestLoaderActivity.this, null);
mListView.setAdapter(mAdapter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_all:
allCalllog();
break;
case R.id.btn_incoming:
incomingCalllog();
break;
case R.id.btn_outcoming:
outcomingCalllog();
break;
case R.id.btn_missed:
missedCalllog();
break;
default:
break;
}
}
private void missedCalllog() {
mCallLogShowType = MISSED;
String selection = CallLog.Calls.TYPE + "=?";
String[] selectionArgs = new String[]{"3"};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
Cursor missedCursor = getContentResolver().query(
CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION, selection,
selectionArgs, CallLog.Calls.DEFAULT_SORT_ORDER);
mAdapter.swapCursor(missedCursor);
}
private void allCalllog() {
mCallLogShowType = ALL;
String selection = null;
String[] selectionArgs = null;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
Cursor allCursor = getContentResolver().query(
CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION, selection,
selectionArgs, CallLog.Calls.DEFAULT_SORT_ORDER);
mAdapter.swapCursor(allCursor);
}
private void incomingCalllog() {
mCallLogShowType = INCOMING;
String selection = CallLog.Calls.TYPE + "=?";
String[] selectionArgs = new String[]{"1"};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
Cursor incomingCursor = getContentResolver().query(
CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION, selection,
selectionArgs, CallLog.Calls.DEFAULT_SORT_ORDER);
mAdapter.swapCursor(incomingCursor);
}
private void outcomingCalllog() {
mCallLogShowType = OUTCOMING;
String selection = CallLog.Calls.TYPE + "=?";
String[] selectionArgs = new String[]{"2"};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
Cursor outcomingCursor = getContentResolver().query(
CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION, selection,
selectionArgs, CallLog.Calls.DEFAULT_SORT_ORDER);
mAdapter.swapCursor(outcomingCursor);
}
private class MyLoaderListener implements android.app.LoaderManager.LoaderCallbacks<Cursor> {
@Override
public android.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
m_FinishLoaderFlag = false;
CursorLoader cursor = new CursorLoader(TestLoaderActivity.this,
CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION, null, null,
CallLog.Calls.DEFAULT_SORT_ORDER);
return cursor;
}
@Override
public void onLoadFinished(android.content.Loader<Cursor> loader, Cursor data) {
if (data == null)
return;
Cursor tempData = data;
if (tempData.getCount() == 0) {
mAdapter.swapCursor(null);
return;
}
if (m_FinishLoaderFlag) {
tempData = null;
String selection = null;
String[] selectionArgs = null;
if (mCallLogShowType == INCOMING) {
selection = CallLog.Calls.TYPE + "=?";
selectionArgs = new String[]{"1"};
} else if (mCallLogShowType == OUTCOMING) {
selection = CallLog.Calls.TYPE + "=?";
selectionArgs = new String[]{"2"};
} else if (mCallLogShowType == MISSED) {
selection = CallLog.Calls.TYPE + "=?";
selectionArgs = new String[]{"3"};
}
if (ActivityCompat.checkSelfPermission(TestLoaderActivity.this, Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
tempData = getContentResolver().query(
CallLog.Calls.CONTENT_URI, CALLLOG_PROJECTION,
selection, selectionArgs,
CallLog.Calls.DEFAULT_SORT_ORDER);
}
mAdapter.swapCursor(tempData);
m_FinishLoaderFlag = true;
}
@Override
public void onLoaderReset(android.content.Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
public void nextView(View view){
startActivity(new Intent(TestLoaderActivity.this,NextActivity.class));
}
}
最后是適配器的代碼:
package reoger.hut.openfiretest.activty;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Date;
import reoger.hut.openfiretest.R;
import static android.content.ContentValues.TAG;
/**
* Created by 24540 on 2017/6/2.
*
*/
public class MyCursorAdapter extends CursorAdapter {
private final Context mContext;
public MyCursorAdapter(Context context, Cursor c) {
this(context, c, true);
}
public MyCursorAdapter(Context context, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);
mContext = context;
}
public MyCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
mContext = context;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
return inflater.inflate(R.layout.item_load, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (cursor == null)
return;
final String id = cursor.getString(0);
String number = cursor.getString(1);
String name = cursor.getString(2);
int type = cursor.getInt(3);
String date = cursor.getString(4);
ImageView TypeView = (ImageView) view.findViewById(R.id.bt_icon);
TextView nameCtrl = (TextView) view.findViewById(R.id.tv_name);
if (name == null) {
nameCtrl.setText(mContext.getString(R.string.name_unknown));
} else {
nameCtrl.setText(name);
}
TextView numberCtrl = (TextView) view.findViewById(R.id.tv_number);
numberCtrl.setText(number);
String value = ComputeDate(date);
TextView dateCtrl = (TextView) view.findViewById(R.id.tv_date);
dateCtrl.setText(value);
switch (type) {
case CallLog.Calls.INCOMING_TYPE:
TypeView.setImageResource(R.drawable.ic_playlist_play_black_24dp);
break;
case CallLog.Calls.OUTGOING_TYPE:
TypeView.setImageResource(R.drawable.chatright);
break;
case CallLog.Calls.MISSED_TYPE:
TypeView.setImageResource(R.drawable.ic_delete_forever_black_24dp);
break;
case 4: // CallLog.Calls.VOICEMAIL_TYPE
break;
default:
break;
}
ImageButton dailBtn = (ImageButton) view.findViewById(R.id.btn_call);
dailBtn.setTag(number);
dailBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Intent.ACTION_CALL_PRIVILEGED 由于Intent中隱藏了谈飒,只能用字符串代替
Intent intent = new Intent(Intent.ACTION_CALL, Uri.fromParts(
"tel", (String) v.getTag(), null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
mContext.startActivity(intent);
}
});
ImageButton deleteBtn = (ImageButton) view
.findViewById(R.id.btn_delete);
deleteBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// 根據(jù)ID進行記錄刪除
String where = CallLog.Calls._ID + "=?";
String[] selectionArgs = new String[]{id};
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
return;
}
int result = mContext.getContentResolver().delete(
CallLog.Calls.CONTENT_URI, where, selectionArgs);
Log.d(TAG, "11result = " + result);
}
});
}
private String ComputeDate(String date) {
long callTime = Long.parseLong(date);
long newTime = new Date().getTime();
long duration = (newTime - callTime) / (1000 * 60);
String value;
// SimpleDateFormat sfd = new
// SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
// Locale.getDefault());
// String time = sfd.format(callTime);
// Log.d(TAG, "[MyCursorAdapter--ComputeDate] time = " + time);
// 進行判斷撥打電話的距離現(xiàn)在的時間岂座,然后進行顯示說明
value=duration + "分鐘前";
// if (duration < 60) {
// value = duration + "分鐘前";
// } else if (duration >= 60 && duration < MainActivity.DAY) {
// SimpleDateFormat sdf = new SimpleDateFormat("HH:mm",
// Locale.getDefault());
// value = sdf.format(new Date(callTime));
//
// // value = (duration / 60) + "小時前";
// } else if (duration >= MainActivity.DAY
// && duration < MainActivity.DAY * 2) {
// value = "昨天";
// } else if (duration >= MainActivity.DAY * 2
// && duration < MainActivity.DAY * 3) {
// value = "前天";
// } else if (duration >= MainActivity.DAY * 7) {
// SimpleDateFormat sdf = new SimpleDateFormat("MM/dd",
// Locale.getDefault());
// value = sdf.format(new Date(callTime));
// } else {
// value = (duration / MainActivity.DAY) + "天前";
// }
return value;
}
}
最后程序運行的截圖類似于這種:
Paste_Image.png
這里我直接copy原作者的運行截圖。
要注意的一點就是杭措,當寫繼承LoaderCallback的時候费什,不要倒錯包了,導入的包是android.app.Load......的那個手素。如圖鸳址;
Paste_Image.png
示例代碼二,這里我只是將手機通訊錄里的名字顯示到了listView中泉懦。代碼如下:
public class NextActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
private ListView mList;
private final static int REQUEST_READ_CONTACTS = 0;
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.CONTACT_STATUS,
ContactsContract.Contacts.CONTACT_PRESENCE,
ContactsContract.Contacts.PHOTO_ID,
ContactsContract.Contacts.LOOKUP_KEY,
};
// If non-null, this is the current filter the user has provided.
String mCurFilter;
SimpleCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, null,
new String[] { ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.CONTACT_STATUS },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
mList = (ListView) findViewById(R.id.listView);
mList.setAdapter(mAdapter);
}
private void populateAutoComplete() {
if(!mayRequestContacts()){
return;
}
getLoaderManager().initLoader(0,null,this);
}
/**
* 獲取聯(lián)系人列表的權(quán)限
* @return
*/
private boolean mayRequestContacts() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
return true;
}
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
Snackbar.make(mList, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener() {
@Override
@TargetApi(Build.VERSION_CODES.M)
public void onClick(View v) {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
});
} else {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
return false;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if(requestCode == REQUEST_READ_CONTACTS){
if(grantResults.length == 1 && grantResults[0] ==PackageManager.PERMISSION_GRANTED){
populateAutoComplete();
}
}
}
public void showContent(View view){
populateAutoComplete();
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = ContactsContract.Contacts.CONTENT_URI;
}
String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.Contacts.DISPLAY_NAME + " != '' ))";
CursorLoader cursorLoader = new CursorLoader(this,baseUri,CONTACTS_SUMMARY_PROJECTION,select,null, ContactsContract.Contacts.DISPLAY_NAME+" COLLATE LOCALIZED ASC");
return cursorLoader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
if(loader!=null)
mAdapter.swapCursor(null);
}
}
對應的布局文件為:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="reoger.hut.openfiretest.activty.NextActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="showContent"
android:text="查看聯(lián)系人"/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
最后顯示的效果為:
device-2017-06-03-195754.png
如果對上面的字段是不很了解稿黍,這里也給出參考資料官方文檔,或者中文的會更加簡單一點,那就試試這個崩哩。
最后巡球,如果對Loader還有什么不懂的,強烈推薦看官方api指南邓嘹。