Pro Android學習筆記(三)——Intent
阿新 • • 發佈:2018-12-31
Intent
簡介
Android中使用Intent來呼叫元件,Android中的元件包括Activity,Service,Broadcast Receiver,Content Provider。Android將多種理念融入到了Intent的概念中。可以使用Intent從一個應用程式中呼叫外部應用程式,可以使用Intent從應用程式呼叫內部或者外部元件,可以使用Intent觸發時間,可以使用Intent發出警報等等。由上述可知,intent是具有相關資料負載的操作。
簡單來說,Intent是你可以告訴Android要執行(或呼叫)的一種操作。Android呼叫的操作取決於該操作所註冊的內容。
例如,編寫一個Activity:BasicViewActivity
public class BasicViewActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basic_view);
}
}
basic_view佈局指向了/res/layout/目錄下的佈局檔案。我們可以在應用程式的描述檔案中註冊此活動,使其可以被其他應用程式呼叫。
註冊程式碼如下:
<activity android:name=".BasicViewActivity" android:label="Basic View Tests" > <intent-filter> <action android:name="com.zxn.intent.action.ShowBasicView" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
註冊之後我們就可以使用Intent來呼叫此BasciViewActivity
public static void invokeBasicActivity(Activity activity) {
String actionName = "com.zxn.intent.action.ShowBasicView";
Intent intent = new Intent(actionName);
activity.startActivity(intent);
}
Android中可用的Intent
以上是我們使用Intent啟動另外一個元件的過程,也是最基本的用法。我們也可以使用Intent啟動Android一些自帶的程式。例如:
public class IntentsUtils {
// 使用瀏覽器開啟一個uri
public static void invokeWebBrowser(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
activity.startActivity(intent);
}
public static void invokeWebSearch(Activity activity) {
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.setData(Uri.parse("http://www.baidu.com"));
activity.startActivity(intent);
}
// 開啟撥號介面
public static void dial(Activity activity) {
Intent intent = new Intent(Intent.ACTION_DIAL);
activity.startActivity(intent);
}
// 撥打一個電話
public static void call(Activity activity) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:904-905-5646"));
activity.startActivity(intent);
}
// 使用一個地圖程式開啟指定位置
public static void showMapAtLatLong(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:0,0?z=4&q=business+near+city"));
activity.startActivity(intent);
}
// 啟動某個應用獲取返回的資料
public static void invokePick(Activity activity) {
Intent pickIntent = new Intent(Intent.ACTION_PICK);
pickIntent.setData(Uri.parse("content://com.google.provider.NotePad/notes"));
activity.startActivityForResult(pickIntent, 1);
}
// 啟動某個應用程式獲取返回的資料
public static void invokeGetContent(Activity activity) {
Intent pickIntent = new Intent(Intent.ACTION_GET_CONTENT);
pickIntent.setType("vnd.android.cursor.item/vnd.google.note");
activity.startActivityForResult(pickIntent, 2);
}
}
建立一個簡單的選單,以便我們呼叫上面這些程式碼。如下:
public class MainActivity extends ActionBarActivity {
private final static String tag = "MainActivity";
// Initialize this in onCreateOptions
Menu myMenu = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setupButton();
this.setupEditText();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
super.onCreateOptionsMenu(menu);
this.myMenu = menu;
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
try {
handleMenus(item);
} catch (Throwable t) {
Log.d(tag, t.getMessage(), t);
throw new RuntimeException("error", t);
}
return true;
}
private void handleMenus(MenuItem item) {
this.appendMenuItemText(item);
if(item.getItemId() == R.id.menu_clear) {
this.emptyText();
} else if(item.getItemId() == R.id.menu_basic_view) {
IntentsUtils.invokeBasicActivity(this);
} else if(item.getItemId() == R.id.menu_show_browser) {
IntentsUtils.invokeWebBrowser(this);
} else if(item.getItemId() == R.id.menu_dial) {
IntentsUtils.dial(this);
} else if(item.getItemId() == R.id.menu_call) {
IntentsUtils.call(this);
} else if(item.getItemId() == R.id.menu_map) {
IntentsUtils.showMapAtLatLong(this);
} else if(item.getItemId() == R.id.menu_testPick) {
IntentsUtils.invokePick(this);
} else if(item.getItemId() == R.id.menu_testGetContent) {
IntentsUtils.invokeGetContent(this);
}
}
private TextView getTextView() {
TextView tv = (TextView)this.findViewById(R.id.textViewId);
return tv;
}
public void appendText(String text) {
TextView tv = (TextView)this.findViewById(R.id.textViewId);
tv.setText(tv.getText() + text);
}
public void appendMenuItemText(MenuItem menuItem) {
String title = menuItem.getTitle().toString();
TextView tv = (TextView)this.findViewById(R.id.textViewId);
tv.setText(tv.getText() + "\n" + title + ":" + menuItem.getItemId());
}
private void emptyText() {
TextView tv = (TextView)this.findViewById(R.id.textViewId);
tv.setText("");
}
private void dial() {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
}
private void setupButton() {
Button b = (Button)this.findViewById(R.id.button1);
b.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
parentButtonClicked(v);
}
});
}
private void parentButtonClicked(View v) {
this.appendText("\nbutton clicked");
this.dialUsingEditText();
}
private void dialWithNumber(String tel) {
String telUriString = "tel:" + tel;
Log.d(tag, telUriString);
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(telUriString));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
}
private void dialUsingEditText() {
EditText etext = (EditText)this.findViewById(R.id.editTextId);
String text = etext.getText().toString();
if(PhoneNumberUtils.isGlobalPhoneNumber(text) == true) {
dialWithNumber(text);
}
}
private EditText getEditText() {
EditText etext = (EditText)this.findViewById(R.id.editTextId);
return etext;
}
private void setupEditText() {
EditText etext = this.getEditText();
etext.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
}
protected void onActivityResult(int requestCode, int resultCode, Intent outputIntent) {
super.onActivityResult(requestCode, resultCode, outputIntent);
IntentsUtils.parseResult(this, requestCode, resultCode, outputIntent);
}
}
Intent的組成
另一種確定Intent用途的方式是檢視Intent物件包含的內容。Intent包含操作、資料URI、extra資料元素的鍵值對映,以及一個顯示類名。1.Intent和資料URI
我們在Intent中可以新增名為data的引數,這個引數指向一個URI,根據URI的不同,從而開啟不同的介面。 舉個栗子:開啟一個指定電話的撥號頁面。那麼我們不僅要指定傳遞intent的操作,還要指定intent的資料。程式碼如下: public static void call(Activity activity) {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:904-905-5646"));
activity.startActivity(intent);
}
以上程式碼中,Intent.ACTION_CALL是我們要執行的動作,開啟撥號介面。下面的setData是為該Intent設定資料,這裡的資料並非是真正的資料,而是指向資料的指標。資料部分是一個表示URI的字串,這個URI包含可被推斷的資料。
2.一般操作
在這裡,我們需要注意一點,操作和資料並非是一一對應的關係,在以上例子中,我們執行Intent.ACTION_CALL傳輸的資料是一個電話號碼,在以下例子中並非是這樣。public static void invokeWebBrowser(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
activity.startActivity(intent);
}
這個程式只是僅僅開啟一個view,並沒有告訴系統開啟一個瀏覽器,Android如何知道該呼叫什麼樣的Activity來響應Intent呢?在這種情況下,Android不僅依賴於一般操作,還依賴於URI的性質。如何區分不同的data呢?這個時候就需要Intent-flater了,intent過濾器,顧名思義,就是對傳遞過來的intent進行過濾,從而得出我們想要的。來看看我們這個Activity所註冊的描述資訊:
<activity......>
<span style="white-space:pre"> </span><intent-filter>
<span style="white-space:pre"> </span><action android:name="android.intent.action.VIEW" />
<span style="white-space:pre"> </span><data android:scheme="http" />
<span style="white-space:pre"> </span><data android:scheme="https" />
<span style="white-space:pre"> </span></intent-filter>
</activity>
在intent-filter中,我們註冊了一個action和data,分別對應操作和資料,action中的“android.intent.action.VIEW“在Intent檔案中對應的就是ACTION_VIEW
Intent.java:
public static final String ACTION_VIEW = "android.intent.action.VIEW";
data部分我們定義了android:scheme的屬性為http和https。這樣intent-filter就能過濾請求為http和https的URI。
intent-filter的data子節點的子元素和特性包括:host、mimeType、path、pathPattern、pathPrefix、port、scheme。具體每種的意義可以參考android官網。
mimeType型別是一個經常用到的型別。例如:我們可以檢視一組筆記:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
<intent-filter>
也可以檢視單個筆記
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
<intent-filter>
3.使用extra資訊
除了操作和資料外,intent還包含extra額外資訊,extra可以向intent提供更多的資訊。extra以鍵值對的形式表示,鍵名稱通常是以包名開頭,值可以是任何基本的資料型別或任意物件,只要他實現了andorid.os.pracelable介面即可。extra使用andorid.os.bundle表示。 可以使用以下方法訪問extra bundle// Get the Bundle from an Intent
Bundle extraBundle = intent.getExtras();
// Place a bundle in an intent
Bundle anotherBundle = new Bundle();
// populate the bundle with key/value pairs
...
// and then set the bundle on the Intent
intent.putExtras(anotherBudnle);
我們可以使用以下方法向extra新增資料:
putExtra(String name, boolean value);
putExtra(String name, int value);
putExtra(String name, double value);
putExtra(String name, String value);
putExtra(String name, int[] values);
putExtra(String name, float[] values);
putExtra(String name, Serializable value);
putExtra(String name, Parcelable value);
putExtra(String name, Bundle value);
putExtra(String name, Intent anotherIntent);
putIntegerArrayListExtra(String name, ArrayList arrayList);
putParcelableArrayListExtra(String name, ArrayList arrayList);
putStringArrayListExtra(String name, ArrayList arrayList);
4.使用元件直接呼叫活動
我們可以直接指定Activity的ComponentName來訪問Activity。具體如下:setComponent(ComponentName name);
setClassName(String packageName, String classNameInThatPackage);
setClassName(Context context, String classNameInThatContext);
setClass(Context context, Class classObjectInThatContext);
ComponentName將一個包名和類名包裝在一起。例如,以下程式碼呼叫系統contacts活動:
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.andorid.contacts", "com.android.aontacts.DialContactsEntryActivity"));
startActivity(intent);
也可以直接使用類名,不構造ComponentName,例如:
Intent directIntent = new Intent(activity, BasicViewActivity.class);
activity.start(directIntent);
別忘記,在AndroidManifest.xml中註冊Activity
<activity android:name=".BasicViewActivity"
android:label="Test Activity">
這裡我們不需要intent-filter,因為這種型別的Intent是顯式Intent,顯式Intent指定了一個完全限定的Android元件,所以會忽略掉該Intent的其他部分。
5.Intent類別
可以將活動分為不同的類別,以便根據類別名來搜尋。比如,我們定義一個啟動頁面:<activity
<span style="white-space:pre"> </span>android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
其中android.intent.category.LAUNCHER則將這個頁面定義為啟動頁面。
更多類別可以訪問android官網檢視:
http://developer.android.com/intl/zh-cn/reference/android/content/Intent.html。
之後我們就可以使用一下程式碼進行訪問:
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.adCategory(Intent.CATEGORY_LAUNCHER);
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
藉助於PackagerManager就可以找到與Intent相匹配的活動。