第八講Intent和BroadcastReceiver
本講介紹了Android應用程序中最爲重要Intent和四大組件之一
文章目錄
Intent
Intent可以啓動一個Activity,也可以啓動一個Service,還可以發起一個廣播Broadcast。
組件名稱 | 方法名稱 |
---|---|
Activity | startActivity() startActivityForResult() |
Service | startService() bindService() |
Broadcasts | sendBroadcast() sendOrderedBroadcast()sendStickyBroadcast() |
1.啓動Activity:
向Context.startActivity() 或[Activity.startActivityForResult()](http://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))方法傳遞一個Intent對象,可以啓動一個activity,或使得一個已經存在的activity去做一些新的事情。
(也可以向 [Activity.setResult()](http://developer.android.com/reference/android/app/Activity.html#setResult(int, android.content.Intent)) 去傳遞這個Intent對象,返回調用了startActivityForResult()
的activity的一些信息。)
2.啓動Service:
向 Context.startService() 方法傳遞Intent對象可以初始化一個service或者向一個已經存在的service傳遞新的指令。
類似的,向[Context.bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int)) 方法傳遞Intent對象可以在調用所在的組件和目標service之間建立一種連接。如果這個service並沒有開始運行,則它可以初始化這個service。
3.發起廣播Broadcast
可以向下面的廣播方法傳遞Intent對象來發起廣播:
Context.sendBroadcast(),[Context.sendOrderedBroadcast()](http://developer.android.com/reference/android/content/Context.html#sendOrderedBroadcast(android.content.Intent, java.lang.String)), 或 Context.sendStickyBroadcast()。系統會找到相應的廣播接收者對此進行響應。
Intent在尋找目標組件時有兩種方法:
第一種,顯式調用,通過Component name直接指定;
第二種,隱式調用,沒有明確指定目標組件的名稱,那麼就要通過一定的條件過濾篩選。
啓動activity、service和broadcast的消息系統是沒有任何重合的,即,一個要啓動activity的Intent對象是絕對不會啓動一個service的。
Intent對象構成
Intent對象由以下六個部分組成:
Component name
Action
Data
Category
Extras
Flags
Component name
Component name即組件名稱,是要處理這個Intent對象的組件名稱。
組件名稱對象由ComponentName類來封裝,組件名稱包含包名稱和類名稱,被聲明在AndroidManifest.xml文件中。
組件名稱通過 setComponent(),[setClass()](http://developer.android.com/reference/android/content/Intent.html#setClass(android.content.Context, java.lang.Class)),[setClassName()](http://developer.android.com/reference/android/content/Intent.html#setClassName(java.lang.String, java.lang.String))設置,通過getComponent()獲取。
需要注意的是Component name是一個可選項,如果被設置,那麼Intent對象就顯式指定了要轉向的組件,如果沒有被設置,則Intent對象需要根據其他信息進行篩選查找。
Action
Action是指Intent要完成的動作,是一個字符串常量。
在Intent類裏面定義了很多Action常量,其中有:
ACTION_MAIN: | Android Application的入口,每個Android應用必須且只能包含一個此類型的Action聲明。 |
---|---|
ACTION_VIEW: | 系統根據不同的Data類型,通過已註冊的對應Application顯示數據。 |
ACTION_EDIT: | 系統根據不同的Data類型,通過已註冊的對應Application編輯示數據。 |
ACTION_DIAL: | 打開系統默認的撥號程序,如果Data中設置了電話號碼,則自動在撥號程序中輸入此號碼 |
ACTION_CALL: | 直接呼叫Data中所帶的號碼 |
ACTION_ANSWER: | 接聽來電 |
ACTION_SEND: | 由用戶指定發送方式進行數據發送操作 |
ACTION_SENDTO: | 系統根據不同的Data類型,通過已註冊的對應Application進行數據發送操作 |
ACTION_BOOT_COMPLETED: | Android系統在啓動完畢後發出帶有此Action的廣播(Broadcast) |
ACTION_TIME_CHANGED: | Android系統的時間發生改變後發出帶有此Action的廣播(Broadcast) |
ACTION_PACKAGE_ADDED: | Android系統安裝了新的Application之後發出帶有此Action的廣播(Broadcast) |
ACTION_PACKAGE_CHANGED: | Android系統中已存在的Application發生改變之後(如應用更新操作)發出帶有此Action的廣播(Broadcast) |
ACTION_PACKAGE_REMOVED: | 卸載了Android系統已存在的Application之後發出帶有此Action的廣播(Broadcast)。 |
Intent類中有很多預定義的常量,爲了一些通常的動作;還有一些定義在Android API的其他地方。
也可以自己定義Action常量,自定義的常量需要加上你的應用的包名作爲前綴。
Action在很大程度上決定了Intent的其他部分是如何構造的,尤其是 data 和 extras域。(就好像函數名會決定着參數值和返回值一樣。)所以Action的名字應該儘可能具體,並且它們應該和Intent中的其他域緊密結合。
使用 setAction() 和 getAction()來設置和讀取Action屬性。
Data
Data屬性是執行動作的URI和MIME類型,不同的動作有不同的數據規格。
比如,Action是ACTION_EDIT時,數據域將是文檔的URI;Action是ACTION_CALL時,數據域是 tel: URI ,帶有要撥打的電話號碼;如果Action是 ACTION_VIEW,則數據域是http: URI。
當匹配intent和能夠處理intent所帶的數據的組件時,知道數據類型(MIME類型)是很重要的。比如,一個展示圖像的組件不應該被叫去播放一個音頻。
很多情況下,從URI可以看出數據類型,比如content: URIs,表示數據是在設備上,但是是由content provider控制。
數據類型也可以顯式指定,比如setData()方法指定數據爲URI,setType() 指定爲MIME type,[setDataAndType()](http://developer.android.com/reference/android/content/Intent.html#setDataAndType(android.net.Uri, java.lang.String)) 指定它既爲URI又爲MIME type。讀取的時候URI用getData(),MIME type用getType()。
在intent-filter中指定data屬性的實際目的是:要求接收的Intent中的data必須符合intent-filter中指定的data屬性,這樣達到反向限定Intent的作用。
tel://: | 號碼數據格式,後跟電話號碼。 |
---|---|
mailto://: | 郵件數據格式,後跟郵件收件人地址 |
smsto://: | 短息數據格式,後跟短信接收號碼 |
content://: | 內容數據格式,後跟需要讀取的內容。 |
file://: | 文件數據格式,後跟文件路徑 |
market://search?q=pname:pkgname: | 市場數據格式,在Google Market裏搜索包名爲pkgname的應用 |
geo://latitude,longitude: | 經緯數據格式,在地圖上顯示經緯度指定的位置。 |
Category
Category是一個字符串,提供了額外的信息,有關於能夠處理這個Intent對象的組件種類。
Category屬性用於指定當前動作(Action)被執行的環境。通過addCategory()方法或在清單文件AndroidManifest.xml中設置。默認爲:CATEGORY_DEFAULT
一個Intent對象中可以包含任意數量的category描述信息。
Intent類中也定義了一些Category常量:
Constant | Meaning |
---|---|
*CATEGORY_DEFAULT: | Android系統中默認的執行方式,按照普通Activity的執行方式執行。 |
CATEGORY_HOME: | 設置該組件爲Home Activity*。* |
CATEGORY_PREFERENCE: | 設置該組件爲Preference*。* |
CATEGORY_LAUNCHER: | 設置該組件爲在當前應用程序啓動器中優先級最高的Activity,通常爲入口ACTION_MAIN配合使用。 |
CATEGORY_BROWSABLE: | 設置該組件可以使用瀏覽器啓動 |
CATEGORY_GADGET: | 設置該組件可以內嵌到另外的Activity中 |
與category相應的方法有添加addCategory()、移除removeCategory() 和獲取所有category getCategories() 。
Extras
傳遞給Intent的額外數據,以Bundle的形式定義,就是一些鍵值對。就好像一些動作和特定的數據URI對應,一些動作和特定的extras對應。
比如ACTION_TIMEZONE_CHANGED intent對象有一個 "time-zone
"的extra來確認新的時區;
ACTION_HEADSET_PLUG
有一個"state
" extra表示耳機是否插入,還有一個 “name
” extra關於耳機類型;
如果你要設計一個SHOW_COLOR動作,那麼extra中應該包含顏色值。
Intent對象有一系列的putXXX()函數用於放入各種數據類型,相應的也有一系列的getXXX()函數用於讀取數據。
實際上,數據可以被作爲一個Bundle對象被使用,利用 putExtras() 和 getExtras() 方法。
EXTRA_BCC: | 存放郵件密送人地址的字符串數組。 |
---|---|
EXTRA_CC: | 存放郵件抄送人地址的字符串數組 |
EXTRA_EMAIL: | 存放郵件地址的字符串數組 |
EXTRA_SUBJECT: | 存放郵件主題字符串 |
EXTRA_TEXT: | 存放郵件內容 |
EXTRA_KEY_EVENT: | 以KeyEvent對象方式存放觸發Intent的按鍵 |
EXTRA_PHONE_NUMBER: | 存放調用ACTION_CALL時的電話號碼 |
Flags
各種類型的Flag。很多是用來指定Android系統如何啓動activity,還有啓動了activity後如何對待它。所有這些都定義在Intent類中。
參考鏈接:https://www.cnblogs.com/mengdd/archive/2013/03/18/2965839.html
URI和intent-filter匹配:
Intent中URI和intent-filter進行比較的時候只會進行部分的比較:
(1)當intent-filter中只設置了scheme,只會比較URI的scheme部分;
(2)當intent-filter中只設置了scheme和authority,那麼只會匹配URI中的scheme和authority;
(3)當intent-filter中設置了scheme、authority和path,那麼只會匹配URI中的scheme、authority、path;(path可以使用通配符進行匹配)
(4)當intent-filter中設置了mimeType,還會進行數據類型的匹配。
一個打電話和發短信示例
1. 佈局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.bean.myapplicationv0.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="電話號碼:"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.116"
app:layout_constraintVertical_bias="0.167"
android:id="@+id/textView2" />
<TextView
android:id="@+id/textView"
android:layout_width="78dp"
android:layout_height="20dp"
android:text="短信內容:"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="130dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintVertical_bias="0.07" />
<Button
android:id="@+id/bt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打電話"
android:onClick="myClick"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintVertical_bias="0.56" />
<Button
android:id="@+id/bt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發短信"
android:onClick="myClick"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintVertical_bias="0.717" />
<EditText
android:id="@+id/et1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text=""
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_bias="0.725"
app:layout_constraintVertical_bias="0.143" />
<EditText
android:id="@+id/et2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text=""
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_bias="0.725"
app:layout_constraintVertical_bias="0.271" />
</android.support.constraint.ConstraintLayout>
2. java文件
package com.example.bean.myapplicationv0;
import android.Manifest;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE, Manifest.permission.SEND_SMS},1);
//申請權限
}
public void myClick(View view){
EditText et1 = (EditText)findViewById(R.id.et1);
EditText et2 = (EditText)findViewById(R.id.et2);
Button btn = (Button)view;
Intent intent = new Intent();//新建對象
switch (btn.getId()){
case R.id.bt1:
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+ et1.getText().toString()));
break;
case R.id.bt2:
intent.setAction(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:"+ et1.getText().toString()));
intent.putExtra("sms_body",et2.getText().toString());
break;
}
startActivity(intent);//啓動Intent
}
}
3. 添加權限
在mainfest.xml中<application前面添加
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
BroadcastReceiver
Android四大組件之一,用於不同組件和多線程之間的通信。
標準廣播
標準廣播(Normal broadcasts):是一種完全異步執行的廣播,在廣播發出後,所有的廣播接收器幾乎都會在同一時間接收到這條廣播,沒有先後順序。
有序廣播
有序廣播(Ordered broadcasts):是一種同步執行的廣播,在廣播發出後,同一時刻只有一個廣播接收器能接收到廣播。有先後順序。
發佈廣播-自定義標準廣播示例:
public void myClick(View view){
Intent intent = new Intent();
intent.setAction("myBroadcast");
intent.setPackage("com.example.bean.myapplication00");
intent.putExtra("myMsg","Hello");
sendBroadcast(intent);
}
接收廣播-接受廣播示例:
myReceiver類
public class myReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,intent.getStringExtra("myMsg"),Toast.LENGTH_SHORT).show();
}
}
在mainfest.xml中下面
<receiver android:name=".myReceiver">
<intent-filter>
<action android:name="myBroadcast"/>
</intent-filter>
</receiver>
實現短消息提示示例
步驟:
創建BroadcastReceiver類的子類。
實現onReceive()方法。
配置AndroidManifest.xmI中的receiver。
action爲: “android.provider.Telephony.SMS_RECEIVED”
配置AndroidManifest.xml的短信接收許可:“android.permission.RECEIVE_SMS”
配置判斷主活動中是否授權了短信的接收許可,並申請短信接收許可。
New - Other - Broadcast Recerive新建MyReceiver
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
//throw new UnsupportedOperationException("Not yet implemented");
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED"))
Toast.makeText(context,"有短信到了!",Toast.LENGTH_SHORT).show();
}
}
權限
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
main.java判斷是否有權限
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECEIVE_SMS)!= PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.RECEIVE_SMS},1);
}
}
題目記錄
- Intent的ComponentName屬性主要是 C
- A.指明某一個包下的,要啓動的組件
- B.指明要啓動的組件對應的類
- C.用包名和類名唯一確定一個要啓動的組件
- D.指明要啓動的組件0.00
- 對於Intent的說法下列哪些是不對的 C 老師說改B
- A.是一個被動的數據結構 0000
- B.Android的四大組件都是通過Intent來激活的0.00
- C.intent保存了一個將要執行操作的抽象描述
- D.Intent是一個對象
- 下列哪個不是Intent常用的傳輸機制 D
- A.將一個Intent對象傳遞給任何廣播方法,都可以傳遞到所有感興趣的廣播接收者0.00
- B.將一個Intent對象傳遞給Context.startActivity()啓動一個活動
- C.將一個Intent對象傳遞給Context.startService()傳遞一個新指令給正在運行的Service
- D.將一個攜帶數據的Intent對象ContentProvider以提供開放的數據
- 對於Intent的Data屬性下列說法不正確的是 D
- A.可以向Activity傳遞一些額外鍵值對信息0.00
- B.Data是作用於Intent上的數據的URI和MIME類型 0000
- C.不同的動作有不同的數據規格
- D.可以使用setData()方法設置URI數據
- Intetn的Data屬性的數據類型可以是 D
- A.整型
- B.字符型
- C.實型
- D.MIME
- Intent的Category屬性是指 D
- A.Intent的分類0.00
- B.Intent的Action屬性分類
- C.Intent的Data屬性的分類
- D.作爲被執行動作的附加信息
- Intent的Extras屬性 D
- A.只是作爲留用一般不使用
- B.主要用於ContentProvider向外部提供信息
- C.只能使用Bundle傳遞額外的鍵值對信息
- D.可以傳遞額外的鍵值對信息
- 顯示Intent是指 D
- A.使用new關鍵字聲明的Intent
- B.在StartActivity中使用的Intent
- C.使用getIntent()方法獲得的Intent
- D.通過名稱指定目標組件的Intent
- 隱式Intent是指 B
- A.不指定Extra的Intent
- B.不指定目標名稱的Intent1.00/1.00
- C.不指定Action屬性的Intent
- D.不指定Category的Intent
- Intent過濾器不檢測的屬性是 C
- A.Data
- B.Action
- C.Extra1.00/1.00
- D.Category
- Intent的Action屬性 A
- A.很大程度上決定了Intent如何構建1.00/1.00
- B.與Intent其他屬性互不影響
- C.必須和Component屬性一同使用
- D.常用於組件的顯式啓動
- Intent有兩種形式其中一種是 A E
- A.顯式Intent1.00/1.00
- B.明確式Intent
- C.直接Intent
- D.聲明式Intent
- E.隱式Intent
- 對於Intent過濾器,下列說法正確的是: B
- A.在Activity的onCreate()方法中配置過濾器
- B.過慮器的標籤是1.00/1.00
- C.只能爲某組件設置一個過濾器
- D.過濾器只適用於隱式Intent
- 下列哪個不是Intent的功能? D
- A.用於啓動組件
- B.封裝了程序的啓動意圖
- C.交換數據
- D.只用於啓動Activity
- ComponentName屬性 A
- A.使用setClass方法設置1.00/1.00
- B.可以通過setComponentName()方法設置
- C.使用setComponentClass()方法設置
- D.使用Component的構造方法設置