J'ai rencontré un problème sur Android 4.0.3 (sur 4.1.2 cela fonctionne très bien) . J'ai dans mon activité BroadcastReceiver. Lorsque j'envoie une diffusion, la méthode onReceive () appelle toujours deux fois. Donnez-moi des suggestions sur les différences entre BroadcastReceiver 4.0 et 4.1
private final GcmBroadcastReceiver gcmReceiver = new GcmBroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action != null && action.equals(MyBroadcastReceiver.ACTION)) {
Log.d("tag", intent.getStringExtra("alert"));
}
}
};
};
@Override
protected void onPause() {
unregisterReceiver(gcmReceiver);
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
registerGcmReceiver();
}
private void registerGcmReceiver() {
IntentFilter filter = new IntentFilter(MyBroadcastReceiver.ACTION);
filter.setPriority(2);
filter.addCategory("com.Android.mypackage");
registerReceiver(gcmReceiver, filter);
}
Réponse courte: il n'y a pas de différence. La classe BroadcastReceiver
pour les deux est à partir d'Android 2.3.2 r1.
J'ai eu un problème similaire, mais pour moi c'était avec un HTC Desire HD avec Android 2.3.5 dessus - les notifications de GCM seraient toujours reçues deux fois. Je n'ai pas réussi à trouver la racine du problème, mais il existe une solution de contournement. Vous pouvez générer un identifiant unique pour chaque notification du serveur et l'envoyer avec les données réelles. Ensuite, dans votre récepteur, vous pouvez mettre à jour un mappage d'identifiant unique en données de notification. S'il existe déjà des données pour cet identifiant, ignorez-le.
Je n'ai probablement pas été très clair, alors voici un exemple:
public void onReceive(Context context, Intent intent) {
String id = intent.getStringExtra("notificationID");
if (myMap.get(id) != null)
return;
final String action = intent.getAction();
if (action != null && action.equals(MyBroadcastReceiver.ACTION)) {
Log.d("tag", intent.getStringExtra("alert"));
myMap.put(id, *any value you need*);
}
}
Si vous n'avez pas besoin de stocker des données supplémentaires, vous pouvez utiliser un HashSet au lieu d'une Map et vérifier s'il contient l'ID.
J'ai eu le même problème.
onReceive()
est appelé deux fois parce que j’enregistrais deux fois le récepteur de radiodiffusion. Un dans onCreate()
de mon activité et un autre dans manifest
.
Je supprime l'enregistrement de récepteur de diffusion de onCreate()
et tout fonctionne correctement. Enregistrez votre récepteur de radiodiffusion dans un seul d'entre eux.
Il y a deux façons de faire ça:
La méthode (statique ou dynamique) à utiliser quand dépend totalement de ce que vous essayez de faire. Fondamentalement, lorsque vous souhaitez apporter des modifications directement à l'écran (écran d'accueil, launcher, barre d'état, etc.) en affichant une notification ou un indicateur dans la barre d'état en écoutant les événements à l'échelle du système ou peut-être ceux envoyés par d'autres applications, il est alors logique d'utiliser des récepteurs de diffusion enregistrés statiquement. Tandis que, sur la base d’événements similaires, vous souhaitez modifier directement votre application lorsque l’utilisateur l’utilise ou le place en arrière-plan, il est judicieux d’utiliser des récepteurs enregistrés de manière dynamique qui dureront jusqu’à la destruction des composants d’enregistrement.
Pour plus d'informations: http://codetheory.in/Android-broadcast-receivers/
Inatialisez BroadcastReciver
sur onStart()
. Cela corrige mon problème.
Vous pouvez également l'implémenter en définissant un indicateur booléen lorsque vous entrez dans la fonction onReceive()
J'appelais sendBroadcast(intent)
plusieurs fois dans ma classe de service
Supprimer l'un d'eux corrige le problème.
Je pense que c'est la bonne façon de déterminer si le Wifi est connecté ou déconnecté.
La méthode onReceive () dans BroadcastReceiver: Il suffit de mettre une simple vérification (c'est une logique implémentée par SharedPreferences):
package com.example.broadcasttest;
import Java.util.List;
import Java.util.Random;
import Android.app.Activity;
import Android.app.ActivityManager;
import Android.app.ActivityManager.RunningTaskInfo;
import Android.content.BroadcastReceiver;
import Android.content.ComponentName;
import Android.content.Context;
import Android.content.Intent;
import Android.content.SharedPreferences;
import Android.util.Log;
import Android.widget.Toast;
public class CustomReceiver extends BroadcastReceiver {
boolean isInternetPresent = false;
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
ActivityManager am = (ActivityManager) context
.getSystemService(Activity.ACTIVITY_SERVICE);
String packageName = am.getRunningTasks(1).get(0).topActivity
.getPackageName();
@SuppressWarnings("deprecation")
List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
if(packageName.equals("com.example.broadcasttest") && taskInfo.get(0).topActivity.getClassName().toString().equals("com.example.broadcasttest.MainActivity"))
{
// SharedPreferences sharedPreferences=context.getSharedPreferences("FLAG", Context.MODE_PRIVATE);
// String check=sharedPreferences.getString("check","");
ConnectionDetector cd = new ConnectionDetector(context);
// get Internet status
isInternetPresent = cd.isConnectingToInternet();
// check for Internet status
if (isInternetPresent) {
SharedPreferences sharedPreferences=context.getSharedPreferences("FLAG", Context.MODE_PRIVATE);
String check=sharedPreferences.getString("check","");
if(check.equals("chkd1")){
Log.d("activity name", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName()+" Package Name : "+componentInfo.getPackageName());
String abc = context.getClass().toString();
Toast.makeText(context, "hiiii "+abc, Toast.LENGTH_SHORT).show();
Log.e("ghorar kochu", "checking:");
MainActivity m = new MainActivity();
m.abc(context);
}
else if(check.equals("chkd"))
{
Log.e("Thanks For the checking", "checking:"+check);
}
}
else if (!isInternetPresent) {
SharedPreferences sharedPreferences1=context.getSharedPreferences("FLAG", Context.MODE_PRIVATE);
SharedPreferences.Editor editor1=sharedPreferences1.edit();
editor1.putString("check","chkd1");
editor1.commit();
}
}
}
}
Il s’agit de la classe de récepteurs réelle.A présent, passe à l’activité principale.
package com.example.broadcasttest;
import Java.net.URLEncoder;
import Java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import Android.app.Activity;
import Android.content.Context;
import Android.content.Intent;
import Android.content.SharedPreferences;
import Android.os.AsyncTask;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.Menu;
import Android.view.MenuItem;
import Android.view.View;
import Android.view.View.OnClickListener;
import Android.widget.Button;
import Android.widget.ListView;
import Android.widget.Toast;
public class MainActivity extends Activity {
Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences1=getSharedPreferences("FLAG", Context.MODE_PRIVATE);
SharedPreferences.Editor editor1=sharedPreferences1.edit();
editor1.putString("check","chkd1");
editor1.commit();
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent in =new Intent(MainActivity.this,Second.class);
startActivity(in);
}
});
}
public void abc(Context context){
try{
SharedPreferences sharedPreferences1=context.getSharedPreferences("FLAG", Context.MODE_PRIVATE);
SharedPreferences.Editor editor1=sharedPreferences1.edit();
editor1.putString("check","chkd");
editor1.commit();
}
catch(NullPointerException e)
{
e.printStackTrace();
}
new JsonForTimeLineList().execute();
}
class JsonForTimeLineList extends AsyncTask<Void, Void, Void> {
private String msg = null;
@Override
protected void onPreExecute() {
super.onPreExecute();
// pDialog.show();
}
@Override
protected Void doInBackground(Void... params) {
return null;
}
@Override
protected void onPostExecute(Void resultaaa) {
Log.e("hi", "helo");
}
}
}
Ce code ne fonctionne que lorsque votre application est à l'état de résumé et dans MainActivity.
Voici ma classe ConnectionDetector. Au travers de laquelle je vérifie la connexion du wifi.
package com.example.broadcasttest;
import Android.app.AlertDialog;
import Android.content.Context;
import Android.content.DialogInterface;
import Android.net.ConnectivityManager;
import Android.net.NetworkInfo;
public class ConnectionDetector {
private Context _context;
public ConnectionDetector(Context context){
this._context = context;
}
public boolean isConnectingToInternet(){
ConnectivityManager connectivity = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null)
{
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null)
for (int i = 0; i < info.length; i++)
if (info[i].getState() == NetworkInfo.State.CONNECTED)
{
return true;
}
}
return false;
}
}
Et voici mon manifeste.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
package="com.example.broadcasttest"
Android:versionCode="1"
Android:versionName="1.0" >
<uses-sdk
Android:minSdkVersion="8"
Android:targetSdkVersion="21" />
<uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE" />
<uses-permission Android:name="Android.permission.INTERNET" />
<application
Android:allowBackup="true"
Android:icon="@drawable/ic_launcher"
Android:label="@string/app_name"
Android:theme="@style/AppTheme" >
<activity
Android:name=".MainActivity"
Android:label="@string/app_name" >
<intent-filter>
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
Android:name=".Second"
Android:label="@string/app_name" >
</activity>
<receiver Android:name="com.example.broadcasttest.CustomReceiver">
<intent-filter >
<action Android:name="Android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
</application>
</manifest>
Et voici mon journal lorsque je suis activer le wifi.
11-19 20:13:11.474: D/activity name(25417): CURRENT Activity ::com.example.broadcasttest.MainActivity Package Name : com.example.broadcasttest
11-19 20:13:11.481: E/ghorar kochu(25417): checking:
11-19 20:13:11.542: E/hi(25417): helo
11-19 20:13:11.573: V/RenderScript(25417): Application requested CPU execution
11-19 20:13:11.580: V/RenderScript(25417): 0xb90a7850 Launching thread(s), CPUs 4
11-19 20:13:17.158: E/Thanks For the checking(25417): checking:chkd
Si vous avez des questions, faites le moi savoir.
Dans mon cas, j'ai décoré la classe broadcast avec [BroadcastReceiver(Enabled = true)]
et en même temps je l'ai enregistré dans OnResume
. Je l'ai corrigé en commentant //[BroadcastReceiver(Enabled = true)]
Je viens d'avoir ce problème et j'ai trouvé une solution qui n'était mentionnée dans aucune des réponses existantes, alors j'aimerais la partager.
J'enregistre le BroadcastReceiver une seule fois dans onCreate
Cependant, je l'enregistrais comme ceci:
LocalBroadcastManager.getInstance(this).registerReceiver(new MyBroadcastReceiver(), mStatusIntentFilter);
En d'autres termes, j'étais construction l'instance boradcastReceiver de l'appel registerReceiver.
Mais lorsque j'ai construit le BroadcastReceiver dans une déclaration distincte, le problème a été résolu. Comme ça:
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(myBroadcastReceiver , mStatusIntentFilter);
Solution de contournement très étrange, c'est peut-être un bogue qui sera corrigé ultérieurement.
Je pense qu’il serait préférable d’enregistrer le récepteur après avoir remplacé la variable BroadcastReceiver
et avant de commencer l’intention à partir de laquelle vous souhaitez recevoir des données (sinon, une variable NullPointerException
sera générée.
Annulez l'enregistrement du destinataire dans onStop()
plutôt que dans onPause()
.
J'ai remarqué que l'annulation de l'enregistrement du récepteur dans la onPause()
crée des problèmes si vous avez des services ou des tâches en arrière-plan à exécuter, ce qui mettra l'activité en pause et par conséquent l'annulera. (Cela entraînera plusieurs appels à la méthode onRecieve()
, c’est-à-dire chaque fois que le destinataire est réenregistré.)
Vous pouvez éviter ce problème si vous enregistrez votre récepteur de radiodiffusion à partir de la classe d'application personnalisée. Cela garantira que votre récepteur de radiodiffusion ne sera enregistré qu'une seule fois pour l'ensemble du cycle de vie de l'application.
J'ai rencontré un problème similaire, mais ma BroadcastReceiver
était statique parce que je voulais l'utiliser comme classe interne. Ce que j'ai fait était d'enregistrer le destinataire (pour créer l'instance statique), puis d'annuler l'enregistrement du même récepteur, appelé une fois par le AlarmManager
timer, ofcourse code est toujours très explicatif:
public void setAlarm(Context context) {
Log.d("EX", "Alarm SET !!");
Intent intent = new Intent("com.example.START_ALARM");
IntentFilter myIf = new IntentFilter("com.example.START_ALARM");
PendingIntent sender = PendingIntent.getBroadcast(context, 192837,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
myBroadcastReceiver mbr = new myBroadcastReceiver();
// ****Here goes the trick.****
context.registerReceiver(mbr, myIf);
context.unregisterReceiver(mbr);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Long firstTime = SystemClock.elapsedRealtime()
+ TimeUnit.SECONDS.toMillis(70);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime,
TimeUnit.SECONDS.toMillis(70), sender);
}
J'avais résolu ce problème en utilisant une valeur static.
S'il vous plaît trouver mon code ci-dessous.
Mon activité
private static Snackbar mSnackbar;
private NetworkChangeReceiver mNetworkChangeReceiver;
@Override
protected void onResume() {
super.onResume();
registerReceivers();
}
@Override
protected void onPause() {
super.onPause();
unRegisterReceivers();
}
private void registerReceivers() {
mNetworkChangeReceiver = new NetworkChangeReceiver() {
@Override
protected void onNetworkChange(boolean status) {
if (!status) {
if (mSnackbar == null) {
mSnackbar = Snackbar
.make(drawer, R.string.no_internet, Snackbar.LENGTH_INDEFINITE)
.setActionTextColor(Color.YELLOW)
.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
mSnackbar.show();
}
} else {
if (mSnackbar != null) {
mSnackbar.dismiss();
mSnackbar = null;
}
}
}
};
IntentFilter nwStateChangeFilter = new IntentFilter();
nwStateChangeFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
nwStateChangeFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(mNetworkChangeReceiver, nwStateChangeFilter);
}
private void unRegisterReceivers() {
unregisterReceiver(mNetworkChangeReceiver);
}
NetworkChangeReceiver.Class
public abstract class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null) { // connected to the internet
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI){
// connected to wifi
onNetworkChange(true);
} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
// connected to the mobile provider's data plan
onNetworkChange(true);
} else {
// not connected to the internet
onNetworkChange(false);
}
} else {
// not connected to the internet
onNetworkChange(false);
}
}
protected abstract void onNetworkChange(boolean status);
}