Подтвердить что ты не робот

Android BroadcastReceiver onReceive() дважды вызывается на Android 4.0

Я столкнулся с одной проблемой в android 4.0.3 (на 4.1.2 он отлично работает). У меня в моей деятельности BroadcastReceiver. Когда я отправляю широковещательную рассылку, метод onReceive() вызывается всегда дважды. Пожалуйста, дайте мне какие-либо предложения о различиях BroadcastReceiver на 4.0 и 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);
}
4b9b3361

Ответ 1

Короткий ответ: нет никакой разницы. Класс BroadcastReceiver для обоих - от Android 2.3.2 r1.

У меня была аналогичная проблема, но для меня это было с HTC Desire HD с Android 2.3.5 на нем - уведомления от GCM всегда получались дважды. Мне не удалось найти корень проблемы, но есть обходной путь. Вы можете создать уникальный идентификатор для каждого уведомления на сервере и отправить его вместе с фактическими данными. Затем в вашем приемнике вы можете обновить сопоставление уникального идентификатора с данными уведомления, а если уже есть данные для данного идентификатора, просто проигнорируйте его.

Я, наверное, не сделал этого очень ясно, так вот пример:

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

Если вам не нужно хранить дополнительные данные, вы можете использовать HashSet вместо Карты и просто проверить, содержит ли он идентификатор.

Ответ 2

Обычно onReceive вызывается дважды, поскольку люди регистрируют трансляцию в двух местах, Скорее всего, вы регистрируетесь в своем onCreate и в своем onResume. (Выберите одно место для регистрации).

Хотя вы, возможно, сделали это, вероятно, уже десяток раз - всегда рекомендуется еще раз взглянуть на жизненный цикл деятельности.

Ответ 3

У меня была такая же проблема.

onReceive() вызывается дважды, потому что я дважды регистрировал широковещательный приемник. Один в моей деятельности onCreate() и другой в manifest.

Я удаляю регистрацию приемника вещания с onCreate() и работает нормально. Зарегистрируйте свой широковещательный приемник только в одном из них.

Есть два способа сделать это:

  • Статически в файле манифеста.
  • Динамически в коде.

Какой метод (статический или динамический) использовать, когда полностью зависит от того, что вы пытаетесь сделать. В основном, если вы хотите сделать некоторые изменения прямо на экране (начальный экран, панель запуска, строка состояния и т.д.), Отображая какое-либо уведомление или какой-либо индикатор в строке состояния, слушая системные события или, возможно, отправленные другими приложениями, то имеет смысл использовать статически зарегистрированные широковещательные приемники. Принимая во внимание, что на основе подобных событий вы хотите внести изменения прямо в свое приложение, когда пользователь использует его или, возможно, его помещают в фоновом режиме, тогда имеет смысл использовать динамически зарегистрированные получатели, которые будут сохраняться до тех пор, пока не будут уничтожены регистрирующие компоненты.

Для получения дополнительной информации: http://codetheory.in/android-broadcast-receivers/

Ответ 4

Инициализировать BroadcastReciver на onStart(). Это исправить мою проблему.

Ответ 5

Вы также можете реализовать, установив булевский флаг, когда вы входите в функцию onReceived()

Ответ 6

Я считаю, что это правильный способ определить, подключен ли Wi-Fi или отключен.

Метод onReceive() в BroadcastReceiver: просто поместите Простую проверку (ее логика реализована 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();
        }

    }




}



}

Это фактический класс приемника. Теперь вы переходите к основному виду деятельности.

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


        }

    }

    }

Этот код работает только тогда, когда ваше приложение находится в состоянии onresume и когда оно находится в MainActivity.

Вот мой класс ConnectionDetector. В этом я проверяю соединение Wi-Fi.

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


}

И вот мой 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>

И вот мой журнал, когда я включаю Wi-Fi.

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

Если у вас есть какие-либо вопросы, просто дайте мне знать.

Ответ 7

Я столкнулся с аналогичной проблемой, но мой BroadcastReceiver был статичным, потому что я хотел использовать его как внутренний класс, то, что я сделал, это зарегистрировать приемник (чтобы создать статический экземпляр), затем отменить регистрацию того же получателя, который заставлял его называть один раз, который по таймеру AlarmManager, конечно-кодовый код всегда много объясняет:

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

Ответ 8

У меня была эта проблема, и я нашел решение, которое не упоминалось ни в одном из существующих ответов, поэтому я хотел бы поделиться им.

Я регистрирую BroadcastReceiver только один раз в onCreate

Однако я регистрировал его следующим образом:

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

Другими словами, я был конструировал экземпляр boradcastReceiver внутри вызова registerReceiver.

Но когда я построил BroadcastReceiver в отдельном выражении, проблема была решена. Вот так:

MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();

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

Очень странное обходное решение, возможно, это ошибка, которая будет исправлена ​​позже.

Ответ 9

Я вызывал sendBroadcast(intent) несколько раз в моем классе службы

Удаление одного из них устраняет проблему.

Ответ 10

Я исправил эту проблему, используя значение static.

Пожалуйста, найдите мой код ниже.

Моя активность

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

Я чувствую, что было бы лучше зарегистрировать приемник после того, как вы переопределили BroadcastReceiver и перед тем, как начать намерение, из которого вы хотите получать данные. (В противном случае он может выбросить NullPointerException.
Отмените регистрацию приемника в onStop(), а не в onPause().

Я заметил, что отмена регистрации получателя в onPause() создает проблемы, если у вас есть службы или фоновые задачи, которые будут выполняться, что приостановит действие и, следовательно, отменит регистрацию вашего широковещательного приемника. (Это приведет к нескольким вызовам метода onRecieve(), то есть каждый раз, когда ресивер перерегистрируется.)

Ответ 12

В моем случае я украсил класс вещания [BroadcastReceiver(Enabled = true)] и в то же время зарегистрировал его в OnResume. Я исправил это, комментируя //[BroadcastReceiver(Enabled = true)]