什么是Intent
Intent是Android程序總各組件之間進(jìn)行交互的一種重要方式,它不僅可以指明當(dāng)前組件想要執(zhí)行的動作,還可以再不同組件之間傳遞數(shù)據(jù)。Intent一般可用于啟動活動、啟動服務(wù)以及發(fā)送廣播等場景。
Intent分類
- 顯示Intent
Intent有很多構(gòu)造函數(shù)重載,其中一個是Intent(Context packageContext, Class<?>cls)。該函數(shù)接受兩個參數(shù),第一個參數(shù)是Context要求提供一個啟動活動的上下文,第二個參數(shù)Class則是指定想要啟動的目標(biāo)活動,通過這個構(gòu)造函數(shù)就可以創(chuàng)建出Intent的“意圖”。再使用startActivity()方法啟動活動,該方法接收一個Intent參數(shù),只需要將上邊創(chuàng)建好的Intent傳入該函數(shù)即可
創(chuàng)建兩個Activity,F(xiàn)irstActivity(主活動)和SecondActivity,在FirstActivity中創(chuàng)建一個按鈕,點(diǎn)擊之后進(jìn)入SecondActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
// 構(gòu)建Intent,傳入FirstActivity.this作為上下文,傳入SecondActivity.class作為目標(biāo)活動
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
// 這樣"意圖"就比較明顯了,即在FirstActivity這個活動的基礎(chǔ)上打來SecondActivity這個活動,執(zhí)行Intent
startActivity(intent);
}
});
}
運(yùn)行后就可以成功啟動SecondActivity了,如果想回到上一個活動,只要按下Back鍵就可以銷毀當(dāng)前活動,回到上一個活動了
- 使用隱式Intent
相比于顯式Intent,隱式Intent并不明確指出想要啟動哪一個活動,而是指定一系列更為抽象的action和category等信息,然后交由系統(tǒng)去分析這個Intent,并找出合適的活動去啟動
那么什么是合適的活動呢?簡答來說就是可以響應(yīng)這個隱式Intent的活動。對于SecondActivity可以響應(yīng)什么樣的隱式Intent呢?通過在<activity>標(biāo)簽下配置<intent-filter>的內(nèi)容,可以指定當(dāng)前活動能夠響應(yīng)的action和category,打開AndroidMainfest.xml,添加如下代碼
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.znty.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
在<action>標(biāo)簽中,指明了當(dāng)前活動可以響應(yīng)com.znty.xietao.activitytest.ACTION_START這個action,而<category>標(biāo)簽則包含了一些附加信息,更明確地指明了當(dāng)前的活動能夠響應(yīng)的Intent中還可能帶有category。只有<action>和<category>中的內(nèi)容同時能夠匹配上Intent中指定的action和category時,這個活動才能響應(yīng)該Intent(就是起個名和分個類)。
回到FirstActivity中的按鈕事件,修改為:
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent("com.znty.activitytest.ACTION_START");
startActivity(intent);
}
});
可以看到使用了Intent的另外一個構(gòu)造函數(shù),直接將action的字符串傳進(jìn)去,表明想要啟動能夠響應(yīng)“com.znty.xietao.activitytest.ACTION_START”這個action的活動,由于category設(shè)置的是DEFAULT,這是一種默認(rèn)的category,在調(diào)用startActivity()方法的時候會自動將這個category添加到Intent中。
重新運(yùn)行程序,可以得到和顯示Intent使用一樣的效果,這里使用的是隱式Intent,這就說明了在<activity>標(biāo)簽下設(shè)置的action和category的內(nèi)容生效了
每個Intent只能指定一個action,但卻能指定多個category。現(xiàn)在在Intent中除了默認(rèn)的category,再添加一個category。調(diào)用Intent的addcategory()方法來添加一個category
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent("com.znty.activitytest.ACTION_START");
intent.addCategory("com.zntq.activitytest.MY_CATEGORY");
startActivity(intent);
}
});
同時需要在AndroidManifest.xml中進(jìn)行設(shè)置,否則的話整個程序就會直接閃退
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.znty.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.zntq.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
這樣再一次運(yùn)行之后,就會發(fā)現(xiàn)一切都正常了
更多隱式Intent的用法
使用隱式Intent不僅可以啟動自己程序內(nèi)的活動,還可以啟動其他程序的活動,這使得Android多個應(yīng)用程序之間的功能共享成為了可能。比如在應(yīng)用程序中需要展示一個網(wǎng)頁,只需要調(diào)用系統(tǒng)的瀏覽器來打開這個網(wǎng)頁就行
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
// Intent.ACTION_VIEW是一個Android系統(tǒng)內(nèi)置的動作,它的常量值是"android.intent.action.VIEW"
intent.setData(Uri.parse("http://www.baidu.com"));
// 通過Uri.parse()方法,將一個網(wǎng)址字符串解析成一個UR對象,再調(diào)用Intent的setData()方法將這個Uri對象傳進(jìn)去
// setData()方法,它接收一個Uri對象,主要用于指定當(dāng)前Intent正在操作的數(shù)據(jù),而這些數(shù)據(jù)通常都是以字符串的形式傳入到Uri.parse()方法中進(jìn)行解析產(chǎn)生的。
startActivity(intent);
}
});
與上邊的對應(yīng),還可以再<intent-filter>標(biāo)簽中再配置一個<data>標(biāo)簽,用于更精確地指定當(dāng)前活動能夠響應(yīng)什么類型的數(shù)據(jù)。<data>標(biāo)簽中主要可以配置以下內(nèi)容
- android:scheme。用于指定數(shù)據(jù)的協(xié)議部分,如上例中的http部分。
- android:host。用于指定數(shù)據(jù)的主機(jī)名部分,如上例中的www.baidu.com部分。
- android:port。用于指定數(shù)據(jù)的端口部分,一般緊隨在主機(jī)名之后。
- android:path。用于指定主機(jī)名和端口之后的部分,如一段網(wǎng)址中跟在域名之后的部分。
- android:mineType。用于指定可以處理的數(shù)據(jù)類型,允許使用通配符的方式進(jìn)行指定。
只有<data>標(biāo)簽中指定的內(nèi)容和Intent中攜帶的Data完全一致時,當(dāng)前活動才能夠響應(yīng)該Intent。不過<data>標(biāo)簽都不會指定過多的內(nèi)容,如上邊例子中,其實(shí)只需要指定android:scheme為http,就可以響應(yīng)所有的http協(xié)議的Intent了。
調(diào)用系統(tǒng)打電話功能,改變FirstActivity中按鈕想打電話的“意圖”,data部分指定的協(xié)議時10086,當(dāng)然還可以指定其他很多協(xié)議,如geo表示顯示地理位置等
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
// 響應(yīng)打電話功能
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
});
向下一個Intent傳遞數(shù)據(jù)
Intent不僅能啟動Activity,還可以再啟動Activity的時候傳遞數(shù)據(jù)。它的思路很簡單,Intent提供了一系列putExtra()方法的重載,可以把想要傳遞的數(shù)據(jù)暫存在Intent中,啟動了另一個活動之后,只需要把這些數(shù)據(jù)再從Intent中取出來就可以了。
比如FirstActivity中有一個字符串,現(xiàn)在想把這個字符串傳遞到SecondActivity中,可以這樣編寫
在FirstActivity中:
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data", data);
// 第一個參數(shù)是鍵,用于后邊的取值,第二個參數(shù)是真正的數(shù)據(jù)
startActivity(intent);
}
});
在SecondActivity中接收數(shù)據(jù):
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
// 通過getIntent()方法獲取到用于SecondActivity的Intent
Intent intent = getIntent();
// 調(diào)用getStringExtra()方法來獲取傳遞的數(shù)據(jù),用鍵來取
// 如果傳遞的是整型數(shù)據(jù),則使用getIntExtra()方法;傳遞的是布爾型數(shù)據(jù)getBoolExtra()方法
String data = intent.getStringExtra("extra_data");
System.out.println(data);
Log.d("SecondActivity", data);
}
}
返回數(shù)據(jù)給上一個Activity
返回上一個活動只需要按一下Back鍵就可以了,并沒有一個用于啟動活動Intent來傳遞數(shù)據(jù)。Activity還有一個startActivityForResult()方法也適用于啟動活動的,但是這個方法期望在活動銷毀的時候能夠返回一個結(jié)果給上一個活動,這就是我們所需要的。
startActivityForResult()方法接收兩個參數(shù),第一個參數(shù)還是Intent,第二個參數(shù)是請求碼,用于之后的回調(diào)中判斷數(shù)據(jù)的來源
修改FirstActivity中按鈕的點(diǎn)擊事件
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
// 使用startActivityForResult()方法來啟動Activity,請求碼只要是一個唯一值就可以了,這里傳入1
startActivityForResult(intent, 1);
}
});
在SecondActivity中給按鈕注冊事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
// 給按鈕注冊點(diǎn)擊事件,并在點(diǎn)擊事件中添加返回數(shù)據(jù)的邏輯
Button button2 = (Button)findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 創(chuàng)建一個Intent,該Intent僅僅用于傳遞數(shù)據(jù),沒有指定任何的"意圖"
Intent intent = new Intent();
// 把數(shù)據(jù)存放在Intent中
intent.putExtra("data_return", "Hello FirstActivity");
// 調(diào)用setresult()方法,該方法是專門用于向上一個頁面?zhèn)鬟f數(shù)據(jù)的。接收兩個參數(shù),第一個參數(shù)
// 用于向上一個活動返回處理結(jié)果,一般只使用RESULT_OK或RESULT_CANCELED這兩個值,第二個參數(shù)則把
// 帶有數(shù)據(jù)的Intent傳遞回去
setResult(RESULT_OK, intent);
// 調(diào)用finish()方法來銷毀當(dāng)前活動
finish();
}
});
}
在SecondActivity銷毀之后會回調(diào)上一個活動的onActivityResult()方法,再回到FirstActivity
// 由于使用 startActivityForResult()方法來啟動SecondActivity的,在SecondActivity被銷毀之后會回調(diào)
// 上一個活動也就是FirstActivity的onActivityResult()方法,因此重寫該方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 該方法接收三個參數(shù),第一個參數(shù)requestCode,就是啟動活動時傳入的請求碼,第二個參數(shù)resultCode,即返回數(shù)據(jù)時
// 傳入的處理結(jié)果,第三個參數(shù)就是攜帶者返回數(shù)據(jù)的Intent
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
}
}
由于在一個Activity中有可能調(diào)用startActivityForResult()方法去啟動很多不同的Activity,每一個Activity返回的數(shù)據(jù)都會回調(diào)到onActivityResult()這個方法中,因此首先要通過檢查requestCode的值來判斷數(shù)據(jù)源。確定數(shù)據(jù)是從SecondActivity返回的之后,再通過resultCode的值來判斷處理結(jié)果是否成功,最后從data中取值并打印,這樣就完成了向上一個Activity返回數(shù)據(jù)的工作。
如果用戶在SecondActivity中并不是通過點(diǎn)擊按鈕而是通過按下Back鍵回到FirstActivity,這時候需要在SecondActivity中重寫onBackPressed()方法來解決:
@Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
}
這樣當(dāng)用戶按下Back鍵,就會執(zhí)行onBackPressed()方法中的代碼,從而在這里添加返回數(shù)據(jù)的邏輯就行。