前幾天研究了下SDK中提供的NotePad例子,從這個例子中能夠看到activity之間使用intent跳轉的機制,而當時沒看明白URI到底是怎麼個東西。今天在看《ProAndroid》時,從作者那得到啟發,終於明白URI是什麼了。
以這個NotePad為例,
在NotePad.java中有如下兩個定義:
public static final String AUTHORITY = "com.google.provider.NotePad";
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/notes");
引用作者原話:
Actually, the URI, or the authority portion of the URI, is configured in the AndroidManifest.xml file as a content provider:
<provider android:name="NotePadProvider"
android:authorities="com.google.provider.NotePad"/>
When Android sees a URI that needs to be resolved, it pulls out the authority portion of it and looks up the ContentProvider class configured for the authority.In the Notepad application, the AndroidManifest.xml file contains a class called NotePadProvider configured for the com.google.provider.NotePad authority.
作者的意思是當android要處理和一個URI相關的操作時,android架構會根據URI中的authority內容,在AndroidManifest.xml <provider>(一個或多個)中尋找擁有相同authority內容的provider,將二者對應起來。在NotePad這個例子中定義了 CONTENT_URI 和NotePadProvider這個類有對應關係。
我設定了幾個斷點,並實際調試了下來驗證下面這段代碼中managedQuery() 的URI參數在傳遞過程中,最終是交給NotePadProvider類中的query()方法處理的!! ^ ^
//NotesList.java
public class NotesList extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
Intent intent = getIntent();
if (intent.getData() == null) {
intent.setData(Notes.CONTENT_URI);//這裡設定好了intent要處理的URI
}
getListView().setOnCreateContextMenuListener(this);
//managedQuery()第一個參數即為上面設定的URI,我想要在這裡跟蹤進去
Cursor cursor = managedQuery(getIntent().getData(),PROJECTION, null, null,Notes.DEFAULT_SORT_ORDER);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.noteslist_item, cursor, new String[] { Notes.TITLE },
new int[] { android.R.id.text1 });
setListAdapter(adapter);
}
}
程式跑起來,跟蹤進managedQuery(),會跳到
ContentResolver.class的
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
IContentProvider provider = acquireProvider(uri);//這裡是關鍵,ContentResolver的query,會根據URI獲得provider!
if (provider == null) {
return null;
}
try {
Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);//傳說中的反向調用!
if(qCursor == null) {
releaseProvider(provider);
return null;
}
//Wrap the cursor object into CursorWrapperInner object
return new CursorWrapperInner(qCursor, provider);
}
..
}
程式繼續運行,如果在NotePadProvider.java中的query中設定斷點,你會發現程式在斷點處停住。
這就證明了 android架構根據URI中的authority找到對應的provider,由provider根據完整的URI內容再詳細處理,比如去更新資料庫某一條記錄。