Android equivalent to NSNotificationCenter

前端 未结 8 2059
旧时难觅i
旧时难觅i 2020-12-22 15:35

In the process of porting an iPhone application over to android, I am looking for the best way to communicate within the app. Intents seem to be the way to go, is this the b

相关标签:
8条回答
  • 2020-12-22 16:10

    Here is something similar to @Shiki answer, but from the angle of iOS developers and Notification center.

    First create some kind of NotificationCenter service:

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

    Then, you will also need some enum type to be secure of mistakes in coding with strings - (NotificationType):

    public enum NotificationType {
    
       LoginResponse;
       // Others
    
    }
    

    Here is usage(add/remove observers) for example in activities:

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

    and here is finally how we post notification to NotificationCenter from some callback or rest service or whatever:

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

    that's it, cheers!

    0 讨论(0)
  • 2020-12-22 16:12

    You could try this: http://developer.android.com/reference/java/util/Observer.html

    0 讨论(0)
  • 2020-12-22 16:13

    The best equivalent I found is LocalBroadcastManager which is part of the Android Support Package.

    From the LocalBroadcastManager documentation:

    Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):

    • You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
    • It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
    • It is more efficient than sending a global broadcast through the system.

    When using this, you can say that an Intent is an equivalent to an NSNotification. Here is an example:

    ReceiverActivity.java

    An activity that watches for notifications for the event named "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

    The second activity that sends/broadcasts notifications.

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

    With the code above, every time the button R.id.button_send is clicked, an Intent is broadcasted and is received by mMessageReceiver in ReceiverActivity.

    The debug output should look like this:

    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! 
    
    0 讨论(0)
  • 2020-12-22 16:13

    Kotlin: Here's a @Shiki's version in Kotlin with a little bit refactor in a fragment.

    1. Register the observer in 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. Post notification anywhere. Only you need the context.

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

    PS:

    1. you can add a Constant.kt like me for well organize the notifications. Constant.kt
    object Constant {
        const val NOTIFICATION_SOMETHING_HAPPEN = "notification_something_happened_locally"
    }
    
    1. For the context in a fragment, you can use activity (sometimes null) or conext like what I used.
    0 讨论(0)
  • 2020-12-22 16:25

    I found that the usage of EventBus of Guava lib is the simplest way for publish-subscribe-style communication between components without requiring the components to explicitly register with one another

    see their sample on 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") );
    } 
    

    you can add this lib simply on Android Studio by adding a dependency to your build.gradle:

    compile 'com.google.guava:guava:17.0'
    
    0 讨论(0)
  • 2020-12-22 16:25

    You could use weak references.

    This way you could manage the memory yourself and add and remove observers as you please.

    When you addObserver add these parameters - cast that context from the activity you are adding it in to the empty interface, add a notification name, and call the method to run interface.

    The method to run interface would have a function that is called run to return the data that you are passing something like this

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

    Create a observation class that invokes a reference with a empty interface. Also construct your Themethodtorun interface from the context being passed in the addobserver.

    Add the observation to a data structure.

    To call it would be the same method however all you need to do is find the specific notification name in the data structure, use the Themethodtorun.run(notification_name, data).

    This will send a callback to where ever you created an observer with a specific notification name. Dont forget to remove them when your done!

    This is good reference for weak references.

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

    I am in the process of uploading this code to github. Keep eyes open!

    0 讨论(0)
提交回复
热议问题