Android開發之旅: Intents和Intent Filters(實例部分)

引言

上篇我們介紹了Intents和Intent Filters的理論部分,主要是介紹了:activitiesservicesbroadcast receivers三種組件的Intent機制兩種Intent(顯式和隱式)及它們如何去匹配目的組件、Intent對象包含哪些信息、Intent Filters的action & category & data。

Intent的重要性,我不再着重介紹了,但我還是要說:Intent能夠使應用程序突破沙盒與外界交流,者這使得Android的世界變得豐富多彩!本篇將用實例來介紹,如何應用Intent,而且繼續用SMS方面的例子來闡述。本文的主要內容如下:

  1. 例子(需求)描述
  2. STEP1、添加用於顯示通訊錄的佈局文件
  3. STEP2、添加Button的點擊事件
  4. STEP3、添加通訊錄活動
  5. STEP4、解析通訊錄返回的數據
  6. STEP5、在清單文件AndroidManifest.xml中註冊通訊錄活動和讀取Contact數據庫的權限
  7. 總結

例子(需求)描述

用手機發過SMS的人都知道:

  1. 用戶可以先編輯短信,然後再去通訊錄中選擇相應的人併發生給他。
  2. 用戶可以在短信內容中插入通訊錄中聯繫人的號碼。

我們的這個例子就是要說明如何實現這個功能。要實現這個功能,即是創建一個新的Activity選擇(ACTION_PICK)通訊錄中的數據,它會顯示通訊錄中的所有聯繫人並讓用戶選擇,然後關閉並返回一個聯繫人的URI給短信程序。下面介紹如何一步一步實現類似的功能,而且是在之前Android 開發之旅:短信的收發及在android模擬器之間實踐(一)中發送SMS的例子(TextMessage)基礎上加上從通訊錄中選擇聯繫人的功能。

STEP1、添加用於顯示通訊錄的佈局文件

我們用一個ListView來顯示整個通訊錄,其中用TextView顯示每一記錄。它們的xml文件分別爲contact.xml、listitemlayout,如下所示:

  1. ====================================contact.xml   
  2.  
  3. <?xml version="1.0" encoding="utf-8"?>   
  4.  
  5. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  6.  
  7. android:orientation="vertical"   
  8.  
  9. android:layout_width="fill_parent"   
  10.  
  11. android:layout_height="fill_parent"   
  12.  
  13. >   
  14.  
  15. <ListView android:id="@+id/contactListView"   
  16.  
  17.     android:layout_width="fill_parent"   
  18.  
  19.     android:layout_height="wrap_content"   
  20.  
  21.     />   
  22.  
  23. </LinearLayout>   
  24.  
  25. =================================== listitemlayout   
  26.  
  27. <?xml version="1.0" encoding="utf-8"?>   
  28.  
  29. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  30.  
  31.     android:orientation="vertical" android:layout_width="fill_parent"   
  32.  
  33.     android:layout_height="fill_parent">   
  34.  
  35.     <TextView android:id="@+id/itemTextView" android:layout_width="wrap_content"   
  36.  
  37.     android:layout_height="wrap_content" android:padding="10px"   
  38.  
  39.     android:textSize="16px" android:textColor="#FFF" />   
  40.  
  41. </LinearLayout>  

爲了能夠打開通訊錄,我們還需要在TextMessage程序中加入一個Button btnContact,通過點擊btnContact激活顯示通訊錄的活動。這隻需在main.xml文件中加入如下代碼:

  1. <Button android:layout_width="wrap_content"   
  2.  
  3.         android:layout_height="wrap_content" android:text="@string/btnContact"   
  4.  
  5.    
  6.  
  7.         android:id="@+id/btnContact"                            /> 

記得還有在values/strings.xml中相應的加入<string name="btnContact">contact</string>

STEP2、添加Button的點擊事件

在上面準備工作做完之後,我們需要監聽btnContact的點擊事件,當用戶點擊btnContact時,跳轉顯示通訊錄界面,當用戶選擇一個聯繫人之後,返回SMS程序的主界面。這裏就要用到了偉大的Intent啦

  1. btnContact = (Button) findViewById(R.id.btnContact);   
  2.  
  3. btnContact.setOnClickListener(new View.OnClickListener() {   
  4.  
  5.     @Override   
  6.  
  7.     public void onClick(View v) {   
  8.  
  9.         // TODO Auto-generated method stub   
  10.  
  11.         Intent intent = new Intent(Intent.ACTION_PICK,   
  12.  
  13.                 ContactsContract.Contacts.CONTENT_URI);   
  14.  
  15.         startActivityForResult(intent, PICK_CONTACT);   
  16.  
  17.     }   
  18.  
  19.    
  20.  
  21. });  

STEP3、添加通訊錄活動

添加一個類文件,類名爲ContactPick(表示通訊錄活動名)繼承Activity。它的主要功能就是獲取從SMS主程序傳遞來的Intent並提取數據;然後去查詢通訊錄數據庫,取出數據並填充到STEP1中定義的ListView;最後,還需要添加當用戶選擇一個聯繫人的事件onItemClick,將結果返回給SMS主程序,這裏也用到了我們偉大的Intent!代碼如下:

  1. package skynet.com.cnblogs.www;   
  2.  
  3.    
  4.  
  5. import android.app.Activity;   
  6.  
  7. import android.content.Intent;   
  8.  
  9. import android.database.Cursor;   
  10.  
  11. import android.net.Uri;   
  12.  
  13. import android.os.Bundle;   
  14.  
  15. import android.provider.ContactsContract;   
  16.  
  17. import android.view.View;   
  18.  
  19. import android.widget.AdapterView;   
  20.  
  21. import android.widget.ListView;   
  22.  
  23. import android.widget.SimpleCursorAdapter;   
  24.  
  25. import android.widget.AdapterView.OnItemClickListener;   
  26.  
  27.    
  28.  
  29. public class ContactPick extends Activity {   
  30.  
  31.     /** Called when the activity is first created. */   
  32.  
  33.     @Override   
  34.  
  35.     public void onCreate(Bundle savedInstanceState) {   
  36.  
  37.         super.onCreate(savedInstanceState);   
  38.  
  39.         setContentView(R.layout.main);   
  40.  
  41.    
  42.  
  43.         Intent orgIntent=getIntent();   
  44.  
  45.         Uri queryUri=orgIntent.getData();           
  46.  
  47.         final Cursor c = managedQuery(queryUri,   
  48.  
  49.                 null,   
  50.  
  51.                 null,   
  52.  
  53.                 null,   
  54.  
  55.                 null);   
  56.  
  57.            
  58.  
  59.         String[] fromColumns=new String[]{ContactsContract.Contacts.DISPLAY_NAME};   
  60.  
  61.         int[] toLayoutIDs = new int[] { R.id.itemTextView };   
  62.  
  63.         SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,   
  64.  
  65.                 R.layout.listitemlayout, c, fromColumns, toLayoutIDs);   
  66.  
  67.         ListView lv = (ListView) findViewById(R.id.contactListView);   
  68.  
  69.         lv.setAdapter(adapter);   
  70.  
  71.         lv.setOnItemClickListener(new OnItemClickListener() {   
  72.  
  73.             @Override   
  74.  
  75.             public void onItemClick(AdapterView<?> parent, View view, int pos,   
  76.  
  77.                     long id) {   
  78.  
  79.                 c.moveToPosition(pos);       
  80.  
  81.                 int rowId = c.getInt(c.getColumnIndexOrThrow(ContactsContract.Contacts._ID));   
  82.  
  83.                 Uri outURI = Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + rowId);   
  84.  
  85.                 Intent outData = new Intent();   
  86.  
  87.                 outData.setData(outURI);   
  88.  
  89.                 setResult(Activity.RESULT_OK,outData);   
  90.  
  91.                 finish();   
  92.  
  93.             }   
  94.  
  95.         });   
  96.  
  97.     }   
  98.  
  99. }  

STEP4、解析通訊錄返回的數據

從通訊錄活動返回之後,我們從返回的Intent中提取數據並填充到填寫電話號碼的EditView中。代碼主要如下:

  1. @Override   
  2.  
  3. public void onActivityResult(int reqCode, int resCode, Intent data) {   
  4.  
  5.     super.onActivityResult(reqCode, resCode, data);   
  6.  
  7.    
  8.  
  9.     switch (reqCode) {   
  10.  
  11.     case (PICK_CONTACT): {   
  12.  
  13.         if (resCode == Activity.RESULT_OK) {   
  14.  
  15.             String name;                   
  16.  
  17.             Uri contactData = data.getData();   
  18.  
  19.             Cursor c = managedQuery(contactData, nullnullnullnull);   
  20.  
  21.             c.moveToFirst();   
  22.  
  23.             name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));   
  24.  
  25.             TextView tv;   
  26.  
  27.             tv = (TextView)findViewById(R.id.edtPhoneNo);   
  28.  
  29.             tv.setText(name);   
  30.  
  31.         }   
  32.  
  33.         break;   
  34.  
  35.     }   
  36.  
  37.     }   
  38.  
  39. }  

STEP5、在清單文件AndroidManifest.xml中註冊通訊錄活動和讀取Contact數據庫的權限

主要工作基本做完了,現在我們只需要註冊通訊錄活動和讀取Contact數據的權限了。完整的清單文件代碼如下:

  1. <?xml version="1.0" encoding="utf-8"?>   
  2.  
  3. <manifest xmlns:android="http://schemas.android.com/apk/res/android"   
  4.  
  5.     package="skynet.com.cnblogs.www" android:versionCode="1"   
  6.  
  7.     android:versionName="1.0">   
  8.  
  9.     <application>   
  10.  
  11.         <activity android:name=".TextMessage" android:label="@string/app_name">   
  12.  
  13.             <intent-filter>   
  14.  
  15.                 <action android:name="android.intent.action.MAIN" />   
  16.  
  17.                 <category android:name="android.intent.category.LAUNCHER" />   
  18.  
  19.             </intent-filter>   
  20.  
  21.         </activity>   
  22.  
  23.         <activity android:name=".ContactPick" android:label="@string/app_name">   
  24.  
  25.             <action android:name="android.intent.action.PICK" />   
  26.  
  27.             <category android:name="android.intent.category.DEFAULT" />   
  28.  
  29.         </activity>   
  30.  
  31.     </application>   
  32.  
  33.     <uses-permission android:name="android.permission.SEND_SMS" />   
  34.  
  35.     <uses-permission android:name="android.permission.READ_CONTACTS" />   
  36.  
  37. </manifest>  

注意通訊錄活動的Intent Filters,它的actionandroid.intent.action.PICKcategoryandroid.intent.category.DEFAULT。現在我們分析一下這個Intent Filter:

  1. <action android:name="android.intent.action.PICK" />使用戶能夠可以在通訊錄列表中選擇一個,然後將選擇的聯繫人的 URL返回給調用者。
  2. <category android:name="android.intent.category.DEFAULT" />這是默認的category,如果不知道category系統會自動加上。這個屬性是讓使其能夠被像Context.startActivity()等找到。要說明的的是,如果列舉了多個category,這個活動僅會去處理那些Intent中都包含了所有列舉的category的組件。

我們還可以在清單文件中看到TextMessage活動的Intent Filter:

  1. <intent-filter>   
  2.  
  3.     <action android:name="android.intent.action.MAIN" />   
  4.  
  5.     <category android:name="android.intent.category.LAUNCHER" />   
  6.  
  7. </intent-filter>  

它指TextMessage活動定是真個程序的入口並且TextMessage會列舉在Launcher即啓動列表中。

程序運行結果如下圖所示:

Intents和Intent Filters(實例部分)

圖1、主界面

Intents和Intent Filters(實例部分)

圖2、點擊contact按鈕之後

Intents和Intent Filters(實例部分)

圖3、選擇一個聯繫人之後

總結

我們用發短信中選擇聯繫人的例子說明Intent和Intent Filter,這裏體現了兩個活動之間如何通過Intent和Intent Filter來交互,這也是我們在編寫Android應用程序的時候經常遇到了。本文除了上述的主要內容之外,還涉及別的知識點,下面列舉幾個個人認爲比較有用的知識點:

  1. Cursor類它跟我們平時用的數據庫中的遊標類似,它提供了對從數據庫返回的結果的隨機讀寫操作。如我們例子中用到的,通過managedQuery方法 查詢數據庫並返回結果,然後利用Cursor對它進行操作。下面介紹Cursor類的幾個方法(我們例子中用到的,更多的方法請自行查閱相關資料):
    1. public abstract int getColumnIndexOrThrow (String columnName):返回給定列名的索引(注意:從0開始的),或者當列名不存在時拋出llegalArgumentException異常;
    2. public abstract boolean moveToFirst ():移動到第一行。如果Cursor爲空,則返回FALSE
    3. public abstract boolean moveToPosition (int position):將遊標移動到一個指定的位置,它的範圍在-1 <= position <= count。如果position位置不可達,返回FALSE
  2. managedQuery方法:根據指定的URI路徑信息返回包含特定數據的Cursor對象,應用這個方法可以使Activity接管返回數據對象的生命週期。參數:
    URI: Content Provider 需要返回的資源索引
    Projection: 用於標識有哪些columns需要包含在返回數據中
    Selection: 作爲查詢符合條件的過濾參數,類似於SQL語句中Where之後的條件判斷
    SelectionArgs: 同上
    SortOrder: 用於對返回信息進行排序
  3. SimpleCursorAdapter允許你綁定一個遊標的列到ListView上,並使用自定義的layout顯示每個項目。SimpleCursorAdapter的創建,需要傳入當前的上下文、一個layout資源,一個遊標和兩個數組:一個包含使用的列的名字,另一個(相同大小)數組包含View中的資源ID,用於顯示相應列的數據值。

本系列的其它文章:

  1. Android 開發之旅:環境搭建及HelloWorld
  2. Android 開發之旅:HelloWorld項目的目錄結構
  3. Android 開發之旅:android架構
  4. Android 開發之旅:應用程序基礎及組件
  5. Android 開發之旅:應用程序基礎及組件(續)
  6. Android 開發之旅:活動與任務
  7. Android 開發之旅:進程與線程
  8. Android 開發之旅:組件生命週期(一)
  9. Android 開發之旅:組件生命週期(二)
  10. Android 開發之旅:組件生命週期(三)
  11. Android 開發之旅:又見Hello World!
  12. Android 開發之旅:深入分析佈局文件&又是"Hello World!"
  13. Android 開發之旅:view的幾種佈局方式及實踐
  14. Android 開發之旅:短信的收發及在android模擬器之間實踐(一)
  15. Android 開發之旅:短信的收發及在android模擬器之間實踐(二)
  16. Android開發之旅: Intents和Intent Filters(理論部分)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章