2

基于下面的示例项目。(取自这里

为什么将字符串传递给构造函数BroadcastReceiver时会触发,而不是何时并传递给它?actionIntentContextSomeOtherActivity.class

           // this works
           Intent intent = new Intent(PROX_ALERT_INTENT);        

           //this does not
           Intent intent = new Intent(this, ProximityIntentReceiver.class);  
           intent.setAction(PROX_ALERT_INTENT);                             

ProximityAlertActivity.java:

package com.androidmyway.demo.proxymityalert;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;


public class ProximityAlertActivity extends Activity {
    private static final long POINT_RADIUS = 100; // in Meters
    private static final long PROX_ALERT_EXPIRATION = -1; // It will never expire
    private static final String PROX_ALERT_INTENT = "com.androidmyway.demo.ProximityAlert";
    private LocationManager locationManager;
    private EditText latitudeEditText;
    private EditText longitudeEditText;
    private Button addAlertButton;

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

            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

            latitudeEditText = (EditText) findViewById(R.id.point_latitude);
            longitudeEditText = (EditText) findViewById(R.id.point_longitude);
            addAlertButton = (Button) findViewById(R.id.add_alert_button);

            addAlertButton.setOnClickListener(new OnClickListener() {
                  public void onClick(View v) {
                         addProximityAlert();
                  }
            });

    }

    private void addProximityAlert() {
           double latitude = Double.parseDouble(latitudeEditText.getText().toString());
           double longitude = Double.parseDouble(longitudeEditText.getText().toString());
           //Intent intent = new Intent(PROX_ALERT_INTENT);           
           Intent intent = new Intent(this, ProximityIntentReceiver.class); 
           intent.setAction(PROX_ALERT_INTENT);
           PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 2, intent,         PendingIntent.FLAG_UPDATE_CURRENT);
           locationManager.addProximityAlert(
                  latitude, // the latitude of the central point of the alert region
                  longitude, // the longitude of the central point of the alert region
                  POINT_RADIUS, // the radius of the central point of the alert region, in meters
                  PROX_ALERT_EXPIRATION, // time for this proximity alert, in milliseconds, or -1 to     indicate no                           expiration
                  proximityIntent // will be used to generate an Intent to fire when entry to or exit from the alert region is detected
           );

           IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);
           registerReceiver(new ProximityIntentReceiver(), filter);
           Toast.makeText(getApplicationContext(),"Alert Added",Toast.LENGTH_SHORT).show();
    }    
}

ProximityIntentReceiver:

package com.androidmyway.demo.proxymityalert;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.location.LocationManager;
import android.util.Log;

public class ProximityIntentReceiver extends BroadcastReceiver {
    private static final int NOTIFICATION_ID = 1000;

    @SuppressWarnings("deprecation")
    @Override
    public void onReceive(Context context, Intent intent) {
        String key = LocationManager.KEY_PROXIMITY_ENTERING;
        Boolean entering = intent.getBooleanExtra(key, false);
        if (entering) {
            Log.d(getClass().getSimpleName(), "entering");
        }else {
            Log.d(getClass().getSimpleName(), "exiting");
        }
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        Intent notificationIntent = new Intent(context, ProximityAlertActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
        Notification notification = createNotification();
        notification.setLatestEventInfo(context, "Proximity Alert!", "You are near your point of interest.", pendingIntent);

        notificationManager.notify(NOTIFICATION_ID, notification);
    }

    private Notification createNotification() {
        Notification notification = new Notification();
        notification.icon = R.drawable.ic_launcher;
        notification.when = System.currentTimeMillis();
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        notification.flags |= Notification.FLAG_SHOW_LIGHTS;
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        notification.defaults |= Notification.DEFAULT_LIGHTS;
        notification.ledARGB = Color.WHITE;
        notification.ledOnMS = 1500;
        notification.ledOffMS = 1500;
        return notification;
    }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.androidmyway.demo.proxymityalert"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>


    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Black.NoTitleBar" >
        <activity
            android:name=".ProximityAlertActivity"
        >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
4

2 回答 2

4

结果我问了两个问题:

Q1:为什么BroadcastReceiver当一个Action字符串被传递给Intent构造函数时会触发而不是在Context传递SomeOtherActivity.class给它的时候触发?(我认为这是一个普遍的问题,而不仅仅是我发布的代码)

Q2:为什么BroadcastReceiver当一个Action字符串被传递给Intent构造函数时会触发而不是在Context传递NameOfReceiver.class给它的时候触发?(这是特定于我发布的代码,因为它使用了以编程方式注册的接收器)

       //this works
       Intent intent = new Intent(PROX_ALERT_INTENT);        

       //this does not
       Intent intent = new Intent(this, ProximityIntentReceiver.class);  
       intent.setAction(PROX_ALERT_INTENT); 

经过一些研究,我相信我有正确的答案:

ANS1:即使在调用构造函数之后Action手动添加一个仍然不会触发 BroadcastReceiver。Intents 上的Android 开发者页面给出了解释:Intentnew Intent(context, SomeOtherActivity.class)

" Android delivers an explicit intent to an instance of the designated target class. Nothing in the Intent object other than the component name matters for determining which component should get the intent."

因此手动添加一个Action无效。此外,一旦使用显式,可以在构造函数中Intent设置的唯一类就是您要显式调用的类。在这种情况下,通过任何其他类都没有意义。IntentBroadcastReceiver

这让我想到了ANS2

CommonsWare 对以下 SO 问题提供了非常明确的答案:

为什么即使我已经注册了警报,我也没有收到邻近变化?

问题是我正在以编程方式注册接收器。这迫使我使用IntentFilter. 如上所述,一旦使用显式Intent ,所有重要的是组件名称。我猜在动态注册接收器时,它正在侦听ActionIntentFilter而不是组件名称(接收器名称)中定义的。

使用显式Intent

Intent intent = new Intent(this, ProximityIntentReceiver.class); 

以及清单中的静态注册接收器:

<receiver android:name="ProximityIntentReceiver" />

解决了这个问题。

如果我对任何事情有误,请纠正我。

于 2013-09-27T00:14:06.437 回答
0

我相信,如果我错了,请纠正我,构造:

Intent intent = new Intent(this, SomeActivity.class); 

旨在启动另一个活动、意图服务或类似的,而不是用于广播。

这也是有道理的,因为其他应用程序可以接收广播,并且如果广播包含类引用,那么其他应用程序将没有机会调用那段代码。

上述意图构造的 Javadocs:

为特定组件创建意图。所有其他字段(操作、数据、类型、类)都是空的,尽管稍后可以通过显式调用对其进行修改。这提供了一种方便的方法来创建旨在执行硬编码类名的意图,而不是依赖系统为您找到合适的类;请参阅 setComponent(ComponentName) 以获取有关此影响的更多信息。

我看到您确实在之后设置了操作,但我认为在 Android 引擎盖下,无论如何,该意图仍然被认为是针对特定组件的。

于 2013-09-23T21:14:27.357 回答