NSNotificationCenterに相当するAndroid


95

iPhoneアプリケーションをAndroidに移植する過程で、アプリ内で通信するための最良の方法を探しています。意図は進むべき道のようですが、これは最良の(唯一の)オプションですか?NSUserDefaultsは、パフォーマンスとコーディングの両方で、インテントよりもはるかに軽量に見えます。

また、stateのアプリケーションサブクラスがあることを追加する必要がありますが、別のアクティビティにイベントを認識させる必要があります。


3
このトピックの初心者にとっては、2番目の答えが最適です。下にスクロール...
2015

回答:


5

あなたはこれを試すことができます:http : //developer.android.com/reference/java/util/Observer.html


42
以下のシキの答えははるかに優れています。
dsaff

5
@dsaffはより完全な回答ですが、私の回答が間違っていることは決してありません。私は明らかに-1に値しません。シキの答えを+1するのは理にかなっています。
Rui Peres、2012年

4
質問にはShikiの方が適切です
Ramz 2013年

4
技術的に不正確でスパムの回答のみが反対投票されることに注意してください-これはどちらにも当てはまりません。報酬の+1と志貴の+1もいい答えです。

350

私が見つけた最高の同等物は、Androidサポートパッケージの一部であるLocalBroadcastManagerです。

LocalBroadcastManagerのドキュメントから:

インテントのブロードキャストを登録し、プロセス内のローカルオブジェクトに送信するヘルパー。これには、sendBroadcast(Intent)を使用してグローバルブロードキャストを送信するよりも多くの利点があります。

  • ブロードキャストしているデータがアプリを離れることはないので、プライベートデータの漏洩を心配する必要はありません。
  • 他のアプリケーションがこれらのブロードキャストを自分のアプリに送信することはできないため、セキュリティホールが悪用されることを心配する必要はありません。
  • システムを通じてグローバルブロードキャストを送信するよりも効率的です。

これを使用するIntentと、はと同等であると言えますNSNotification。次に例を示します。

ReceiverActivity.java

というイベントの通知を監視するアクティビティ"custom-event-name"

@Override
public void onCreate(Bundle savedInstanceState) {

  ...
  
  // Register to receive messages.
  // This is just like [[NSNotificationCenter defaultCenter] addObserver:...]
  // We are registering an observer (mMessageReceiver) to receive Intents
  // with actions named "custom-event-name".
  LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
      new IntentFilter("custom-event-name"));
}

// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get extra data included in the Intent
    String message = intent.getStringExtra("message");
    Log.d("receiver", "Got message: " + message);
  }
};

@Override
protected void onDestroy() {
  // Unregister since the activity is about to be closed.
  // This is somewhat like [[NSNotificationCenter defaultCenter] removeObserver:name:object:] 
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
  super.onDestroy();
}

SenderActivity.java

通知を送信/ブロードキャストする2番目のアクティビティ。

@Override
public void onCreate(Bundle savedInstanceState) {
  
  ...
  
  // Every time a button is clicked, we want to broadcast a notification.
  findViewById(R.id.button_send).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      sendMessage();
    }
  });
}

// Send an Intent with an action named "custom-event-name". The Intent sent should 
// be received by the ReceiverActivity.
private void sendMessage() {
  Log.d("sender", "Broadcasting message");
  Intent intent = new Intent("custom-event-name");
  // You can also include some extra data.
  intent.putExtra("message", "This is my message!");
  LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

上記のコードでR.id.button_sendは、ボタンがクリックされるたびに、インテントがブロードキャストされmMessageReceiver、in によって受信されReceiverActivityます。

デバッグ出力は次のようになります。

01-16 10:35:42.413: D/sender(356): Broadcasting message
01-16 10:35:42.421: D/receiver(356): Got message: This is my message! 

11
このような有益で詳細な回答をお寄せいただき、誠にありがとうございます。
クリスレイシー、2012

14
onCreateメソッドでregisterReceiverを呼び出さないでください。これにより、アクティビティがリークし、onDestroyメソッドが呼び出されなくなります。onResumeはregisterReceiverを呼び出し、onPauseはunregisterReceiverを呼び出すより良い選択のようです。
ステファンJAIS 2013

4
に完全に相当しNSNotificationCenter、受け入れられる答えになるはずです!
Leon Storey 2013年

グローバル通知を使用すると、混乱した設計につながる可能性があることを指摘しておきます。簡単な方法に進む前に、コンポーネント間の最適な結合を考えます。場合によっては、リスナーまたはiOSデリゲートパターンに類似したものを使用するほうがよい場合もあります。
saulobrito 2014年

これは私のために働いてくれてありがとう。@Shikiあなたはこの質問に私にあなたの意見を与えることができると思いますしてくださいstackoverflow.com/questions/25598696/...
アクセル・

16

これは@Shikiの回答に似ていますが、iOS開発者と通知センターの観点からです。

最初に、ある種のNotificationCenterサービスを作成します。

public class NotificationCenter {

 public static void addObserver(Context context, NotificationType notification, BroadcastReceiver responseHandler) {
    LocalBroadcastManager.getInstance(context).registerReceiver(responseHandler, new IntentFilter(notification.name()));
 }

 public static void removeObserver(Context context, BroadcastReceiver responseHandler) {
    LocalBroadcastManager.getInstance(context).unregisterReceiver(responseHandler);
 }

 public static void postNotification(Context context, NotificationType notification, HashMap<String, String> params) {
    Intent intent = new Intent(notification.name());
    // insert parameters if needed
    for(Map.Entry<String, String> entry : params.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        intent.putExtra(key, value);
    }
    LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
 }
}

次に、文字列を使用したコーディングの間違いを防ぐために、いくつかの列挙型も必要になります-(NotificationType):

public enum NotificationType {

   LoginResponse;
   // Others

}

以下は、アクティビティーでの使用例(オブザーバーの追加/削除)です。

public class LoginActivity extends AppCompatActivity{

    private BroadcastReceiver loginResponseReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
           // do what you need to do with parameters that you sent with notification

           //here is example how to get parameter "isSuccess" that is sent with notification
           Boolean result = Boolean.valueOf(intent.getStringExtra("isSuccess"));
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        //subscribe to notifications listener in onCreate of activity
        NotificationCenter.addObserver(this, NotificationType.LoginResponse, loginResponseReceiver);
    }

    @Override
    protected void onDestroy() {
        // Don't forget to unsubscribe from notifications listener
        NotificationCenter.removeObserver(this, loginResponseReceiver);
        super.onDestroy();
    }
}

最後に、コールバックやRESTサービスなどからNotificationCenterに通知をポストする方法を示します。

public void loginService(final Context context, String username, String password) {
    //do some async work, or rest call etc.
    //...

    //on response, when we want to trigger and send notification that our job is finished
    HashMap<String,String> params = new HashMap<String, String>();          
    params.put("isSuccess", String.valueOf(false));
    NotificationCenter.postNotification(context, NotificationType.LoginResponse, params);
}

それだけです、乾杯!


解決策をありがとう!のBundle params代わりにを使用するとHashMap、さまざまなタイプのパラメータを渡すのに便利です。そこの間に素敵な接続があるIntentBundleintent.putExtras(params)
zubko

4

これを使用することができます:http : //developer.android.com/reference/android/content/BroadcastReceiver.html、これは同様の動作を提供します。

Context.registerReceiver(BroadcastReceiver、IntentFilter)を使用してプログラムでレシーバーを登録すると、Context.sendBroadcast(Intent)を介して送信されたインテントがキャプチャされます。

ただし、アクティビティ(コンテキスト)が一時停止されている場合、レシーバは通知を受信しないことに注意してください。


簡単な設計ノート:BroadcastReceiversとNSNotificationCenterはどちらもイベントアグリゲーターとして動作できます。デリゲートまたはオブザーバーに対する利点は、送信側と受信側が分離されていることです(実際にはメッセージまたはデータの結合がありますが、これは最も弱い結合タイプの1つです)。修正して編集。
AngraX 2011

4

Guava libのEventBusの使用は、コンポーネントを明示的に相互に登録することなく、コンポーネント間のパブリッシュサブスクライブスタイルの通信を行うための最も簡単な方法であることがわかりました

https://code.google.com/p/guava-libraries/wiki/EventBusExplainedでサンプルをご覧ください

// Class is typically registered by the container.
class EventBusChangeRecorder {
  @Subscribe public void recordCustomerChange(ChangeEvent e) {
    recordChange(e.getChange());
  }

// somewhere during initialization
eventBus.register(this);

}

// much later
public void changeCustomer() {
  eventBus.post(new ChangeEvent("bla bla") );
} 

build.gradleに依存関係を追加することで、Androidライブラリにこのlibを追加できます。

compile 'com.google.guava:guava:17.0'

プラットフォームに依存しにくい「モデル」サイドコードにより適しています。
karmakaze

2

KotlinKotlinでの@Shikiのバージョンは、フラグメントに少しリファクタリングされています。

  1. オブザーバーをFragmentに登録します。

Fragment.kt

class MyFragment : Fragment() {

    private var mContext: Context? = null

    private val mMessageReceiver = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            //Do something here after you get the notification
            myViewModel.reloadData()
        }
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)

        mContext = context
    }

    override fun onStart() {
        super.onStart()
        registerSomeUpdate()
    }

    override fun onDestroy() {
        LocalBroadcastManager.getInstance(mContext!!).unregisterReceiver(mMessageReceiver)
        super.onDestroy()
    }

    private fun registerSomeUpdate() {
        LocalBroadcastManager.getInstance(mContext!!).registerReceiver(mMessageReceiver, IntentFilter(Constant.NOTIFICATION_SOMETHING_HAPPEN))
    }

}
  1. どこにでも通知を投稿できます。コンテキストだけが必要です。

    LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(Constant.NOTIFICATION_SOMETHING_HAPPEN))```

PS

  1. 通知を適切に整理するために、私のようなConstant.ktを追加できます。 Constant.kt
object Constant {
    const val NOTIFICATION_SOMETHING_HAPPEN = "notification_something_happened_locally"
}
  1. フラグメント内のコンテキストについては、activity(時々null)またはconext私が使用したものを使用できます。

0

弱参照を使用できます。

この方法では、メモリを自分で管理し、オブザーバーを自由に追加および削除できます。

addObserverがこれらのパラメーターを追加するとき-追加するアクティビティからそのコンテキストを空のインターフェースにキャストし、通知名を追加し、メソッドを呼び出してインターフェースを実行します。

インターフェースを実行するメソッドには、runと呼ばれる関数があり、渡したデータを次のように返します。

public static interface Themethodtorun {
        void run(String notification_name, Object additional_data);
    }

空のインターフェイスで参照を呼び出す監視クラスを作成します。また、addobserverに渡されるコンテキストからThemethodtorunインターフェイスを構築します。

観測をデータ構造に追加します。

呼び出す方法は同じですが、データ構造で特定の通知名を見つけるだけで、Themethodtorun.run(notification_name、data)を使用できます。

これにより、特定の通知名でオブザーバーを作成した場所にコールバックが送信されます。あなたが終わったらそれらを削除することを忘れないでください!

これは弱参照の良い参照です。

http://learningviacode.blogspot.co.nz/2014/02/weak-references-in-java.html

このコードをgithubにアップロードしているところです。目を開けてください!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.