Android开发- Intent和Broadcast Receiver

Intent是一种消息传递机制,可以在应用程序内使用,也可以在应用程序间使用。可以用于:

  • 使用类名显示启动一个特定的Service或者Activity。
  • 启动Activity或者Service来执行一个动作的Intent,通常需要使用特定的数据,或者对特定的数据执行动作。
  • 广播某个时间已经发生。

使用Intent来启动Activity

显式启动新的Activity

    Intent intent = new Intent(MyActivity.this, SelectHorseActivity.class);
    startActivity(intent); 

调用startActivity之后,新的Activity会被创建、启动和恢复运行,它会移动到Activity栈的顶部。

调用新的Activity的finish或按下设备的返回按钮将关闭该Activity,并把它从栈中移除。

隐式的Intent和运行时迟绑定

隐式的Intent提供了一种机制,可以让匿名的应用程序组件响应动作请求。这意味着可以要求系统启动一个可执行给定动作的Activity,而不必知道需要启动哪个应用程序或者Activity。

例如希望让用户从应用程序中拨打电话,那么可以实现一个新的拨号程序,也可以使用一个隐式的Intent来请求一个在电话号码(表示为一个URI)上执行动作。

// Create the implicit Intent to use to start a new Activity.
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:555-2368"));

startActivity(intent);

当构建一个新的隐式的Intent时,需要指定一个要执行的动作,另外,也可以提供执行那个动作需要的数据的URI。还可以通过向Intent添加extra来向目标Activity发送额外的数据。

Extra是一种向Intent附加基本类型值的机制。可以在任何Intent上使用重载后的putExtra方法来附加一个新的键值对,以后在启动的Activity中使用对于的getExtra方法来检索它。

确定Intent能否解析

在调用startActivity之前,确定调用是否可以解析为一个Activity是一种很好的做法。通过调用Intent的resolveActivity方法,并向该方法传入包管理器,可以对包管理器进行查询,确定是否有Activity能够启动以响应该Intent。

    if (somethingWeird && itDontLookGood) {
      // Create the implicit Intent to use to start a new Activity.
      Intent intent =
        new Intent(Intent.ACTION_DIAL, Uri.parse("tel:555-2368"));

      // Check if an Activity exists to perform this action.
      PackageManager pm = getPackageManager();
      ComponentName cn = intent.resolveActivity(pm);
      if (cn == null) {
        // If there is no Activity available to perform the action
        // Check to see if the Market is available.
        Uri marketUri =
          Uri.parse("market://search?q=pname:com.myapp.packagename");
        Intent marketIntent = new
          Intent(Intent.ACTION_VIEW).setData(marketUri);

        // If the Market is available, use it to download an application
        // capable of performing the required action. Otherwise log an
        // error.
        if (marketIntent.resolveActivity(pm) != null)
          startActivity(marketIntent);
        else
          Log.d(TAG, "Market client not available.");
      }
      else
        startActivity(intent);
    } 

从Activity返回结果

通过startActivity启动的Activity独立于其父Activity,并且在关闭时不会提供任何反馈。

当需要反馈时,可以启动一个Activity作为另一个Activity的子Activity,用它向父Activity传递结果。子Activity只是以一种不同的方式启动的Activity。因此,必须在应用程序的manifest文件中注册它们,就像其他任何Activity一样。在manifest文件中注册的任何Activity都可以作为子Activity打开,包括系统Activity或者第三方应用程序的Activity。

当子Activity结束时,它会触发调用Activity内的事件处理程序onActivityResult。

启动子Activity

显示启动一个子Activity以返回结果

  private static final int SHOW_SUBACTIVITY = 1;

  private void startSubActivity() {
    Intent intent = new Intent(this, MyOtherActivity.class);
    startActivityForResult(intent, SHOW_SUBACTIVITY);
  }

隐式启动一个子Activity以返回结果

  private static final int PICK_CONTACT_SUBACTIVITY = 2;

  private void startSubActivityImplicitly() {
    Uri uri = Uri.parse("content://contacts/people");
    Intent intent = new Intent(Intent.ACTION_PICK, uri);
    startActivityForResult(intent, PICK_CONTACT_SUBACTIVITY);
  }

返回结果

当准备好返回子Activity时,可以在调用finish以前调用setResult,以便向调用Activity返回一个结果。

setResult方法有两个参数:结果码和表示为Intent的结果数据本身。

结果码是运行子Activity的结果-通常是Activity.RESULT_OK或者Activity.RESULT_CANCELED。在某些情况下,当OK和CANCELED不足以精确描述可用的返回结果时,可以使用自己的响应码来处理应用程序特定的选择;setResult支持任意的整数值。

作为结果返回的Intent通常包含某段内容的URI和用于返回附加信息的一组extra。

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.selector_layout);

    final ListView listView = (ListView)findViewById(R.id.listView1);

    Button okButton = (Button) findViewById(R.id.ok_button);
    okButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        long selected_horse_id = listView.getSelectedItemId();

        Uri selectedHorse = Uri.parse("content://horses/" +
                                       selected_horse_id);
        Intent result = new Intent(Intent.ACTION_PICK, selectedHorse);

        setResult(RESULT_OK, result);
        finish();
      }
    });

    Button cancelButton = (Button) findViewById(R.id.cancel_button);
    cancelButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        setResult(RESULT_CANCELED);
        finish();
      }
    });
  }

如果用户通过按下硬件返回键关闭Activity,或者在调用finish之前没有调用setResult,那么结果码将被设为RESULT_CANCELED,结果Intent将被设为null。

处理子Activity结果

当一个子Activity关闭的时候,它会触发其调用Activity的onActivityResult事件处理程序。

onActivityResult接受多个参数:

  • 请求码 启动正在返回的子Activity时使用的请求码
  • 结果码 子Activity设置的结果码,用来说明其结果
  • 数据 Intent用来包装所有返回的数据。
  private static final int SELECT_HORSE = 1;
  private static final int SELECT_GUN = 2;

  Uri selectedHorse = null;
  Uri selectedGun = null;

  @Override
  public void onActivityResult(int requestCode,
                               int resultCode,
                               Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    switch(requestCode) {
      case (SELECT_HORSE):
        if (resultCode == Activity.RESULT_OK)
          selectedHorse = data.getData();
        break;

      case (SELECT_GUN):
        if (resultCode == Activity.RESULT_OK)
          selectedGun = data.getData();
        break;

      default: break;
    }
  }

原生Android动作  

Standard Activity Actions



Linkify

Linkify是一个辅助类,它会自动地在TextView类(或者TextView的派生类)中通过RegEx模式匹配来创建超链接。

那些匹配一个制定的RegEx模式的文本都将会被转换为一个可以单击的超链接,这些超链接可以隐式使用匹配的文本作为目标URI来触发startActivity(new Intent(Intent.ACTION_VIEW,uri))。

可以制定任何字符串模式来作为可单击连接的处理;

原生Linkify链接类型

final TextView myTextView = (TextView)findViewById(R.id.text_view);
Linkify.addLinks(myTextView, Linkify.WEB_URIS|Linkify.EMAIL_ADDRESSES);

或者

  <TextView
    android:id="@+id/text_view"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    android:autoLink="phone|email"
/>

创建定制的链接字符串

要为自己的数据建立链接,需要定义自己的linkify字符串,可以通过创建一个新的RegEx模式来匹配希望显示为超链接的文本。

和本地类型一样,可以通过调用Linkify.addLinks来为目标TextView建立链接,只不过这次传入的是RegEx模式,而不是预设的常量。也可以给它传递一个前缀,当单击链接时,该前缀将会被添加到目标URI的前面。

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final TextView myTextView = (TextView)findViewById(R.id.text_view);

     // Define the base URI.
     String baseUri = "content://com.paad.earthquake/earthquakes/";

     // Contruct an Intent to test if there is an Activity capable of
     // viewing the content you are Linkifying. Use the Package Manager
     // to perform the test.
     PackageManager pm = getPackageManager();
     Intent testIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(baseUri));
     boolean activityExists = testIntent.resolveActivity(pm) != null;

     // If there is an Activity capable of viewing the content
     // Linkify the text.
     if (activityExists) {
       int flags = Pattern.CASE_INSENSITIVE;
       Pattern p = Pattern.compile("\\bquake[\\s]?[0-9]+\\b", flags);
       Linkify.addLinks(myTextView, p, baseUri);
     }
  }


使用Intent广播事件

作为一个系统级的消息传递机制,Intent可以在进程间发送结构化的消息。因此,可以通过实现Boradcast Receiver来监听和响应应用程序内的这些Broadcast Intent。

Broadcast Intent用于向监听器通知系统的应用程序或应用程序事件,从而可以扩展应用程序间的事件驱动的编程模型。

Broadcast Intent可以使应用程序更加开放;通过使用Intent来广播一个事件,可以在不用修改原始应用程序的情况下,让你和第三方开发人员对事件做出反应。在应用程序中,可以通过监听Broadcast Intent来对设备状态变化和第三方应用程序事件做出反应。

使用Intent来广播事件

在应用程序组件中,可以构建希望广播的Intent,然后使用sendBroadcast方法来发送它。

  public final static String EXTRA_LIFEFORM_NAME  = "EXTRA_LIFEFORM_NAME";
  public final static String EXTRA_LATITUDE = "EXTRA_LATITUDE";
  public final static String EXTRA_LONGITUDE = "EXTRA_LONGITUDE";

  public static final String ACTION_BURN = "com.paad.alien.action.BURN_IT_WITH_FIRE";

  public static final String NEW_LIFEFORM = "com.paad.alien.action.NEW_LIFEFORM";

  //
  private void detectedLifeform(String detectedLifeform, double currentLongitude, double currentLatitude) {
    Intent intent = new Intent(NEW_LIFEFORM);
    intent.putExtra(EXTRA_LIFEFORM_NAME,
                    detectedLifeform);
    intent.putExtra(EXTRA_LONGITUDE,
                    currentLongitude);
    intent.putExtra(EXTRA_LATITUDE,
                    currentLatitude);

    sendBroadcast(intent);
  }

使用Broadcast Receiver来监听广播

要使Broadcast Receiver能够接收广播,就需要对其进行注册,既可以使用代码,也可以在应用程序的manifest文件中注册(此时成为manifest接收器)。无论怎么注册,都需要使用一个Intent Filter来指定它要监听哪些Intent和数据。

对于包含manifest接收器的应用程序,在Intent被广播出去的时候,应用程序不一定非要处于运行状态才能执行接收。当匹配的Intent被广播出去的时候,它们会被自动的启动。

public class LifeformDetectedReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the lifeform details from the intent.
  }
}

onReceive处理程序必须在5秒钟内完成,否则就会显示Force Close对话框。

一般情况下,Broadcast Receiver将会更新内容、启动Service、更新Activity UI,或者使用Notification Manager来通知用户。5秒钟的执行限制保证了主要的处理工作不能够、也不应该有Broadcast Receiver直接完成。

public class LifeformDetectedReceiver
  extends BroadcastReceiver {

  public final static String EXTRA_LIFEFORM_NAME = "EXTRA_LIFEFORM_NAME";
  public final static String EXTRA_LATITUDE = "EXTRA_LATITUDE";
  public final static String EXTRA_LONGITUDE = "EXTRA_LONGITUDE";

  public static final String ACTION_BURN = "com.paad.alien.action.BURN_IT_WITH_FIRE";

  public static final String NEW_LIFEFORM = "com.paad.alien.action.NEW_LIFEFORM";

  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the lifeform details from the intent.
    Uri data = intent.getData();
    String type = intent.getStringExtra(EXTRA_LIFEFORM_NAME);
    double lat = intent.getDoubleExtra(EXTRA_LATITUDE, 0);
    double lng = intent.getDoubleExtra(EXTRA_LONGITUDE, 0);
    Location loc = new Location("gps");
    loc.setLatitude(lat);
    loc.setLongitude(lng);
    if (type.equals("facehugger")) {
      Intent startIntent = new Intent(ACTION_BURN, data);
      startIntent.putExtra(EXTRA_LATITUDE, lat);
      startIntent.putExtra(EXTRA_LONGITUDE, lng);

      context.startService(startIntent);
    }
  }
}

在代码中注册Broadcast Receiver

在代码中注册的接收器只会在包含它的应用程序组件运行时响应Broadcast Intent。

public class MyActivity extends Activity {

  private IntentFilter filter = new IntentFilter(LifeformDetectedReceiver.NEW_LIFEFORM);

  private LifeformDetectedReceiver receiver = new LifeformDetectedReceiver();

  @Override
  public synchronized void onResume() {
    super.onResume();

    // Register the broadcast receiver.
    registerReceiver(receiver, filter);
  }

  @Override
  public synchronized void onPause() {
    // Unregister the receiver
    unregisterReceiver(receiver);  

    super.onPause();
  }
}

在应用程序的manifest中注册Broadcast Receiver

广播有序的Intent sendOrderedBroadcast

广播Sticky Intent

Sticky Intent是Broadcast Intent的有用变体,可以保存它们最后一次广播的值,并且当有一个新的接收器被注册为接收该广播时,它们会把这些值作为Intent返回。

要广播自己的Sticky Intent,应用程序必须具有BROADCAST_STICKY用户权限,然后需要调用sendStickyBroadcast并传入相关的Intent。

要删除一个Sticky Intent,可以调用removeStickyBroadcast,并传入要删除的Sticky Intent。

Local Broadcast Manager

Local Broadcast Manager(局部广播管理器)包含在Android Support Library中,用于简化注册Broadcast Intent,以及在应用程序内的组件之间发送Broadcast Intent的工作。

局部广播的作用域要小一些,所以使用Local Broadcast Manager比发送全局广播更加高效。而且使用Local Broadcast Manager也确保了应用程序外部的任何组件都收不到你广播的Intent,所以不会有私人数据或敏感数据泄露出去的风险。

        //注册一个局部Broadcaset Receive
        LocalBroadcastManager lbm=LocalBroadcastManager.getInstance(this);
        lbm.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                //TODO
            }
        },new IntentFilter(LOCAL_ACTION));

        //发送局部Broadcast Intent
        lbm.sendBroadcast(new Intent(LOCAL_ACTION));

        lbm.sendBroadcastSync(new Intent(LOCAL_ACTION));

Pending Intent

PendingIntent类提供了一种创建可由其他应用程序在稍晚的时间触发的Intent的机制。

创建Intent Filter和Broadcast Receiver

使用Intent Filter为隐式Intent提供服务

通过使用Intent Filter,应用程序组件可以声明它们支持的动作和数据。

要把一个Activity或者Service注册为一个可能的Intent处理程序,可以在它的manifest节点中添加一个intent-filter标签并使用下面的标签

  • action 使用android:name属性指定要为之服务的动作的名称。每个Intent Filter必须要有至少一个action标签。
  • category 使用android:name属性来制定应该在哪种情况下为action提供服务。每个IntentFilter标签可以包含多个category标签。既可以制定自己的category也可以使用Android提供的标准值。
  • data data标签允许制定组件可以执行的数据类型;根据情况,也可以包含多个数据标签。可以使用以下属性的任意组合来制定你的组件所支持的数据:
    •   android:host 指定一个有效的主机名
    •   android:mimetype 制定组件可以执行的数据类型。
    •   android:path 指定URI的有效路径值。
    •   android:port 指定主机的有效端口
    •   android:scheme 要求一种特定的模式

在以下的例子中,以http://blog.radioactiveyak.com形式开头的链接都将由这个Activity来处理。

    <activity android:name=".MyBlogViewerActivity">
      <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="http"
              android:host="blog.radioactiveyak.com"/>
      </intent-filter>
    </activity>

监听电量变化

想要在一个Activity中监听电池电量或者充电状态的变化,可以使用Intent Filter注册一个Receiver来实现,该Intent Filter通过Battery Manager来监听Intent.ACTION_BATTERY_CHANGED广播。

包含当前电池电量和充电状态的Broadcast Intent是一个sticky Intent,因此不需要实现一个Broadcast Receiver就可以在任何时间获取到当前的电池状态。

    IntentFilter batIntentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    Intent battery = context.registerReceiver(null, batIntentFilter);
    int status = battery.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
    boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;

监听链接变化

获取当前链接状态的详细信息,需要使用Connectivity Manager。

    String svcName = Context.CONNECTIVITY_SERVICE;
    ConnectivityManager cm = (ConnectivityManager)context.getSystemService(svcName);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    boolean isConnected = activeNetwork.isConnectedOrConnecting();
    boolean isMobile = activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE;

监听Dock变化

Android设备可以放在一个汽车的dock上或者桌子的dock上。通过注册一个Recevier来监听Intent.ACTION_DOCK_EVENT,可以确定docking的状态和类型。

和电池状态一样,dock事件的Broadcast Intent也是sticky的。

以下示例显示了当注册了一个监听dock事件的Receiver后,如何从返回的Intent中获得当前的docking状态。

    IntentFilter dockIntentFilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
    Intent dock = context.registerReceiver(null, dockIntentFilter);

    int dockState = dock.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED );
    boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;

在运行时管理Manifest Receiver

使用Package Manager的setComponentEnabledSetting方法,可以在运行时启动和禁用应用程序的manifest Receiver。

想要减少应用程序的开销,当应用程序不需要响应一些系统事件时,最好禁用监听这些常见系统时间的manifest Receiver。这项技术也能够让你定时执行一个基于系统事件的动作-如当设备链接到Wi-Fi时去下载一个大文件-而不用考虑每次应用程序启动后链接改变时广播的开销。

以下示例显示了如何在运行时启用和禁用一个manifest Receiver。

    ComponentName myReceiverName = new ComponentName(this, MyReceiver.class);
    PackageManager pm = getPackageManager();

    // Enable a manifest receiver
    pm.setComponentEnabledSetting(myReceiverName,
      PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
      PackageManager.DONT_KILL_APP);

    // Disable a manifest receiver
    pm.setComponentEnabledSetting(myReceiverName,
      PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
      PackageManager.DONT_KILL_APP);

    // View Output
    Log.d(TAG, "Is Charging? " + isCharging);
    Log.d(TAG, "Is Connected? " + isConnected);
    Log.d(TAG, "Is Mobile? " + isMobile);
    Log.d(TAG, "Is Docked? " + isDocked);
时间: 2024-08-02 19:28:44

Android开发- Intent和Broadcast Receiver的相关文章

【Android的从零单排开发日记】之入门篇(六)——Android四大组件之Broadcast Receiver

广播接受者是作为系统的监听者存在着的,它可以监听系统或系统中其他应用发生的事件来做出响应.如设备开机时,应用要检查数据的变化状况,此时就可以通过广播来把消息通知给用户.又如网络状态改变时,电量变化时都可以通过广播来通知用户.要做比喻的话,广播就像是我们的感官,能够有效且快速的从外界获取信息来反馈给自身. 一.广播的功能和特征 广播的生命周期很短,经过 调用对象—实现onReceive—结束 整个过程就结束了.从实现的复杂度和代码量来看,广播无疑是最迷你的Android 组件,实现往往只需几行代码

android 之 Intent、broadcast

Intent的功能有: 在mainActivity中为按钮1添加监听事件: listener1 = new OnClickListener() { @Override    public void onClick(View v) {        // TODO Auto-generated method stub       Intent intent1 = new Intent(mainActivity.this, Activity1.class);        intent1.putEx

Broadcast Intent 和Broadcast Receiver的使用

package tw.android; import android.app.Activity; import android.content.*; import android.os.Bundle; import android.view.View; import android.widget.Button; public class Main extends Activity { private Button mBtnRegReceiver, mBtnUnregReceiver, mBtnS

Android开发Intent应用概述

原文: http://bbs.gfan.com/android-93448-1-1.html 今天,我们来研究一下Intent,没错,就是前面说过的比较难理解的那个东西,希望通过这篇文章之后,你发现前面那句话其实是不对的.前文中说过,Intent就像Activity之间的双面胶,就字面意思而言:“意图, 意向, 目的”, 基本上可以诠释这个对象的作用.它里面包含的就是一些信息,这些信息能够告诉我们当前发生了什么,以及想要干什么.我觉得和前面的事件驱动中的事件非常 像,不同的是,它不仅仅包含事件,

Android 四大组件 之 Broadcast/Receiver 流程

下图描述了在source application中broadcast一个intent,注册此intent的Target Application如何启动和接收的流程. The picture above is the flow chart for how the source Application broadcast an intent (1) Inform AMS to broadcast the intent, in blue; (2) AMS searched all registered

Android开发--Intent的使用

1.概述 Intent负责对应用中一次操作的动作,动作涉及的数据,附加的数据进行描述,起到媒介的作用.通过Intent对象指定一个activity,利用startActivity或 startActivityForResult方法启动另一个activity.另外,Intent可以实现数据在不同activity之间的跳转. 2.activity跳转示意图 3.创建Intent对象 3.1在原先的activity.java文件中创建Intent对象 注:Intent(originactivity.t

Android面试收集录2 Broadcast Receiver详解

1.Broadcast Receiver广播接收器简单介绍 1.1.定义 Broadcast Receiver(广播接收器),属于Android四大组件之一 在Android开发中,Broadcast Receiver的应用场景非常多.广播,是一个全局的监听器,属于Android四大组件. Android 广播分为两个角色:广播发送者,广播接收者. 1.2.作用 用于监听/接收 应用发出的广播消息,并做出响应. 应用场景 a.不同组件之间通信(包括应用内/不同应用之间) b.与Android系统

Android中Intent详解(二)之使用Intent广播事件及Broadcast Receiver简介

通过第一篇的讲解,我们已经看到了如何使用Intent来启动新的应用程序组件,但是实际上他们也可以使用sendBroadcast方法来在组件间匿名的广播消息. 作为一个系统级别的消息传递机制,Intent可以在进程之间发送结构化的消息.因此,通过实现Broadcast Receiver来监听和响应应用程序内的这些Broadcast Intent. 通过使用Intent来广播一个事件,可以在不修改原始的应用程序的情况下,让我们开发人员对事件做出反应.Android大量使用了Broadcast Rec

Android中Intent具体解释(二)之使用Intent广播事件及Broadcast Receiver简单介绍

通过第一篇的解说,我们已经看到了怎样使用Intent来启动新的应用程序组件,可是实际上他们也能够使用sendBroadcast方法来在组件间匿名的广播消息. 作为一个系统级别的消息传递机制,Intent能够在进程之间发送结构化的消息. 因此,通过实现Broadcast Receiver来监听和响应应用程序内的这些Broadcast Intent. 通过使用Intent来广播一个事件,能够在不改动原始的应用程序的情况下.让我们开发者对事件做出反应.Android大量使用了Broadcast Rec