Android的UI架構要求使用者將他們的app分為activity,通過itent來進行調度,其中有一個main activity由Android的launcher在案頭中調用。例如一個日曆的應用,需要查看日曆的activity,查看單個事件的activity,編輯事件的activity等等。在查看日曆的activity中,如果使用者選擇的某個事件,需要通過查看事件的activity來處理。這就是最近本的app UI架構,本次,我們將學習如何通過intent來完成。
Activity之間的關係
某種商務邏輯下,activity1需要知道被調起的activity2是否結束,activity2就是activity1的subactivity。
另一些商務邏輯下,activity1並不需要瞭解被它調起的activity2的運行情況,例如在郵件中開啟一個附件,郵件activity1並不需要瞭解查看附件activity2是否結束。這種情況下,兩個activity不是主從關係,而是peer關係,activity2是一個常規的activity。
步驟1:Make the Intent
intent會封裝一個請求給Android,使得其他activity或者intent receiver知道如何處理。如果intent要launch的activity是我們自己編寫的,可以很容易通過一個精確指定的intent來實現,例如:
new Intent(this, HelpActivity.class);
其中HelpActivity.class就是我們需要launch的component。這個activity只需要在AndroidManifest.xml檔案中定義,但是不需要任何的inter filter,因為是通過直接請求的方式。如果我們需要打上一些data,即Uri,請求一個通用的activity,如下:
Uri uri=Uri.parse("geo:"+lat.toString()+","+lon.toString());
Intent i=new Intent(Intent.ACTION_VIEW, uri);
步驟2:Make the Call
根據activity之間的關係,通過intent的方法startActivity()或者startActivityForResult()來launch另一個activity。後者是需要知道activity2是否運行結束,以及啟動並執行結果。
startActivityForResult()會向intent傳遞一個數字,這個數字對於calling activity來講是唯一的。用於區分哪個activity。被調起的activity運行完,會在calling activity中觸發onActivityResult(),我們可以通過這個唯一的數字來區分到底是哪個被調起的activity運行結束。我們還會得到下面的資訊:
- result code,通過被調起的activity用setResult()來設定,一般是RESULT_OK和RESULT_CANCELLED,當然我們也可以定義我們自己的傳回值,(從RESULT_FIRST_USER開始定義)
- 可選的String,用於傳遞某些返回資訊,例如是一個URL來表述某個資源,有例如在ACTION_PICK中返回使用者選取內容的資料。
- 可選的Bundle,用於返回所需的資訊
例子一:一個簡單的調用
例子通過輸入經緯度,然後通過intent去launch地圖應用。布局檔案如下,順帶複習一下TableLayout的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ...... >
<TableLayout android:layout_width="fill_parent" android:layout_height="wrap_content"
android:stretchColumns="1,2">
<TableRow>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="2dip" android:paddingRight="4dip"
android:text="Location:" />
<EditText android:id="@+id/c18_lat"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:cursorVisible="true"
android:editable="true"
android:singleLine="true"
android:layout_weight="1"/>
<EditText android:id="@+id/c18_lon"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:cursorVisible="true"
android:editable="true"
android:singleLine="true"
android:layout_weight="1" />
</TableRow>
</TableLayout>
<Button android:id="@+id/c18_map"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Show Me!" />
</LinearLayout>
原始碼如下:
public class Chapter18Test1 extends Activity{
private EditText latitude = null;
private EditText longtitude =null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chapter_18_test1);
latitude = (EditText)findViewById(R.id.c18_lat);
longtitude = (EditText)findViewById(R.id.c18_lon);
Button button = (Button)findViewById(R.id.c18_map);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String _lat = latitude.getText().toString();
String _lon = longtitude.getText().toString();
//由於AVD缺乏地圖應用,所以在模擬器中,會無法觸發geo:作為URI的應用,會出現報錯,如果仍然使用模擬器,可通過Web瀏覽的方式。例子採用模擬器。
//Uri uri=Uri.parse("geo:" + _lat + _lon);
Uri uri=Uri.parse("http://maps.google.com/?q=" +_lat + "," + _lon);
startActivity(new Intent(Intent.ACTION_VIEW,uri));
}
});
}
}
例子二:Tab Browser
我們可以回顧一下Android學習筆記(二二): 多頁顯示-Tag的使用中最後一個例子,在Tab中顯示Acitvity。如果我們需要將Activity作為content在tab中顯示,我們提供一個Intent來launch所需的activity。在這個例子中,我們將在Tab的內容中通過intent調起網頁瀏覽。
如果我們直接使用
Intent intent=new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(http://commonsware.com));
然後在tab中setContent(intent);我們會發現不能爭取工作,因為在Android中,基於安全考慮,不能在tab中載入其他app的activity。因此我們需要自己來寫。我們先寫兩個嵌入webkit browser的瀏覽器。
public class Chapter18Test2_1 extends Activity{ private WebView browser = null; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); browser = new WebView(this); setContentView(browser); browser.loadUrl("http://commonsware.com"); } } |
public class Chapter18Test2_2 extends Activity{ private WebView browser = null; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); browser = new WebView(this); setContentView(browser); browser.loadUrl("http://www.android.com"); } } |
calling activity的原始碼如下,很簡單
public class Chapter18Test2 extends TabActivity{
//使用TabActivity,已經有Tab的布局,因此我們不再需要布局xml檔案。
private TabHost host = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
host=getTabHost();
host.addTab(host.newTabSpec("one").setIndicator("CW").
setContent(new Intent(this,Chapter18Test2_1.class)));
host.addTab(host.newTabSpec("Two").setIndicator("Android").
setContent(new Intent(this,Chapter18Test2_2.class)));
}
}
我們回頭在來看看這個例子的代碼,同樣的開啟某個webkit browser的URL使用了兩個activity,兩個class,這是相當浪費的。我們可以將URL作為Intent的extra的資訊傳遞。我們將上面的例子修改一下,通過Bundle來傳遞extra資訊,並在calling activity中,可以很方便地增加tab。
被調用的activity:
public class Chapter18Test2_0 extends Activity{
private WebView browser = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
browser = new WebView(this);
setContentView(browser);
Bundle bundle = getIntent().getExtras();
browser.loadUrl(bundle.getString("http_uri"));
}
}
calling的activity:
public class Chapter18Test2 extends TabActivity{
private TabHost host = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
host=getTabHost();
addTab("one","CW","http://commonsware.com");
addTab("Two","Android","http://www.android.com");
addTab("Three","Blog","http://blog.csdn.net/flowingflying/");
}
//增加一個方法,用於添加tab
private void addTab(String tag, String indicator, String uri){
Bundle bundle = new Bundle();
bundle.putString("http_uri",uri);
Intent intent = new Intent(this,Chapter18Test2_0.class);
intent.putExtras(bundle);
host.addTab(host.newTabSpec(tag).setIndicator(indicator).setContent(intent));
}
}
相關連結:
我的Android開發相關文章