Android Sample NotePad学习二
为了看起来方便先把NotesList.java的代码贴上来:
public class NotesList extends ListActivity { private static final String TAG = "NotesList"; // Menu item ids public static final int MENU_ITEM_DELETE = Menu.FIRST; public static final int MENU_ITEM_INSERT = Menu.FIRST + 1; /** * The columns we are interested in from the database */ private static final String[] PROJECTION = new String[] { Notes._ID, // 0 Notes.TITLE, // 1 }; /** The index of the title column */ private static final int COLUMN_INDEX_TITLE = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT); // If no data was given in the intent (because we were started // as a MAIN activity), then use our default content provider. Intent intent = getIntent(); if (intent.getData() == null) { intent.setData(Notes.CONTENT_URI); } // Inform the list we provide context menus for items getListView().setOnCreateContextMenuListener(this); // Perform a managed query. The Activity will handle closing and requerying the cursor // when needed. Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null, Notes.DEFAULT_SORT_ORDER); // Used to map notes entries from the database to views SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor, new String[] { Notes.TITLE }, new int[] { android.R.id.text1 }); setListAdapter(adapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); // This is our one standard application action -- inserting a // new note into the list. menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert) .setShortcut('3', 'a') .setIcon(android.R.drawable.ic_menu_add); // Generate any additional actions that can be performed on the // overall list. In a normal install, there are no additional // actions found here, but this allows other applications to extend // our menu with their own actions. Intent intent = new Intent(null, getIntent().getData()); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); /* menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, new ComponentName(this, NotesList.class), null, intent, 0, null);*/ menu.addIntentOptions(Menu.FIRST, 0, 0, new ComponentName(this, NotesList.class), null, intent, 0, null); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); //If getListAdapter.getCount()>0,then return true. final boolean haveItems = getListAdapter().getCount() > 0; // If there are any notes in the list (which implies that one of // them is selected), then we need to generate the actions that // can be performed on the current selection. This will be a combination // of our own specific actions along with any extensions that can be // found. if (haveItems) { // This is the selected item. Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId()); // Build menu... always starts with the EDIT action... Intent[] specifics = new Intent[1]; specifics[0] = new Intent(Intent.ACTION_EDIT, uri); MenuItem[] items = new MenuItem[1]; // ... is followed by whatever other actions are available... Intent intent = new Intent(null, uri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0, items); // Give a shortcut to the edit action. if (items[0] != null) { items[0].setShortcut('1', 'e'); } } else { menu.removeGroup(Menu.CATEGORY_ALTERNATIVE); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ITEM_INSERT: // Launch activity to insert a new item startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData())); return true; } return super.onOptionsItemSelected(item); } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { AdapterView.AdapterContextMenuInfo info; try { info = (AdapterView.AdapterContextMenuInfo) menuInfo; } catch (ClassCastException e) { Log.e(TAG, "bad menuInfo", e); return; } Cursor cursor = (Cursor) getListAdapter().getItem(info.position); if (cursor == null) { // For some reason the requested item isn't available, do nothing return; } // Setup the menu header menu.setHeaderTitle(cursor.getString(COLUMN_INDEX_TITLE)); // Add a menu item to delete the note menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_delete); } @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo info; try { info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); } catch (ClassCastException e) { Log.e(TAG, "bad menuInfo", e); return false; } switch (item.getItemId()) { case MENU_ITEM_DELETE: { // Delete the note that the context menu is for Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id); getContentResolver().delete(noteUri, null, null); return true; } } return false; } @Override protected void onListItemClick(ListView l, View v, int position, long id) { Uri uri = ContentUris.withAppendedId(getIntent().getData(), id); String action = getIntent().getAction(); if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) { // The caller is waiting for us to return a note selected by // the user. The have clicked on one, so return it now. setResult(RESULT_OK, new Intent().setData(uri)); } else { // Launch activity to view/edit the currently selected item startActivity(new Intent(Intent.ACTION_EDIT, uri)); } } }
下面对于之前一些不懂或者是理解模糊或者是有偏差的地方进行学习一下:】
@Override protected void onListItemClick(ListView l, View v, int position, long id) { Uri uri = ContentUris.withAppendedId(getIntent().getData(), id); String action = getIntent().getAction(); if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) { // The caller is waiting for us to return a note selected by // the user. The have clicked on one, so return it now. setResult(RESULT_OK, new Intent().setData(uri)); } else { // Launch activity to view/edit the currently selected item startActivity(new Intent(Intent.ACTION_EDIT, uri)); } }
当我单击"GaoMatrix"条目时,会触发上面的事件,通过设置断点查看这个时候的uri的值:
可以看到这个uri的值是:content://com.google.provider.NotePad/notes/1
之前错误的理解是:startActivity(new Intent(Intent.ACTION_EDIT, uri));,启动一个新的Activity,这个肯定要到AndroidManifest.xml上去查看相应的action是Intent.ACTION_EDIT的Activity。
<provider android:name="NotePadProvider" android:authorities="com.google.provider.NotePad" /> <activity android:name="NotesList" android:label="@string/title_notes_list"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.PICK" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.GET_CONTENT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/vnd.google.note" /> </intent-filter> </activity> <activity android:name="NoteEditor" android:theme="@android:style/Theme.Light" android:label="@string/title_note" android:screenOrientation="sensor" android:configChanges="keyboardHidden|orientation" > <!-- This filter says that we can view or edit the data of a single note --> <intent-filter android:label="@string/resolve_edit"> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> <action android:name="com.android.notepad.action.EDIT_NOTE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/vnd.google.note" /> </intent-filter> <!-- This filter says that we can create a new note inside of a directory of notes. --> <intent-filter> <action android:name="android.intent.action.INSERT" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /> </intent-filter> </activity>
发现只有NoteEditor这个Activity有<action android:name="android.intent.action.EDIT" />,这个肯定不能就被这个Activity截获呀,因为可能系统里面某个Activity也有这个,那肯定还是要根据这个uri进行进一步的适配,可是这个intent-filter下面就一个<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />这个只是说明他可以对什么样的文件类型进行操作,和这个uri的值没有什么关系呀。今天才发现,原来他们之间是有关系的,只不过是要经过中间的一步。
首先这个uri的值是:content://com.google.provider.NotePad/notes/1是个内容提供者,在AndroidManifest.xml里面有:
<provider android:name="NotePadProvider" android:authorities="com.google.provider.NotePad"/>
而这个ContentProvider正好和我们的uri相匹配的,然后通过这个内容提供者的public String getType(Uri uri)返回操作的类型:
static { sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES); sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID); sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES); sNotesProjectionMap = new HashMap<String, String>(); sNotesProjectionMap.put(Notes._ID, Notes._ID); sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE); sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE); sNotesProjectionMap.put(Notes.CREATED_DATE, Notes.CREATED_DATE); sNotesProjectionMap.put(Notes.MODIFIED_DATE, Notes.MODIFIED_DATE); // Support for Live Folders. sLiveFolderProjectionMap = new HashMap<String, String>(); sLiveFolderProjectionMap.put(LiveFolders._ID, Notes._ID + " AS " + LiveFolders._ID); sLiveFolderProjectionMap.put(LiveFolders.NAME, Notes.TITLE + " AS " + LiveFolders.NAME); // Add more columns here for more robust Live Folders. } @Override public String getType(Uri uri) { switch (sUriMatcher.match(uri)) { case NOTES: case LIVE_FOLDER_NOTES: return Notes.CONTENT_TYPE; case NOTE_ID: return Notes.CONTENT_ITEM_TYPE; default: throw new IllegalArgumentException("Unknown URI " + uri); } }
而根据返回的type正好和上面所说的那个action里面的<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
相对应,这就解释了,为什么会调用这个Activity。