【android編程】第八講-Intent和BroadcastReceiver

第八講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的其他部分是如何構造的,尤其是 dataextras域。(就好像函數名會決定着參數值和返回值一樣。)所以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);
    }
}

題目記錄

  1. Intent的ComponentName屬性主要是 C
    • A.指明某一個包下的,要啓動的組件
    • B.指明要啓動的組件對應的類
    • C.用包名和類名唯一確定一個要啓動的組件
    • D.指明要啓動的組件0.00
  2. 對於Intent的說法下列哪些是不對的 C 老師說改B
    • A.是一個被動的數據結構 0000
    • B.Android的四大組件都是通過Intent來激活的0.00
    • C.intent保存了一個將要執行操作的抽象描述
    • D.Intent是一個對象
  3. 下列哪個不是Intent常用的傳輸機制 D
    • A.將一個Intent對象傳遞給任何廣播方法,都可以傳遞到所有感興趣的廣播接收者0.00
    • B.將一個Intent對象傳遞給Context.startActivity()啓動一個活動
    • C.將一個Intent對象傳遞給Context.startService()傳遞一個新指令給正在運行的Service
    • D.將一個攜帶數據的Intent對象ContentProvider以提供開放的數據
  4. 對於Intent的Data屬性下列說法不正確的是 D
    • A.可以向Activity傳遞一些額外鍵值對信息0.00
    • B.Data是作用於Intent上的數據的URI和MIME類型 0000
    • C.不同的動作有不同的數據規格
    • D.可以使用setData()方法設置URI數據
  5. Intetn的Data屬性的數據類型可以是 D
    • A.整型
    • B.字符型
    • C.實型
    • D.MIME
  6. Intent的Category屬性是指 D
    • A.Intent的分類0.00
    • B.Intent的Action屬性分類
    • C.Intent的Data屬性的分類
    • D.作爲被執行動作的附加信息
  7. Intent的Extras屬性 D
    • A.只是作爲留用一般不使用
    • B.主要用於ContentProvider向外部提供信息
    • C.只能使用Bundle傳遞額外的鍵值對信息
    • D.可以傳遞額外的鍵值對信息
  8. 顯示Intent是指 D
    • A.使用new關鍵字聲明的Intent
    • B.在StartActivity中使用的Intent
    • C.使用getIntent()方法獲得的Intent
    • D.通過名稱指定目標組件的Intent
  9. 隱式Intent是指 B
    • A.不指定Extra的Intent
    • B.不指定目標名稱的Intent1.00/1.00
    • C.不指定Action屬性的Intent
    • D.不指定Category的Intent
  10. Intent過濾器不檢測的屬性是 C
    • A.Data
    • B.Action
    • C.Extra1.00/1.00
    • D.Category
  11. Intent的Action屬性 A
    • A.很大程度上決定了Intent如何構建1.00/1.00
    • B.與Intent其他屬性互不影響
    • C.必須和Component屬性一同使用
    • D.常用於組件的顯式啓動
  12. Intent有兩種形式其中一種是 A E
    • A.顯式Intent1.00/1.00
    • B.明確式Intent
    • C.直接Intent
    • D.聲明式Intent
    • E.隱式Intent
  13. 對於Intent過濾器,下列說法正確的是: B
    • A.在Activity的onCreate()方法中配置過濾器
    • B.過慮器的標籤是1.00/1.00
    • C.只能爲某組件設置一個過濾器
    • D.過濾器只適用於隱式Intent
  14. 下列哪個不是Intent的功能? D
    • A.用於啓動組件
    • B.封裝了程序的啓動意圖
    • C.交換數據
    • D.只用於啓動Activity
  15. ComponentName屬性 A
    • A.使用setClass方法設置1.00/1.00
    • B.可以通過setComponentName()方法設置
    • C.使用setComponentClass()方法設置
    • D.使用Component的構造方法設置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章