引言
上篇我們介紹了Intents和Intent Filters的理論部分,主要是介紹了:activities、services、broadcast receivers三種組件的Intent機制兩種Intent(顯式和隱式)及它們如何去匹配目的組件、Intent對象包含哪些信息、Intent Filters的action & category & data。
Intent的重要性,我不再着重介紹了,但我還是要說:Intent能夠使應用程序突破沙盒與外界交流,者這使得Android的世界變得豐富多彩!本篇將用實例來介紹,如何應用Intent,而且繼續用SMS方面的例子來闡述。本文的主要內容如下:
- 例子(需求)描述
- STEP1、添加用於顯示通訊錄的佈局文件
- STEP2、添加Button的點擊事件
- STEP3、添加通訊錄活動
- STEP4、解析通訊錄返回的數據
- STEP5、在清單文件AndroidManifest.xml中註冊通訊錄活動和讀取Contact數據庫的權限
- 總結
例子(需求)描述
用手機發過SMS的人都知道:
- 用戶可以先編輯短信,然後再去通訊錄中選擇相應的人併發生給他。
- 用戶可以在短信內容中插入通訊錄中聯繫人的號碼。
我們的這個例子就是要說明如何實現這個功能。要實現這個功能,即是創建一個新的Activity選擇(ACTION_PICK)通訊錄中的數據,它會顯示通訊錄中的所有聯繫人並讓用戶選擇,然後關閉並返回一個聯繫人的URI給短信程序。下面介紹如何一步一步實現類似的功能,而且是在之前Android 開發之旅:短信的收發及在android模擬器之間實踐(一)中發送SMS的例子(TextMessage)基礎上加上從通訊錄中選擇聯繫人的功能。
STEP1、添加用於顯示通訊錄的佈局文件
我們用一個ListView來顯示整個通訊錄,其中用TextView顯示每一記錄。它們的xml文件分別爲contact.xml、listitemlayout,如下所示:
- ====================================contact.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <ListView android:id="@+id/contactListView"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
- =================================== listitemlayout
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView android:id="@+id/itemTextView" android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:padding="10px"
- android:textSize="16px" android:textColor="#FFF" />
- </LinearLayout>
爲了能夠打開通訊錄,我們還需要在TextMessage程序中加入一個Button btnContact,通過點擊btnContact激活顯示通訊錄的活動。這隻需在main.xml文件中加入如下代碼:
- <Button android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:text="@string/btnContact"
- android:id="@+id/btnContact" />
記得還有在values/strings.xml中相應的加入<string name="btnContact">contact</string>。
STEP2、添加Button的點擊事件
在上面準備工作做完之後,我們需要監聽btnContact的點擊事件,當用戶點擊btnContact時,跳轉顯示通訊錄界面,當用戶選擇一個聯繫人之後,返回SMS程序的主界面。這裏就要用到了偉大的Intent啦!
- btnContact = (Button) findViewById(R.id.btnContact);
- btnContact.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent(Intent.ACTION_PICK,
- ContactsContract.Contacts.CONTENT_URI);
- startActivityForResult(intent, PICK_CONTACT);
- }
- });
STEP3、添加通訊錄活動
添加一個類文件,類名爲ContactPick(表示通訊錄活動名)繼承Activity。它的主要功能就是獲取從SMS主程序傳遞來的Intent並提取數據;然後去查詢通訊錄數據庫,取出數據並填充到STEP1中定義的ListView;最後,還需要添加當用戶選擇一個聯繫人的事件onItemClick,將結果返回給SMS主程序,這裏也用到了我們偉大的Intent啦!代碼如下:
- package skynet.com.cnblogs.www;
- import android.app.Activity;
- import android.content.Intent;
- import android.database.Cursor;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.ContactsContract;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.ListView;
- import android.widget.SimpleCursorAdapter;
- import android.widget.AdapterView.OnItemClickListener;
- public class ContactPick extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Intent orgIntent=getIntent();
- Uri queryUri=orgIntent.getData();
- final Cursor c = managedQuery(queryUri,
- null,
- null,
- null,
- null);
- String[] fromColumns=new String[]{ContactsContract.Contacts.DISPLAY_NAME};
- int[] toLayoutIDs = new int[] { R.id.itemTextView };
- SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
- R.layout.listitemlayout, c, fromColumns, toLayoutIDs);
- ListView lv = (ListView) findViewById(R.id.contactListView);
- lv.setAdapter(adapter);
- lv.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int pos,
- long id) {
- c.moveToPosition(pos);
- int rowId = c.getInt(c.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
- Uri outURI = Uri.parse(ContactsContract.Contacts.CONTENT_URI.toString() + rowId);
- Intent outData = new Intent();
- outData.setData(outURI);
- setResult(Activity.RESULT_OK,outData);
- finish();
- }
- });
- }
- }
STEP4、解析通訊錄返回的數據
從通訊錄活動返回之後,我們從返回的Intent中提取數據並填充到填寫電話號碼的EditView中。代碼主要如下:
- @Override
- public void onActivityResult(int reqCode, int resCode, Intent data) {
- super.onActivityResult(reqCode, resCode, data);
- switch (reqCode) {
- case (PICK_CONTACT): {
- if (resCode == Activity.RESULT_OK) {
- String name;
- Uri contactData = data.getData();
- Cursor c = managedQuery(contactData, null, null, null, null);
- c.moveToFirst();
- name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
- TextView tv;
- tv = (TextView)findViewById(R.id.edtPhoneNo);
- tv.setText(name);
- }
- break;
- }
- }
- }
STEP5、在清單文件AndroidManifest.xml中註冊通訊錄活動和讀取Contact數據庫的權限
主要工作基本做完了,現在我們只需要註冊通訊錄活動和讀取Contact數據的權限了。完整的清單文件代碼如下:
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="skynet.com.cnblogs.www" android:versionCode="1"
- android:versionName="1.0">
- <application>
- <activity android:name=".TextMessage" android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".ContactPick" android:label="@string/app_name">
- <action android:name="android.intent.action.PICK" />
- <category android:name="android.intent.category.DEFAULT" />
- </activity>
- </application>
- <uses-permission android:name="android.permission.SEND_SMS" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- </manifest>
注意通訊錄活動的Intent Filters,它的action是android.intent.action.PICK;category是android.intent.category.DEFAULT。現在我們分析一下這個Intent Filter:
- <action android:name="android.intent.action.PICK" />:使用戶能夠可以在通訊錄列表中選擇一個,然後將選擇的聯繫人的 URL返回給調用者。
- <category android:name="android.intent.category.DEFAULT" />:這是默認的category,如果不知道category系統會自動加上。這個屬性是讓使其能夠被像Context.startActivity()等找到。要說明的的是,如果列舉了多個category,這個活動僅會去處理那些Intent中都包含了所有列舉的category的組件。
我們還可以在清單文件中看到TextMessage活動的Intent Filter:
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
它指TextMessage活動定是真個程序的入口並且TextMessage會列舉在Launcher即啓動列表中。
程序運行結果如下圖所示:
圖1、主界面
圖2、點擊contact按鈕之後
圖3、選擇一個聯繫人之後
總結
我們用發短信中選擇聯繫人的例子說明Intent和Intent Filter,這裏體現了兩個活動之間如何通過Intent和Intent Filter來交互,這也是我們在編寫Android應用程序的時候經常遇到了。本文除了上述的主要內容之外,還涉及別的知識點,下面列舉幾個個人認爲比較有用的知識點:
-
Cursor類它跟我們平時用的數據庫中的遊標類似,它提供了對從數據庫返回的結果的隨機讀寫操作。如我們例子中用到的,通過managedQuery方法 查詢數據庫並返回結果,然後利用Cursor對它進行操作。下面介紹Cursor類的幾個方法(我們例子中用到的,更多的方法請自行查閱相關資料):
- public abstract int getColumnIndexOrThrow (String columnName):返回給定列名的索引(注意:從0開始的),或者當列名不存在時拋出llegalArgumentException異常;
- public abstract boolean moveToFirst ():移動到第一行。如果Cursor爲空,則返回FALSE
- public abstract boolean moveToPosition (int position):將遊標移動到一個指定的位置,它的範圍在-1 <= position <= count。如果position位置不可達,返回FALSE
- managedQuery方法:根據指定的URI路徑信息返回包含特定數據的Cursor對象,應用這個方法可以使Activity接管返回數據對象的生命週期。參數:
URI: Content Provider 需要返回的資源索引
Projection: 用於標識有哪些columns需要包含在返回數據中
Selection: 作爲查詢符合條件的過濾參數,類似於SQL語句中Where之後的條件判斷
SelectionArgs: 同上
SortOrder: 用於對返回信息進行排序 - SimpleCursorAdapter允許你綁定一個遊標的列到ListView上,並使用自定義的layout顯示每個項目。SimpleCursorAdapter的創建,需要傳入當前的上下文、一個layout資源,一個遊標和兩個數組:一個包含使用的列的名字,另一個(相同大小)數組包含View中的資源ID,用於顯示相應列的數據值。
本系列的其它文章:
- Android 開發之旅:環境搭建及HelloWorld
- Android 開發之旅:HelloWorld項目的目錄結構
- Android 開發之旅:android架構
- Android 開發之旅:應用程序基礎及組件
- Android 開發之旅:應用程序基礎及組件(續)
- Android 開發之旅:活動與任務
- Android 開發之旅:進程與線程
- Android 開發之旅:組件生命週期(一)
- Android 開發之旅:組件生命週期(二)
- Android 開發之旅:組件生命週期(三)
- Android 開發之旅:又見Hello World!
- Android 開發之旅:深入分析佈局文件&又是"Hello World!"
- Android 開發之旅:view的幾種佈局方式及實踐
- Android 開發之旅:短信的收發及在android模擬器之間實踐(一)
- Android 開發之旅:短信的收發及在android模擬器之間實踐(二)
- Android開發之旅: Intents和Intent Filters(理論部分)