এনএসএনটিফিকেশন সেন্টারের সমতুল্য অ্যান্ড্রয়েড


95

অ্যান্ড্রয়েডে আইফোন অ্যাপ্লিকেশন পোর্ট করার প্রক্রিয়াতে, আমি অ্যাপের মধ্যে যোগাযোগের সর্বোত্তম উপায়টি সন্ধান করছি। উদ্দেশ্যগুলি মনে হয় এই পথে যাওয়ার উপায়, এটি কি সেরা (একমাত্র) বিকল্প? এনএসইউসারডিফাল্টগুলি পারফরম্যান্স এবং কোডিং উভয় ক্ষেত্রে ইন্টেন্টের তুলনায় অনেক হালকা ওজন বলে মনে হয়।

আমারও যুক্ত করা উচিত আমার কাছে রাজ্যের জন্য একটি অ্যাপ্লিকেশন সাবক্লাস রয়েছে, তবে আমার অন্য ক্রিয়াকলাপটি একটি ইভেন্ট সম্পর্কে সচেতন করা দরকার।


4
এই বিষয়ে নতুনদের জন্য, দ্বিতীয় উত্তরটি সেরা। নীচে স্ক্রোল করুন ...
স্টিফান

উত্তর:


6

আপনি এটি চেষ্টা করতে পারেন: http://developer.android.com/references/java/util/Oserser.html


42
নীচে শিকির উত্তর আরও ভাল।
dsaff

4
@ ডিএসএফ আরও সম্পূর্ণ উত্তর হওয়া সত্ত্বেও, কোনওভাবেই আমার উত্তর ভুল নয়, আমি স্পষ্টভাবে একটি -১ এর প্রাপ্য নই। শিকির উত্তরটি +1 করা আপনার পক্ষে কী বোঝায়।
রুই পেরেস

4
শিকির প্রশ্নের উত্তম উত্তর
রমজ

4
মনে রাখবেন যে কেবলমাত্র প্রযুক্তিগতভাবে ভুল এবং স্প্যামের উত্তরগুলি হ্রাস করা উচিত - এটি একটির মধ্যেও ফিট করে না। ক্ষতিপূরণের জন্য +1 এবং শিকির জন্যও +1 কারণ এটি দুর্দান্ত উত্তর।

352

আমি খুঁজে পাওয়া সবচেয়ে সমতুল্য হ'ল লোকালড্রোডকাস্টম্যানেজার যা অ্যান্ড্রয়েড সমর্থন প্যাকেজের অংশ ।

লোকালব্রডকাস্টম্যানেজার ডকুমেন্টেশন থেকে:

আপনার প্রক্রিয়াটির মধ্যে স্থানীয় বস্তুগুলিতে ইন্টেন্টসগুলির সম্প্রচারের জন্য নিবন্ধকরণ এবং প্রেরণে সহায়তাকারী সেন্ডব্রোডকাস্ট (ইনটেন্ট) সহ গ্লোবাল ব্রডকাস্টগুলি প্রেরণে এটির বেশ কয়েকটি সুবিধা রয়েছে:

  • আপনি জানেন যে ডেটা আপনি সম্প্রচার করছেন তা আপনার অ্যাপ্লিকেশনটি ছাড়বে না, তাই ব্যক্তিগত ডেটা ফাঁস হওয়ার বিষয়ে চিন্তা করার দরকার নেই।
  • অন্যান্য অ্যাপ্লিকেশনগুলির জন্য এই অ্যাপ্লিকেশনগুলিতে এই সম্প্রচারগুলি প্রেরণ করা সম্ভব নয়, সুতরাং সেগুলি ব্যবহার করতে পারে এমন সুরক্ষা ছিদ্র থাকার বিষয়ে আপনার চিন্তা করার দরকার নেই।
  • সিস্টেমের মাধ্যমে বৈশ্বিক সম্প্রচার পাঠানোর চেয়ে এটি আরও দক্ষ।

এটি ব্যবহার করার সময়, আপনি বলতে পারেন যে একটি Intentএকটি এর সমতুল্য NSNotification। এখানে একটি উদাহরণ:

রিসিভারএকটিভিটি.জভা

একটি ক্রিয়াকলাপ যা ইভেন্টটির জন্য বিজ্ঞপ্তিগুলির জন্য নজর রাখে "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! 

11
Thank you very much for taking the time to write such a helpful, detailed response.
Chris Lacy

14
You probably shouldn't call registerReceiver in your onCreate method as this will leak your Activity and your onDestroy method will never get called. onResume seems a better choice to call registerReceiver, and onPause to call unregisterReceiver.
Stephane JAIS

4
Perfect equivalent to NSNotificationCenter, should be the accepted answer!
Leon Storey

I'd like to point out that using global notifications might lead you to a messed design. Think about what would be the best coupling between your components before jumping to the easy way. Sometimes it's just better to use listeners or something similar to iOS delegate pattern, and so on.
saulobrito

Thanks this worked for me. @Shiki please do you think you could give me your opinion on this question stackoverflow.com/questions/25598696/…
Axel

16

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!


Thanks for your solution! I found that using Bundle params instead of HashMap is more convenient for passing params of different types. There is a nice connection between Intent and Bundle: intent.putExtras(params)
zubko

4

You could use this: http://developer.android.com/reference/android/content/BroadcastReceiver.html, which gives a similar behavior.

You can register receivers programmatically through Context.registerReceiver(BroadcastReceiver, IntentFilter) and it will capture intents sent through Context.sendBroadcast(Intent).

Note, though, that a receiver will not get notifications if its activity (context) has been paused.


A quick design note: BroadcastReceivers and NSNotificationCenter can both operate as a event aggregator. The advantage over Delegates or Observers is that the sender and receiver are decoupled (they actually have message or data coupling but that's one of the weakest coupling types). Edited with correction.
AngraX

4

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'

More suitable for 'model' side code which can be less platform dependent.
karmakaze

2

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

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

I wrote a wrapper that can do this same job, equivalent to iOS using LiveData

Wrapper:

class ObserverNotify {
    private val liveData = MutableLiveData<Nothing>()


    fun postNotification() {
        GlobalScope.launch {
            withContext(Dispatchers.Main) {
                liveData.value = liveData.value
            }
        }
    }

    fun observeForever(observer: () -> Unit) {
        liveData.observeForever { observer() }
    }

    fun observe(owner: LifecycleOwner, observer: () -> Unit) {
        liveData.observe(owner) { observer()}
    }

}

class ObserverNotifyWithData<T> {
    private val liveData = MutableLiveData<T>()


    fun postNotification(data: T) {
        GlobalScope.launch {
            withContext(Dispatchers.Main) {
                liveData.value = data
            }
        }
    }

    fun observeForever(observer: (T) -> Unit) {
        liveData.observeForever { observer(it) }
    }

    fun observe(owner: LifecycleOwner, observer: (T) -> Unit) {
        liveData.observe(owner) { observer(it) }
    }

}

Declaring observer types:

object ObserverCenter {
    val moveMusicToBeTheNextOne: ObserverNotifyWithData<Music> by lazy { ObserverNotifyWithData() }
    val playNextMusic: ObserverNotify by lazy { ObserverNotify() }
    val newFCMTokenDidHandle: ObserverNotifyWithData<String?> by lazy { ObserverNotifyWithData() }
}

In the activity to observe:

ObserverCenter.newFCMTokenDidHandle.observe(this) {
    // Do stuff
}

To notify:

ObserverCenter.playNextMusic.postNotification()
ObserverCenter.newFCMTokenDidHandle.postNotification("MyData")
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.