android之旅-Intent和BroadcastReceiver(修改了網上文章很多不足,重點參考了android4進階編程)
一、Intent作用及分類
Intent是一種訊息傳遞機制,可以在程式內及程式間使用,主要用法為:①使用類名顯式啟動一個service或Activity②在①的基礎上執行一個動作的intent,並進行相關處理③廣播某個時間已經發生。
二、使用Intent啟動Activity
1、顯式啟動一個Activity
所謂顯式啟動,即顯式指定我們要啟動Activity的類名,比如我們要在Mainactivity中的Button被按下時,開啟IntentActivity,就可以使用下面的代碼:
if(v==btn1){Intent intent=new Intent();intent.setClass(MainActivity.this, IntentActivity.class);startActivity(intent);}注意,所有的Activity都儲存於一個Activity棧,當我們調用startActivity後,IntentActivity將會經過Creat start resume最終運行,並且IntentActivity會移動到Acticity棧的頂部。但是當我們按下back(或在代碼執行finish())會從Activity棧棧頂依次刪除Activity。
2、隱式啟動Activity
隱式啟動Activity即匿名啟動某一恰當的程式組件來響應動作請求。如我們要隱式的啟動開啟連絡人的Activity:
//隱含選取連絡人,注意使用startActivity並不能啟動介面Intent intent=new Intent(Intent.ACTION_PICK,Uri.parse(content://contacts/people));startActivityForResult(intent,PICK_CONTACT_SUBACTIVITY);
3、啟動Activity並捕獲子Activity返回的結果
在上文我們可以看出,單純使用startActivity MainActivity並不能得到IntentActivity進行處理後的結果。這時我們需要startActivityForResult:
但是僅僅使用這個介面還不夠,我們需要一個介面來監聽結構,這時,我們就需要重載MainActivity中的protected void onActivityResult(int requestCode, int resultCode, Intent data):
在MainActivity中:
//定義intent識別碼 private static final int SHOW_SUBACTIVITY=1;
Intent intent=new Intent(); intent.setClass(MainActivity.this, IntentActivity.class); //傳入識別碼唯一標識SHOW_SUBACTIVITY,啟動intent,以便擷取下一頁面返回的結果 startActivityForResult(intent, SHOW_SUBACTIVITY);
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stub super.onActivityResult(requestCode, resultCode, data); if(requestCode==SHOW_SUBACTIVITY) { switch (resultCode) { case RESULT_CANCELED: { Bundle bd=data.getExtras(); edittxt.setText(bd.getString(text)); break; } case RESULT_OK: { Bundle bd=data.getExtras(); edittxt.setText(bd.getString(text)); break; } default: break; } }}
在IntentActivity中:
switch(v.getId()){case R.id.resultcancel:{Intent intent=new Intent();intent.setClass(IntentActivity.this, MainActivity.class);intent.putExtra(text, cancel:i am from intentactivity!and pass back me on childactivity finished!);setResult(RESULT_CANCELED,intent);finish();break;}case R.id.resultok:{Intent intent=new Intent(); intent.setClass(IntentActivity.this, MainActivity.class); intent.putExtra(text, ok: am from intentactivity!and pass back me on childactivity finished!); setResult(RESULT_OK,intent); finish(); break;}default:break;}解析:我們在startActivityForResult(intent, SHOW_SUBACTIVITY);傳入SHOW_SUBACTIVITY,其實就是一個大於0的整數,用來標識相應的Intent;為了接受Result,對onActivityResult(int requestCode, int resultCode, Intent data) 進行重寫,注意,requestCode就是Intent的標識符,即為上文中的SHOW_SUNACTIVITY,resultCode即為IntentActivity中的setResult(RESULT_OK,intent);傳回的Result值 -RESULT_OK,date即為setResult(RESULT_OK,intent);傳回的intent。
三、使用Intent廣播事件
1、最基本的廣播事件發送與接受:
廣播的發送,很簡單,產生一個Intent,設定Action,直接進行廣播:
public static final String BROAD_UI_STRING=com.example.intentbraodcast.BROAD_UI;
Intent intent=new Intent(BROAD_UI_STRING);intent.putExtra(str, update ui by broadcast!);sendBroadcast(intent);
廣播的註冊,最好在廣播的發送前註冊廣播:
//註冊Broadcast Receiver registerReceiver(new MyBroadcastReceiver, new IntentFilter(BROAD_UI_STRING));
註:上文中的 BROAD_UI_STRING就是一個自訂的獨一無二的字串,由於廣播不但可用於應用程式內部交換資料,還可用於系統間應用交換資料,故一般用傳統的包名首碼法來命名。
進行註冊以前,我們需要實現自己的接收器,繼承BroadcastReceiver即可,我們對廣播出的Intent繫結資料再次進行處理
public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //TODO: React to the Intent received. String actionString=intent.getAction(); if (actionString.equals(BROAD_UI_STRING)) { //改變下一個activity中的值 String str=intent.getStringExtra(str); Intent newIntent=new Intent(); newIntent.setClass(MainActivity.this,IntentActivity.class ); newIntent.putExtra(str, str); context.startActivity(newIntent); } else if(actionString.equals(LOCAL_ACTION)) { edittxt.setText(intent.getStringExtra(str)); } } }廣播的登出:在我們不再廣播時,通常是介面掛起或停止時,需要對接收器進行登出:
@Overrideprotected void onPause() { unregisterReceiver(receiver);super.onPause();}需要注意的是,接收器中的處理常式需要在5秒鐘內完成,否則會顯示Force CLose的對話方塊。很多時候,我們希望當我們的應用程式在關閉時也能響應一些廣播,需要在Manifest中的application節點添加一個receiver標籤,指定接收器類名和過濾器標識符:
這樣,即使我們的應用程式處於關閉狀態也能響應廣播。
2、有序廣播
3、廣播Sticky Intent,在一些教程仍出現,但在android 5.0以後會漸漸廢棄,故不再討論。
4、LocalBroadcastManager(局部廣播管理器)
顧名思義,其用於局部資料的訊息驅動,是一種輕量級的handler,更高效的廣播模型。
操作過程與普通廣播管理器類似,只不過要先擷取LocalBroadcastManager:
lbm=LocalBroadcastManager.getInstance(MainActivity.this);
發送時將sendBroadcast改為lbm.sendBroadcast,註冊時將registerReceiver改為lbm.registerReceiver,登出時將unregisterReceiver改為lbm.unregisterReceiver
下面為樣本的全部代碼,工程檔案我也會放到最後:
package com.example.intentandbroadcast;import android.R.string;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.net.Uri;import android.os.Bundle;import android.support.v4.content.LocalBroadcastManager;import android.view.*;import android.view.View.OnClickListener;import android.widget.*;@SuppressWarnings(unused)public class MainActivity extends Activity { Button btn1; Button btn2,btn3,btn4,btn_broad_ui,btn_local_broad; EditText edittxt; TextView tv; LocalBroadcastManager lbm; MyBroadcastReceiver receiver; //定義intent識別碼 private static final int SHOW_SUBACTIVITY=1; private static final int PICK_CONTACT_SUBACTIVITY=2; public static final String BROAD_UI_STRING=com.example.intentbraodcast.BROAD_UI; public static final String LOCAL_ACTION=com.example.intentbraodcast.LOCAL_ACTION; void getviewdefinition() { btn1=(Button)findViewById(R.id.btn1); btn2=(Button)findViewById(R.id.btn2); btn3=(Button)findViewById(R.id.btn3); btn4=(Button)findViewById(R.id.btn4); btn_broad_ui=(Button)findViewById(R.id.btn_broad_ui); edittxt=(EditText)findViewById(R.id.edittext); tv=(TextView)findViewById(R.id.textview); btn_local_broad=(Button)findViewById(R.id.btn_local_broad_ui); lbm=LocalBroadcastManager.getInstance(MainActivity.this); receiver=new MyBroadcastReceiver(); } public class OnButtonClick implements OnClickListener {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif(v==btn1){Intent intent=new Intent();intent.setClass(MainActivity.this, IntentActivity.class);//傳入識別碼唯一標識SHOW_SUBACTIVITY,啟動intent,以便擷取下一頁面返回的結果startActivityForResult(intent, SHOW_SUBACTIVITY);}else if(v==btn3){//觸發外部intent打電話Intent intent=new Intent(Intent.ACTION_DIAL,Uri.parse(tel:13237170570));startActivity(intent);}else if(v==btn4){//隱含選取連絡人,注意使用startActivity並不能啟動介面Intent intent=new Intent(Intent.ACTION_PICK,Uri.parse(content://contacts/people));startActivityForResult(intent,PICK_CONTACT_SUBACTIVITY);}else if(v==btn_broad_ui){Intent intent=new Intent(BROAD_UI_STRING);intent.putExtra(str, update ui by broadcast!);sendBroadcast(intent);}else if(v==btn_local_broad){//設定本地廣播,更高效:Intent intent=new Intent(LOCAL_ACTION);intent.putExtra(str, i am created by local broadcast!);lbm.sendBroadcast(intent);}} }@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getviewdefinition(); OnButtonClick btnclick=new OnButtonClick(); btn1.setOnClickListener(btnclick); btn3.setOnClickListener(btnclick); btn4.setOnClickListener(btnclick); btn_broad_ui.setOnClickListener(btnclick); btn_local_broad.setOnClickListener(btnclick); }@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();//註冊Broadcast Receiver registerReceiver(receiver, new IntentFilter(BROAD_UI_STRING)); //註冊local broadcastlbm.registerReceiver(receiver, new IntentFilter(LOCAL_ACTION)); } @Overrideprotected void onPause() { unregisterReceiver(receiver); lbm.unregisterReceiver(receiver);super.onPause();} @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {// TODO Auto-generated method stub super.onActivityResult(requestCode, resultCode, data); if(requestCode==SHOW_SUBACTIVITY) { switch (resultCode) { case RESULT_CANCELED: { Bundle bd=data.getExtras(); edittxt.setText(bd.getString(text)); break; } case RESULT_OK: { Bundle bd=data.getExtras(); edittxt.setText(bd.getString(text)); break; } default: break; } }} @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //TODO: React to the Intent received. String actionString=intent.getAction(); if (actionString.equals(BROAD_UI_STRING)) { //改變下一個activity中的值 String str=intent.getStringExtra(str); Intent newIntent=new Intent(); newIntent.setClass(MainActivity.this,IntentActivity.class ); newIntent.putExtra(str, str); context.startActivity(newIntent); } else if(actionString.equals(LOCAL_ACTION)) { edittxt.setText(intent.getStringExtra(str)); } } }}
package com.example.intentandbroadcast;import java.security.PublicKey;import com.example.intentandbroadcast.MainActivity.MyBroadcastReceiver;import android.app.Activity;import android.app.PendingIntent.CanceledException;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.support.v4.content.LocalBroadcastManager;import android.view.*;import android.view.View.OnClickListener;import android.widget.*;public class IntentActivity extends Activity {Button cancel,ok,btn_local;TextView txtintentTextView;IntentFilter filter;String stickystring;void getdefinition(){cancel=(Button)findViewById(R.id.resultcancel); ok=(Button)findViewById(R.id.resultok); btn_local=(Button)findViewById(R.id.btn_localintent); txtintentTextView=(TextView)findViewById(R.id.textintent); }public class OnBtnClick implements OnClickListener{@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch(v.getId()){case R.id.resultcancel:{Intent intent=new Intent();intent.setClass(IntentActivity.this, MainActivity.class);intent.putExtra(text, cancel:i am from intentactivity!and pass back me on childactivity finished!);setResult(RESULT_CANCELED,intent);finish();break;}case R.id.resultok:{Intent intent=new Intent(); intent.setClass(IntentActivity.this, MainActivity.class); intent.putExtra(text, ok: am from intentactivity!and pass back me on childactivity finished!); setResult(RESULT_OK,intent); finish(); break;}default:break;}}} @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //雷區,這個啟動的xml打錯了 調了好久 setContentView(R.layout.activity_intent); getdefinition();//測試startactivyforresult cancel.setOnClickListener(new OnBtnClick()); ok.setOnClickListener(new OnBtnClick()); }@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }