web-dev-qa-db-ja.com

アプリがバックグラウンドにあるときでもBroadcastReceiverが機能するのはなぜですか?

BroadcastReceiverを使用してアプリのインターネット接続を確認しています。接続が失われた場合は警告ダイアログを表示します。正常に動作します。しかし、私の問題は、アプリがバックグラウンドにある場合でもBroadcastReceiverが機能することです。そのため、ユーザーが他のアプリを使用している場合でも、インターネット接続が失われるとダイアログがポップアップします。これは私のアプリを完全に台無しにしています。

アプリだけでブロードキャストレシーバーを制限する方法を知っている人はいますか?

これが私のBroadcastReceiverです:

 public class ConnectivityChangedReceiver extends BroadcastReceiver{

    @Override
    public void onReceive( Context context, Intent intent )
     {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    if (networkInfo != null && networkInfo.isConnected()) {
    } else {
        try{
            Intent i=new Intent(context, InternetDialogActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
        } catch(Exception e){
            e.printStackTrace();
        }
    }
  }
}

そして活動は:

 public class InternetDialogActivity extends Activity implements OnClickListener{
   @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.internet_dialog_box);
      getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
      Button retryButton = (Button) findViewById(R.id.retryInternetButton);
      retryButton.setOnClickListener(this);
    }

   public boolean checkConnectivity(){
       ConnectivityManager connectivityManager   = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
           NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

       if (networkInfo!=null && networkInfo.isConnected()) {
           finish();
           return true;
       } else {
           Intent intent = getIntent();
           finish();
           startActivity(intent);
           return false; 
      }
   }

   @Override
   public void onClick(View view) {
      switch(view.getId()){
         case R.id.retryInternetButton:
             try{
                 checkConnectivity();
             } catch(Exception e){
                 e.printStackTrace();
             }
             break;
       }
   }
   }

マニフェストでレシーバーとアクティビティを宣言する方法を次に示します。

  <receiver Android:name="com.lisnx.service.ConnectivityChangedReceiver"
        Android:label="NetworkConnection">
        <intent-filter>
            <action Android:name="Android.net.conn.CONNECTIVITY_CHANGE"/>
        </intent-filter>
  </receiver>

  <activity Android:name="com.lisnx.activity.InternetDialogActivity"
        Android:configChanges="orientation|keyboardHidden"
        Android:theme="@Android:style/Theme.Dialog" />

マニフェストで宣言しないことで、BroadcastReceiverをアプリ内で動作するように制限できることを読みました。しかし、私はレシーバーがどのように機能するのか知りませんか?私を助けてください。私はそれにひどくこだわっています。よろしくお願いします。

19
Yogesh Somani

A BroadcastReceiver は、アプリがバックグラウンドにある場合に機能します。これは、受信者がピックアップするイベントがグローバルに送信され、各アプリは、これらのイベントをリッスンするように登録されているためです。実行中です。

これに対処するには、BroadcastReceiveronReceiveコードで、アプリがフォアグラウンドにあるかどうかを確認します。

これを行うための一貫した効果的な方法は1つあり、私が知っているのは1つだけです。アプリケーションの一時停止/再開アクションを追跡する必要があります。 everyアクティビティでこれを確認してください。

いくつかのサンプルコード この回答には (ソリューション#1)があります。あなたのケースでは、BroadcastReceiverから何かを行う前に、検証としてMyApplication.isActivityVisible() == trueをチェックする必要があります。

37
Eric

インテントフィルターをマニフェストから削除して、アクティビティーに登録/登録解除しようとしましたか?したがって、IntentフィルターをonStart()メソッドで登録し、onStop()メソッドで登録解除することができます。コードは次のように考えられます:

static final String ACTION = "Android.net.conn.CONNECTIVITY_CHANGE";


IntentFilter filter = new IntentFilter(ACTION);
this.registerReceiver(ConnectivityChangedReceiver, filter);


unregisterReceiver(ConnectivityChangedReceiver);

Activity Lifecycle についても、まだ慣れていない場合は学ぶ必要があります。

17
soreal

各アクティビティのonPause()onResume()BroadcastReceiverを登録/登録解除する必要があります。次に、アプリがフォアグラウンドにあるときのみ、レシーバーが「リッスン」していることがわかります。 BaseActivityを拡張し、onPause()onResume()をオーバーライドしてレシーバーを登録/登録解除する独自のActivityを作成することで、簡単にそれを行うことができます。すべてのアクティビティにBaseActivityを拡張させ、通常どおりsuper.onResume()およびsuper.onPause()を呼び出すようにしてください。次にコード例を示します。

_public class BaseActivity extends Activity {
    // Create an IntentFilter to listen for connectivity change events
    static IntentFilter filter = new IntentFilter("Android.net.conn.CONNECTIVITY_CHANGE");
    // Create an instance of our BroadcastReceiver
    static ConnectivityChangedReceiver receiver = new ConnectivityChangedReceiver();

    @Override
    protected void onPause() {
        super.onPause();
        // Stop listening for connectivity change events
        unregisterReceiver(receiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Listen for connectivity change events
        registerReceiver(receiver, filter);
    }
}
_

すべてのアクティビティはBaseActivityを拡張する必要があり、onResume()またはonPause()で特別なことを行う必要がある場合は、必ずsuper.onXXXXX()を呼び出すようにしてください。この:

_public MyActivity extends BaseActivity {
    @Override
    protected void onResume() {
        super.onResume();
        // Here you do whatever you need to do in onResume() of your activity
        ...
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Here you do whatever you need to do in onPause() of your activity
        ...
    }
}
_

コンパイラーを介してコードを実行しなかったので、タイプミスや何かを見落とした場合はお詫びします。

13
David Wasser

アプリがバックグラウンドにあるときは、レシーバーを使用していないことを確認する必要があると思います。そのためには、すべてのアクティビティのonPause()およびonResume()メソッドを使用する必要があります。

4

アプリが実行されている場合にのみ起動するBroadcast Receiverを作成するには、以下のコードに従ってください。

1。次のようにブロードキャストレシーバーを作成します。


import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;

public class InternetStatusNotifier extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        //Recieve notification here

    }

}

2。ブロードキャストレシーバーに次のように機能させるアクティビティまたはフラグメントを作成します。


import Android.app.Activity;
import Android.content.IntentFilter;
import Android.os.Bundle;

public class MainActivity extends Activity {
    private InternetStatusNotifier mInternetStatusNotifier;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mInternetStatusNotifier = new InternetStatusNotifier();
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume() {
        registerReceiver(mInternetStatusNotifier, new IntentFilter(
                "Android.net.conn.CONNECTIVITY_CHANGE"));
        super.onResume();
    }

    @Override
    protected void onPause() {
        unregisterReceiver(mInternetStatusNotifier);
        super.onPause();
    }

注:これは、放送受信機を画面固有の方法で使用する方法です。この方法で放送を受信するのは画面表示のみです。マニフェストファイルを使用してブロードキャストを登録すると、アプリを閉じたときにも受信されます

3

私の知る限り、ブロードキャストレシーバーがmanifest.xml内に登録されている場合、アプリケーションが存在する限り、ブロードキャストレシーバーが存在します。また、動的に登録されたレシーバー(つまり、プログラムでBroadcastReceiverを登録する)は、UIスレッドで呼び出されます。これは、レシーバーがUIの処理をブロックするため、onReceive()メソッドは可能な限り高速であることを意味します。

ただし、ブロードキャストレシーバーに関する情報について説明します。ただし、最初にいくつかの情報を知っておく必要があります。まず、ブロードキャストレシーバーはスタンドアロンのアプリケーションコンポーネントであるため、他のアプリケーションコンポーネントが実行されていなくても実行を継続できます。そのため、アクティビティのonPauseでブロードキャストレシーバーの登録を解除します。また、開発者はこれをActivity.onResume()実装に登録する必要があります。

次に、DeveloperはActivity.onSaveInstanceState()で登録解除しないでください。これは、ユーザーが履歴スタックに戻った場合に呼び出されないためです。その情報は BroadcastReceiverのドキュメント から引用しています。

別のポイントは、BroadcastReceiverオブジェクトはonReceive()の呼び出しの間のみ有効であることです。 onReceive()メソッドが終了するとすぐに、BroadcastReceiverが終了します。

プログラムでレシーバーを登録する方法:

_public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
_

ここで、BroadcastReceiver-レシーバーは、ブロードキャストインテントがフィルターと一致したときに呼び出されます。
そしてIntentFilter- Intentは、レシーバーがリッスンするイベントを指定します。

登録:

_YourConnectionListener receiver;
this.reciever = new YourConnectionListener();
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(this.reciever, filter);
_

ブロードキャスト情報を送信しました:

_Intent intent = new Intent();
intent.putExtra("Message", "Your connectivity info has Changed!!"); 
this.sendBroadcast(intent);
_

受信機:

今、放送を受信する必要があります。 Androidイベントが発生するたびに、登録されているすべてのブロードキャストレシーバーでonReceive()メソッドを呼び出します。接続が変更されるたびに通知を受け取りたいとします。

_public class YourConnectionListener extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent){
         // your Code
    }
}   
_

onReceive()には2つの引数があります。

  • context:追加情報にアクセスしたり、サービスやアクティビティを開始したりするために使用できるContextオブジェクト。
  • intent:レシーバーの登録に使用されるインテント。このオブジェクトには、実装で使用できる追加情報が含まれています。
    さらに、開発者はBroadcastReceiverでの長期にわたるタスクを回避する必要があります。したがって、静的および動的に登録されたレシーバーでは、開発者はレシーバー自体で小さなタスクを実行する必要があります。それより長いタスクについては、レシーバー内からサービスを開始する必要があります。
3
Ratna Halder

これがAndroidでのブロードキャストレシーバーの動作方法です。マニフェストでブロードキャストに登録し、アプリが実行されていない場合、Androidは、ブロードキャストを処理するための新しいプロセスを開始します。通常、ブロードキャストから直接UIを表示することはお勧めしませんこれは他のアプリに割り込む可能性があるためです。また、ユニバーサルな「接続が失われました」ダイアログを使用することもよい考えではありません。これは、おそらくネットワークアクセスを使用する各アクティビティで処理する必要があります。

元の質問と同様に、アクティビティがバックグラウンドで動作する場合はレシーバーを無効にし(onPause()など)、フォアグラウンドで動作する場合はレシーバーを有効にする必要があります(onResume()など)。 )。 enabled=falseをマニフェストに入れ、必要に応じてコードで次のように切り替えます。

   public static void toggle(Context context, boolean enable) {
        int flag = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
        ComponentName receiver = new ComponentName(context,
                ConnectivityMonitor.class);

        context.getPackageManager().setComponentEnabledSetting(receiver, flag,
                PackageManager.DONT_KILL_APP);
   }
1
Nikolay Elenkov

アプリがフォアグラウンドにあるかどうかを確認する簡単な方法

if((mContext.getPackageName().equalsIgnoreCase(
                ((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
                        .getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}
0
Naren

誰かがそれを開いたときにアプリケーションからインターネット設定を確認することをお勧めします。これは、私がそれを行う方法のコードの一部です。

public static boolean isNetworkConnected(Context ctx) {  
        ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);  
        NetworkInfo ni = cm.getActiveNetworkInfo();  
        if (ni == null) {  
            return false; // There are no active networks.  
        } else  
            return true;  
    }
0
yubaraj poudel