Android BroadcastReceiver onReceive() called twice on android 4.0

落爺英雄遲暮 提交于 2019-11-30 06:53:10

问题


I faced to one problem on android 4.0.3 (on 4.1.2 it works fine). I have in my Activity BroadcastReceiver. When I send a broadcast, method onReceive() called always twice. Please give me any suggestions about BroadcastReceiver differences on 4.0 and 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);
}

回答1:


Short answer: there isn't a difference. The BroadcastReceiver class for both is from Android 2.3.2 r1.

I've had a similar problem, but for me it was with an HTC Desire HD with Android 2.3.5 on it - the notifications from GCM would always get received twice. I didn't manage to find the root of the problem, but there is a workaround. You can generate a unique ID for each notification in the server and send it along with the actual data. Then, in your receiver, you can update a mapping of unique ID to notification data, and if there is already data for the given ID, just ignore it.

I probably didn't make that very clear, so here's an example:

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*);
    }
}

If you don't need to store additional data, you can use a HashSet instead of a Map and just check if it contains the ID.




回答2:


Usually onReceive is being called twice since people are registering the broadcast in 2 locations, Most likely you are registering in your onCreate and in your onResume. (Choose one spot to register).

Although you might have done it probably a dozen of times - it is always recommended to take another glance at the Activity Life Cycle.




回答3:


I had same issue.

onReceive() gets called twice because i was registering Broadcast receiver twice. One in my activity's onCreate() and another in manifest.

I remove broadcast receiver registration from onCreate() and it's working fine. Register your broadcast receiver in only one of them.

There are two ways to do this:

  • Statically in the manifest file.
  • Dynamically in the code.

Which method (static or dynamic) to use when depends completely upon what you’re trying to do. Basically when you want to do some changes right on the screen (home screen, launcher, status bar, etc.) by showing up some notification or some indicator in the status bar by listening to system wide events or maybe those sent by other apps, then it make sense to use statically registered broadcast receivers. Whereas based on similar events you want to do changes right in your app when the user is using it or maybe it’s put in the background, then it makes sense to use dynamically registered receivers which’ll last till the registering components are destroyed.

For more info: http://codetheory.in/android-broadcast-receivers/




回答4:


Inatialize BroadcastReciver on onStart(). This fix my problem.




回答5:


I believe this is the correct way to determine if Wifi has connected or disconnected.

The onReceive() method in the BroadcastReceiver:Just put a Simple checking(Its a logic implemented by 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();
        }

    }




}



}

This is actual receiver class.Now coming to the main activity.

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");


        }

    }

    }

This code only works when your app is onresume state and when it is in MainActivity.

Here is my ConnectionDetector class.Through which i am checking the connection of 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;
        }


}

And here is my Manifest.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>

And here is my log when i am enable the 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

If you have any query just let me know.




回答6:


I was calling sendBroadcast(intent) multiple times in my Service class

Removing one of them fixed the problem.




回答7:


You can also implement it by setting a boolean flag, when you enter to onReceive() function




回答8:


I faced a similar problem, but my BroadcastReceiver was static because I wanted to use it as an inner class, what I did was to register the receiver (in order to create the static instance), then unregister the same receiver, that made it be called once which is by the AlarmManager timer, ofcourse code is always much explanatory :

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



回答9:


I have just had this problem and I found a solution that wasn't mentioned in any of the existed answers, so I would like to share it.

I register the BroadcastReceiver just once in onCreate

However, I was registering it like this:

LocalBroadcastManager.getInstance(this).registerReceiver(new MyBroadcastReceiver(), mStatusIntentFilter);

In other words, I was constructing the boradcastReceiver instance inside the registerReceiver call.

But when I construct the BroadcastReceiver in a separate statement the problem was solved. Like this:

MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();

LocalBroadcastManager.getInstance(this).registerReceiver(myBroadcastReceiver , mStatusIntentFilter);

Very weird workaround, maybe it's a bug that will be fixed later.




回答10:


I had fixed this issue by using a static value.

Please find my code below.

My Activity

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



回答11:


I feel that it would be best to register the receiver after you have overridden the BroadcastReceiver and before starting the intent from which you want to receive data.(Otherwise it may throw a NullPointerException.
Unregister the reciever in onStop() rather than in onPause().

I have noticed that unregistering the receiver in the onPause() creates problems if you have services or background tasks to be executed, which will pause the activity and hence unregister your Broadcast Receiver. (This will result in multiple calls to the onRecieve() method, i.e. each time the receiver is re-registered.)




回答12:


In my case, I decorated the broadcast class with [BroadcastReceiver(Enabled = true)] and at the same time registered it in OnResume. I fixed it by commenting out //[BroadcastReceiver(Enabled = true)]




回答13:


You can avoid getting this problem, If you register your broadcast receiver from custom Application class. This will make sure that your broadcast receiver will be registered only once for the entire application life cycle.




回答14:


I have found the reason for this issue.

Basically when we register the receiver for BLUETOOTH_STATE_CHANGE then if we are Turning ON the bluetooth then its onReceive() method will call twice for the following two Bluetooth States:

STATE 1: STATE_TURNING_ON Indicates the local Bluetooth adapter is turning on.

STATE 2: STATE_ON Indicates the local Bluetooth adapter is on, and ready for use.

Same while Turing OFF the bluetooth then its onReceive() method will again call twice for the following two Bluetooth States:

STATE 1: STATE_TURNING_OFF Indicates the local Bluetooth adapter is turning off.

STATE 2: STATE_OFF Indicates the local Bluetooth adapter is off.

So basically we can handle this situation in the following way:

@Override
public void onReceive(Context context, Intent intent) {
    final String action = intent.getAction();
    if (action != null && action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
        if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_ON) {

            // When Bluetooth adapter is on, and ready for use
            //DO YOUR CODE HERE FOR "BLUETOOTH ON" CASE


        }
        else if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {

            //When local Bluetooth adapter is off
            //DO YOUR CODE HERE FOR "BLUETOOTH OFF" CASE

        }

    }
} 

After looking to your code(@girlOnSledge), it seems that if you will follow the above procedure, your code will also work fine in that case.



来源:https://stackoverflow.com/questions/21314126/android-broadcastreceiver-onreceive-called-twice-on-android-4-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!