web-dev-qa-db-ja.com

Android NSNotificationCenterと同等

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

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

90
John
6
Rui Peres

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

LocalBroadcastManagerドキュメントから:

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

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

これを使用する場合、IntentNSNotificationと同等であると言えます。以下に例を示します。

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がクリックされるたびに、Intentがブロードキャストされ、mMessageReceiver内の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! 
328
Shiki

これは@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();
    }
}

最後に、コールバックサービスやレストサービスなどから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);
}

乾杯です!

12
Elvis Rudonja

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

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

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

4
AngraX

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 Studioにこのlibを追加できます。

compile 'com.google.guava:guava:17.0'
4
Shlomi Hasin

弱参照を使用できます。

このようにして、自分でメモリを管理し、必要に応じてオブザーバーを追加および削除できます。

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にアップロードしています。目を開けておいてください!

0
Victor Du Preez