19

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 を制限できることを読みました。しかし、受信機がどのように機能するかわかりませんか?私を助けてください。私はそれにひどく立ち往生しています。事前にサンクス。

4

9 に答える 9

37

BroadcastReceiverレシーバーがピックアップしたイベントはグローバルに送信され、各アプリは実行中かどうかに関係なく、これらをリッスンするように登録されているため、アプリがバックグラウンドにあるときに機能します。

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

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

この回答にはいくつかのサンプル コードがあります(解決策 #1)。あなたの場合、MyApplication.isActivityVisible() == trueから何かを行う前に検証として確認する必要がありますBroadcastReceiver

于 2012-09-05T05:34:59.540 に答える
18

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

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


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


unregisterReceiver(ConnectivityChangedReceiver);

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

于 2012-09-05T05:58:19.897 に答える
14

各アクティビティの登録/登録解除を行う必要がBroadcastReceiverありonPause()ます。onResume()これで、アプリがフォアグラウンドにあるときにのみレシーバーが「リッスン」していることがわかります。BaseActivityレシーバーを拡張ActivityおよびオーバーライドonPause()onResume()、登録/登録解除する独自のものを作成することで、これを簡単に行うことができます。すべてのアクティビティを延長して、通常どおり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
        ...
    }
}

コンパイラを介してコードを実行しなかったため、タイプミスや見落としがありましたらお詫び申し上げます。

于 2012-09-05T08:32:32.833 に答える
4

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

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

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

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

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

public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)

ここで、BroadcastReceiver-receiverは、ブロードキャストインテントがフィルターと一致したときに呼び出されます。
また、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オブジェクト。
  • インテント:レシーバーの登録に使用されるインテント。このオブジェクトには、実装で使用できる追加情報が含まれています。
    さらに、開発者はBroadcastReceiverでの長期にわたるタスクを回避する必要があります。したがって、静的および動的に登録されたレシーバーでは、開発者はレシーバー自体でマイナーなタスクを実行する必要があります。それより長いタスクについては、レシーバー内からサービスを開始する必要があります。
于 2012-09-05T07:20:36.140 に答える
4

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

于 2012-10-25T13:05:11.727 に答える
1

これが、ブロードキャスト レシーバが 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);
   }
于 2012-09-05T05:36:56.603 に答える
0

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

if((mContext.getPackageName().equalsIgnoreCase(
                ((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
                        .getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}
于 2014-01-02T16:13:31.747 に答える
-1

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

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;  
    }
于 2015-03-14T14:57:23.947 に答える