Android教程 -04 啟動其它Activity,靜態工廠設計模式傳遞資料
意圖 Intent
一個應用程式肯定不只有一個介面,如何切換到其它介面,只時候就需要啟動其它的Activity。啟動Activity有多種方式。我在這簡單總結下:
學習開啟其它的Activity,首先需要了解意圖:
Intent是在不同元件中(比如兩個Activity)提供執行時繫結的物件。Intent代表一個應用”想去做什麼事”,你可以用它做各種各樣的任務,不過大部分的時候他們被用來啟動另一個Activity。
顯示意圖
顯示意圖顧名思義, 其實就是把要開啟的Activity的名字赤裸裸的寫在程式碼中。
如下面程式碼就是要啟動Demo2Activity,當然肯定需要上下文(Context)這個上帝類。需要注意的是要啟動的activity必須要在清單檔案(AndroidManifest.xml)中進行配置。
// 初始化Button控制元件
button= (Button) findViewById(R.id.button);
// 設定button的點選事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 宣告Button的點選事件 跳轉到Demo2Activity
// 引數1 上下文 引數2 跳轉Activity的位元組碼
Intent intent = new Intent(getApplicationContext(), Demo2Activity.class);
startActivity(intent);
}
});
顯示意圖啟動Activity的速度略快,不過有些侷限性,只能開啟自己程式中的Activity
隱式意圖
- 相對於顯示意圖更加含蓄
- 需要指定當前Activity 能夠響應的action或category。
每個Activity要想能被開啟都需要在清單檔案(AndroidManifest.xml)中進行配置,當配置完成,程式部署到手機的時候,該Activity會加入到系統的列表中。在配置的時候,我們可以對activity進行一些描述(新增action或category),另一個Activity通過這些描述就可以開啟這個Activity。
參考下圖:
程式碼如下
<!--在清單檔案中描述Demo2Activity-->
<activity
android:name=".Demo2Activity"
android:label="@string/title_activity_demo2" >
<intent-filter>
<action android:name="aaa.bbb.ccc" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
// 初始化Button控制元件
button = (Button) findViewById(R.id.button);
// 設定button的點選事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通過隱式意圖開啟activity
Intent intent = new Intent();
intent.setAction("aaa.bbb.ccc");
intent.addCategory("android.intent.category.DEFAULT");
startActivity(intent);
}
});
隱式意圖不僅可以開啟自己程式的Activity,還可以開啟其它程式的Activity,一般的原則是開啟自己程式的Activity多用顯示意圖。
隱式意圖的常見操作
撥打電話
/**
* 撥打電話
*/
public void dail(View v){
Intent intent=new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:1333333333"));
startActivity(intent);
}
開啟瀏覽器
/**
* 開啟瀏覽器
*/
public void goToBrowser(View v){
Intent intent=new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
分享文字
/**
* 分享
*/
public void share(View v){
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SEND);
// 指定引數的型別
intent.setType("text/plain"); // "image/png"
// 設定要分享的文字
intent.putExtra(Intent.EXTRA_TEXT,"於連林很帥");
startActivity(intent);
}
需要注意的是,如果想讓你的程式具備分享其他程式文字的功能,需要在你想要分享的Activity新增如下配置:
<activity
android:name=".MainActivity"
>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="text/plain" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
這樣我們程式的MainActivity就具備分享文字的功能了。
Activity之間傳遞資料
Activity之間傳遞資料是很常見的操作,傳遞資料核心的方法就是通過Intent的putExtra方法傳遞,可以傳遞的型別包括八大基本型別,字串和實現Serializable或Parcelable介面的物件,也可以傳遞ArrayList集合(集合裡對型別有約束,允許的型別包括String,Parcelable)。
寫法和用map集合新增資料一樣, 需要用到key-value鍵值對。
我們以SendDataActivity和RDataActivity為例演示一下程式碼:
// SendDataActivity傳遞資料給RDataActivity
public void sendData(View v){
Intent intent=new Intent(this,RDataActivity.class);
intent.putExtra("key","要傳遞的資料");
// 開啟Activity
startActivity(intent);
}
下面是RDataActivity接受資料:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rdata);
// 獲取到開啟當前Activity的意圖
Intent intent =getIntent();
// Value就是我們接受的資料
String value=intent.getStringExtra("key");
//...
}
需要注意的是兩個Activity的key(就是程式碼中”key”) 必須保持一致。但是這種寫法有個潛在的問題。
靜態工廠設計模式傳遞資料
在實際開發的過程中,往往同時有多個程式設計師寫不同的Activity。經常會出現傳遞資料的Activity和接受資料的Activity不是一個程式設計師寫的。為了保持key統一,就需要兩個程式設計師之間進行溝通,這樣大大提高了程式的耦合性,程式變的不那麼容易維護。
安卓中的基本問題之一就是對鍵/值對的持有。因為bundle 需要鍵/值對,所以你總是需要一個key。然而問題是哪裡儲存這些key?
與其建立另一個類的物件,不如讓對應的類自己建立物件。
我們接下來修改一下RDataActivity的程式碼,新增一個靜態方法,其餘不用變。讓RDataActivity自己建立自己的Intent
public static Intent newIntent(Context context,String value){
Intent intent=new Intent(context,RDataActivity.class);
intent.putExtra("key",value);
return intent;
}
呼叫者類無需知道intent以及key的任何事情。SendDataActivity只需告訴RDataActivity,”嘿,我需要一個帶有這個資料的intent”。就是這樣,RDataActivity會做完其它的事情。我們接下來修改下SendDataActivity的sendData方法
public void sendData(View v){
Intent intent=RDataActivity.newIntent(this,"value");
startActivity(intent); // 開啟RDataActivity
}
這樣改完以後程式碼就變的容易維護了。
返回資料給之前的Activity
這時候就用到兩個核心的方法:
1. startActivityForResult()
2. onActivityResult()
開啟Activity要用startActivityForResult了,我們繼續把上面的程式碼改造下:
// SendDataActivity傳遞資料給RDataActivity
public void sendData(View v){
Intent intent=RDataActivity.newIntent(this,"value");
// 修改開啟Activity的方法
startActivityForResult(intent,0); //引數2是 requestCode請求碼
}
RDataActivity新增程式碼:
// 退出按鈕點選事件, 點選退出
public void exit(View v){
Intent intent=new Intent();
intent.putExtra("result","resultData"); //回傳的資料
setResult(0, intent); //引數1: resultCode 結果碼
finish(); // 主動關閉當前Activity
}
當RDataActivity退出的時候就會呼叫SendDataActivity的onActivityResult()方法
@Override
// requestCode 請求碼 resultCode結果碼 data傳遞的資料
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==0&&data!=null){
String result=data.getStringExtra("result");
Toast.makeText(this,result,Toast.LENGTH_LONG).show();
}
}