web-dev-qa-db-fra.com

Android BroadcastReceiver onReceive () appelé deux fois sur Android 4.0

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);
}
23
girlOnSledge

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.

8
npace

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:

  • Statiquement dans le fichier manifeste. 
  • Dynamiquement dans le code.

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/

18
Sushant

Inatialisez BroadcastReciver sur onStart(). Cela corrige mon problème.

8
SINIGAMI

Vous pouvez également l'implémenter en définissant un indicateur booléen lorsque vous entrez dans la fonction onReceive()

1
varghesekutty

J'appelais sendBroadcast(intent) plusieurs fois dans ma classe de service

Supprimer l'un d'eux corrige le problème.

1
ymerdrengene

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.

1
Subho

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)]

0
Donald O

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.

0
William Kinaan

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é.)

0
Aliabbas Merchant

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.

0
Sameer Ranjan

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);
}
0
E_X

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);
}
0
Rasool Mohamed