android簡訊小程式之CursorAdapter繫結ListView
阿新 • • 發佈:2018-11-08
同步查詢繫結:
mListView = findViewById(R.id.id_containers); //定義uri mALL_conversation_uri = Telephony.Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build(); //定義projection //查詢要返回的欄位 default_all_threads_projection = new String[]{ Telephony.Threads._ID, Telephony.Threads.DATE, Telephony.Threads.SNIPPET, Telephony.Threads.MESSAGE_COUNT, Telephony.Threads.RECIPIENT_IDS, Telephony.Threads.SNIPPET, Telephony.Threads.SNIPPET_CHARSET, Telephony.Threads.READ, Telephony.Threads.ERROR, Telephony.Threads.HAS_ATTACHMENT, Telephony.Threads.RECIPIENT_IDS }; //限制條件 mSelection = "_id IN (SELECT DISTINCT thread_id FROM sms where "+ "thread_id NOT NULL UNION SELECT DISTINCT thread_id FROM pdu where "+ "thread_id NOT NULL )"; Cursor query = getContentResolver().query(mALL_conversation_uri, default_all_threads_projection, mSelection, null, null); mListView.setAdapter(new MyAdapter(MainActivity.this,query));
MyAdaper:
class MyAdapter extends CursorAdapter { private Context mContext; private final LayoutInflater layoutInflater; public MyAdapter(Context context, Cursor c) { super(context, c); mContext = context; layoutInflater = LayoutInflater.from(mContext); } public MyAdapter(Context context, Cursor c, boolean autoRequery, Context mContext, LayoutInflater layoutInflater) { super(context, c, autoRequery); this.mContext = mContext; this.layoutInflater = layoutInflater; } public MyAdapter(Context context, Cursor c, int flags, Context mContext, LayoutInflater layoutInflater) { super(context, c, flags); this.mContext = mContext; this.layoutInflater = layoutInflater; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = layoutInflater.inflate(R.layout.test_item, parent, false); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { TextView mContent = view.findViewById(R.id.txt_content); String string = cursor.getString(cursor.getColumnIndex(Telephony.Threads.SNIPPET)); mContent.setText(string); } }
上面這種方法容易報錯ANR,故慎用!!
非同步查詢繫結:
MainActivity:
//開始查詢簡訊 public void startQuery(){ conversationsQuery = new ConversationQuery(getContentResolver()); conversationsQuery.startQuery(QueryParameter.ALL_CONVERSATION_QUERY_TOKEN,null,QueryParameter.QUERY_ALL_URI,QueryParameter.QUERY_PROJECTION,QueryParameter.QUERY_SELECTION,null,null); }
//處理增刪改查 class ConversationQuery extends AsyncQueryHandler{ public ConversationQuery(ContentResolver cr) { super(cr); } /*** * * @param token 身份證 * @param cookie * @param cursor 遊標 查詢返回的內容 */ @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { super.onQueryComplete(token, cookie, cursor); if (cursor != null && cursor.getCount() > 0){ //cursor 開始的時候在-1 需要將其移動到第一個下標 if (cursor.moveToFirst()){ /** * 從原始碼中可以看出呼叫此方法後會把當前的mCursor置為新傳過來的cursor把原來的cursor返回去並關掉 作用:當我們的Cursor變化時呼叫此方法 adapter.changeCursor(cursor),它的功能類似於adapter.notifyDataSetChanged()方法 */ myAdapter.changeCursor(cursor); } }else{ Toast.makeText(MainActivity.this,R.string.cursor_null,Toast.LENGTH_SHORT).show(); } } }
MyAdaper:
/** * Created by XX on 2018/4/30. */ class MyAdapter extends CursorAdapter { private Context mContext; private LayoutInflater layoutInflater; /** * * @param context 上下文 * @param c 遊標 cursor * @param autoRequery true時 資料庫更新將自動重新整理listView */ public MyAdapter(Context context, Cursor c, boolean autoRequery) { super(context, c, autoRequery); this.mContext = context; this.layoutInflater = LayoutInflater.from(mContext); } public MyAdapter(Context context, Cursor c, int flags) { super(context, c, flags); this.mContext = context; this.layoutInflater = LayoutInflater.from(mContext); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = layoutInflater.inflate(R.layout.test_item, parent, false); return view; } /*** * instanceof: java裡面的二元運算子, * 判斷左邊的物件是否是右邊類的例項。假如是的話,返回true;假如不是的話,返回false。 */ @Override public void bindView(View view, Context context, Cursor cursor) { ConversationItem conversationItem = null; if (view instanceof ConversationItem){ conversationItem = (ConversationItem) view; } if (conversationItem != null){ ConversationBean conversationBean = new ConversationBean(cursor); conversationItem.bindValues(conversationBean); } } }
ConversationItem:
/** * Created by Chauncy_Tan on 2018/5/10. * * ConversationItem 繼承了LinearLayout 沒錯我們的list item整個佈局的最外層就是一個LinearLayout * 為了更好地賦值我們將使用我們這個自定義的LinearLayout */ public class ConversationItem extends LinearLayout { private TextView mContent; public ConversationItem(Context context) { super(context); } public ConversationItem(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public ConversationItem(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onFinishInflate() { super.onFinishInflate(); mContent = findViewById(R.id.txt_content); } //用於繫結為控制元件賦值 public void bindValues(ConversationBean conversationBean){ mContent.setText(conversationBean.getmContent()); } }
ConversationBean:
/** * Created by XX on 2018/5/10. */ public class ConversationBean { public ConversationBean(Cursor cursor) { if (cursor != null){ String snippet = cursor.getString(cursor.getColumnIndex(Telephony.Threads.SNIPPET)); setmContent(snippet); } } private String mContent; public String getmContent() { return mContent; } public void setmContent(String mContent) { this.mContent = mContent; } }
ListView的每一個Item佈局檔案:
<com.example.test.ConversationItem 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="56dp"> <TextView android:id="@+id/txt_content" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:lines="1" android:text="TextView" /> </com.example.test.ConversationItem>
AsyncQueryHandler內部實現
AsyncQueryHandler類封裝了呼叫者執行緒與工作執行緒的互動過程。互動的主體是兩個Handler,一個執行在呼叫者執行緒中,一個執行在工作者執行緒中。通過提供onXXXComplete的回撥介面,實現事件的完成處理。
剛剛接觸query()以及startQuery()時對它的引數我是一臉懵逼,其實這些引數是能夠拼接成一個完整的SQL語句
startQuery()
token:就好比人的身份證,startQuery()可以多次呼叫返回多個結果,用token來區分
cookie:你想傳給onXXXComplete方法使用的一個物件。(暫時我還沒用到一直是null)
uri:你可以理解為從哪一個表查(from xxxtable)
projection:你查詢需要返回的欄位,null代表 *
selection:你的查詢條件
selectionArgs:查詢引數
orderBy:排序條件
@param token A token passed into {@link #onQueryComplete} to identify * the query. * @param cookie An object that gets passed into {@link #onQueryComplete} * @param uri The URI, using the content:// scheme, for the content to * retrieve. * @param projection A list of which columns to return. Passing null will * return all columns, which is discouraged to prevent reading data * from storage that isn't going to be used. * @param selection A filter declaring which rows to return, formatted as an * SQL WHERE clause (excluding the WHERE itself). Passing null will * return all rows for the given URI. * @param selectionArgs You may include ?s in selection, which will be * replaced by the values from selectionArgs, in the order that they * appear in the selection. The values will be bound as Strings. * @param orderBy How to order the rows, formatted as an SQL ORDER BY * clause (excluding the ORDER BY itself). Passing null will use the * default sort order, which may be unordered.
query()
query沒有token以及Cookie引數沒有token因為它是同步的,cookie我還在瞭解
@param uri The URI, using the content:// scheme, for the content to * retrieve. * @param projection A list of which columns to return. Passing null will * return all columns, which is inefficient. * @param selection A filter declaring which rows to return, formatted as an * SQL WHERE clause (excluding the WHERE itself). Passing null will * return all rows for the given URI. * @param selectionArgs You may include ?s in selection, which will be * replaced by the values from selectionArgs, in the order that they * appear in the selection. The values will be bound as Strings. * @param sortOrder How to order the rows, formatted as an SQL ORDER BY * clause (excluding the ORDER BY itself). Passing null will use the * default sort order, which may be unordered.