2013-09-23 5 views
1

Основываясь на примере проекта ниже. (Взято из here)Конструктор намерений и BroadcastReceiver

Почему BroadcastReceiver огонь до когда action строка передается в Intent конструктор, но не тогда, когда Context и SomeOtherActivity.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> 

ответ

3

Оказывается, я задаю два вопроса:

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 вручную в Intent после вызова конструктора с new Intent(context, SomeOtherActivity.class) по-прежнему не будет запускать BroadcastReceiver. Android developers page on Intents дает объяснение:

"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."

Therefor вручную добавив Action не имеет никакого эффекта. Кроме того, после использования явного Intent единственным классом, который может быть установлен в конструкторе Intent, является класс BroadcastReceiver, который вы явно хотите вызвать. Передача любого другого класса в этом случае не имеет смысла.

Это подводит меня к ANS2:

CommonsWare предлагает очень четкий ответ на следующий вопрос: SO

Why don't I get proximity alterts even though I've registered alerts?

Проблема заключается в том, что я программно регистрации получателя. Это заставляет меня использовать IntentFilter. Как указано выше, после использования явного Intentвсе, что имеет значение, - это имя компонента. Я предполагаю, что при динамической регистрации приемника он прослушивает Action, определенный в IntentFilter вместо имени компонента (имя получателя).

Использование явного Intent:

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

вместе со статически зарегистрированном приемником в манифесте:

<receiver android:name="ProximityIntentReceiver" /> 

исправили проблему.

Пожалуйста, исправьте меня, если я ошибаюсь.

0

Я считаю, поправьте меня, если я ошибаюсь, что строительство:

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

Предназначена для запуска другой деятельности, намерения или услуги похоже, не для вещания.

Это также имеет смысл по той причине, что другие приложения могут получать трансляции, и если в трансляции содержится ссылка на класс, то у этого другого приложения не будет возможности называть этот фрагмент кода.

Javadocs для вышеуказанного намерения строительства:

Создать намерение для конкретного компонента. Все остальные поля (действие, данные, тип, класс) являются нулевыми, хотя впоследствии они могут быть изменены с явными вызовами. Это обеспечивает удобный способ создания намерения, предназначенного для выполнения жестко закодированного имени класса, вместо того, чтобы полагаться на систему, чтобы найти подходящий класс для вас; см. setComponent (ComponentName) для получения дополнительной информации о последствиях этого.

Я вижу, что вы устанавливаете действие впоследствии, но я думаю, что под капотом Android это намерение по-прежнему считается для какого-то конкретного компонента.

+0

Это имеет смысл. Но что конкретно происходит под капотом, что вызывает это? – Vandermonde

Смежные вопросы