Android NSNotificationCenter के बराबर


95

एंड्रॉइड पर एक iPhone एप्लिकेशन को पोर्ट करने की प्रक्रिया में, मैं ऐप के भीतर संवाद करने का सबसे अच्छा तरीका ढूंढ रहा हूं। इरादे जाने का रास्ता प्रतीत होता है, क्या यह सबसे अच्छा (केवल) विकल्प है? NSUserDefaults प्रदर्शन और कोडिंग दोनों में इंटेंट्स की तुलना में बहुत हल्का लगता है।

मुझे यह भी जोड़ना चाहिए कि मेरे पास राज्य के लिए एक एप्लिकेशन उपवर्ग है, लेकिन मुझे किसी अन्य गतिविधि को एक घटना से अवगत कराने की आवश्यकता है।


3
इस विषय के नए लोगों के लिए, दूसरा उत्तर सबसे अच्छा है। नीचे स्क्रॉल करें ...
Stephan

जवाबों:


5

आप यह कोशिश कर सकते हैं: http://developer.android.com/reference/java/util/Observer.html


42
शिकी का जवाब नीचे बेहतर है।
dsaff

5
@dsaff अधिक पूर्ण उत्तर होने के बावजूद, किसी भी तरह से मेरा उत्तर गलत नहीं है, मैं स्पष्ट रूप से -1 के लायक नहीं हूं। क्या मतलब है आप के लिए +1 Shiki के जवाब के लिए है।
रुई पेरेस

4
सवाल के लिए शिकी का बेहतर जवाब है
रमज़

4
ध्यान दें कि केवल तकनीकी रूप से गलत और स्पैम उत्तरों को डाउनवोट किया जाना चाहिए - यह न तो फिट बैठता है। मुआवजे के लिए +1 और शिकी के लिए भी +1 क्योंकि यह एक बेहतरीन जवाब है।

351

मुझे मिला सबसे अच्छा समकक्ष LocalBroadcastManager है जो Android समर्थन पैकेज का हिस्सा है ।

LocalBroadcastManager प्रलेखन से:

आपकी प्रक्रिया के भीतर स्थानीय वस्तुओं के इरादों के प्रसारण के लिए पंजीकरण करने और भेजने के लिए हेल्पर। यह SendBroadcast (इरादे) के साथ वैश्विक प्रसारण भेजने पर कई फायदे हैं:

  • आप जानते हैं कि आप जो डेटा प्रसारित कर रहे हैं, वह आपके ऐप को नहीं छोड़ेगा, इसलिए निजी डेटा को लीक करने के बारे में चिंता करने की ज़रूरत नहीं है।
  • अन्य अनुप्रयोगों के लिए इन प्रसारणों को अपने ऐप पर भेजना संभव नहीं है, इसलिए आपको सुरक्षा छेद होने की चिंता करने की आवश्यकता नहीं है जो वे शोषण कर सकते हैं।
  • यह सिस्टम के माध्यम से वैश्विक प्रसारण भेजने से अधिक कुशल है।

इसका उपयोग करते समय, आप कह सकते हैं कि 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

दूसरी गतिविधि जो सूचनाएं भेजती / प्रसारित करती है।

@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है 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
इतनी मददगार, विस्तृत प्रतिक्रिया लिखने के लिए समय निकालने के लिए बहुत-बहुत धन्यवाद।
क्रिस लैसी

14
आपको संभवतः अपने ऑनक्रिट विधि में registerReceiver को कॉल नहीं करना चाहिए क्योंकि इससे आपकी गतिविधि लीक हो जाएगी और आपका onDestroy तरीका कभी भी कॉल नहीं किया जाएगा। onResume registerReceiver को कॉल करने के लिए एक बेहतर विकल्प लगता है, और unregisterReceiver को कॉल करने के लिए onPause।
स्टीफन जेएआईएस

4
बिल्कुल सही NSNotificationCenter, स्वीकृत उत्तर होना चाहिए!
लियोन स्टोरी

मैं यह बताना चाहता हूं कि वैश्विक सूचनाओं का उपयोग करने से आप एक गड़बड़ डिजाइन को जन्म दे सकते हैं। आसान तरीके से कूदने से पहले अपने घटकों के बीच सबसे अच्छा युग्मन क्या होगा, इसके बारे में सोचें। कभी-कभी श्रोताओं या आईओएस प्रतिनिधि पैटर्न के समान कुछ का उपयोग करना बेहतर होता है, और इसी तरह।
सैलोब्रिटो

धन्यवाद यह मेरे लिए काम किया। @ शकी कृपया क्या आपको लगता है कि आप मुझे इस सवाल पर अपनी राय दे सकते हैं stackoverflow.com/questions/25598696/…
Axel

16

यहाँ @Shiki उत्तर के समान कुछ है, लेकिन iOS डेवलपर्स और अधिसूचना केंद्र के कोण से।

पहले किसी प्रकार की अधिसूचना सूचना सेवा बनाएँ:

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

और अंत में हम कुछ कॉलबैक या बाकी सेवा या जो कुछ भी है, से अधिसूचना अधिसूचना में पोस्ट करते हैं:

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अधिक सुविधाजनक है। के बीच एक अच्छा संबंध है Intentऔर Bundle:intent.putExtras(params)
zubko

4

आप इसका उपयोग कर सकते हैं: http://developer.android.com/reference/android/content/BroadcastReceiver.html , जो समान व्यवहार देता है।

आप Context.registerReceiver (BroadcastReceiver, IntentFilter) के माध्यम से रिसीवर को प्रोग्रामेटिक रूप से पंजीकृत कर सकते हैं और यह Context.sendBroadcast (Intent) के माध्यम से भेजे गए इंटेंट्स को कैप्चर करेगा।

ध्यान दें, हालांकि, एक रिसीवर को सूचनाएं नहीं मिलेंगी यदि उसकी गतिविधि (संदर्भ) रोक दी गई है।


एक त्वरित डिजाइन नोट: ब्रॉडकास्टसीवर्स और NSNotificationCenter दोनों एक इवेंट एग्रीगेटर के रूप में काम कर सकते हैं। डेलिगेट्स या ऑब्जर्वर पर लाभ यह है कि प्रेषक और रिसीवर को डिकूप्ड किया जाता है (उनके पास वास्तव में संदेश या डेटा युग्मन है लेकिन यह सबसे कमजोर युग्मन प्रकारों में से एक है)। सुधार के साथ संपादित।
अंगरेजी

4

मैंने पाया कि गुवा लिब के ईवेंटबस का उपयोग घटकों के बीच प्रकाशित-सदस्यता-शैली संचार के लिए सबसे सरल तरीका है, घटकों को स्पष्ट रूप से एक दूसरे के साथ रजिस्टर करने की आवश्यकता के बिना।

https://code.google.com/p/guava-lbooks/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 पर निर्भरता जोड़कर बस एंड्रॉइड स्टूडियो पर इस काम को जोड़ सकते हैं:

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

'मॉडल' साइड कोड के लिए अधिक उपयुक्त है जो कम प्लेटफॉर्म पर निर्भर हो सकता है।
कर्मकाज़े

2

कोटलिन : यहां एक खंड में थोड़ा सा रिफ्लेक्टर के साथ कोटलिन में @ शिकी का संस्करण है।

  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))```

पुनश्च :

  1. आप अच्छी तरह से सूचनाओं को व्यवस्थित करने के लिए मेरी तरह एक कॉन्स्टेंट.कैट जोड़ सकते हैं। Constant.kt
object Constant {
    const val NOTIFICATION_SOMETHING_HAPPEN = "notification_something_happened_locally"
}
  1. एक टुकड़े में संदर्भ के लिए, आप activity(कभी-कभी null) या conextजैसे मैंने क्या उपयोग किया।

0

आप कमजोर संदर्भों का उपयोग कर सकते हैं।

इस तरह से आप मेमोरी को स्वयं प्रबंधित कर सकते हैं और कृपया पर्यवेक्षकों को जोड़ सकते हैं और हटा सकते हैं।

जब आप addObserver इन मापदंडों को जोड़ते हैं - उस संदर्भ को उस गतिविधि से डालें जिसे आप इसे खाली इंटरफ़ेस में जोड़ रहे हैं, एक अधिसूचना नाम जोड़ें, और इंटरफ़ेस चलाने के लिए विधि को कॉल करें।

इंटरफ़ेस चलाने की विधि में एक फ़ंक्शन होता है जिसे डेटा को वापस करने के लिए रन कहा जाता है जो आप कुछ इस तरह से गुजर रहे हैं

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

एक अवलोकन वर्ग बनाएं जो एक खाली इंटरफ़ेस के साथ एक संदर्भ देता है। Addobserver में दिए जा रहे संदर्भ से अपने Themethodtorun इंटरफ़ेस का निर्माण भी करें।

डेटा संरचना में अवलोकन जोड़ें।

इसे कॉल करने के लिए एक ही तरीका होगा, हालांकि आपको केवल डेटा संरचना में विशिष्ट अधिसूचना नाम ढूंढना होगा, Themethodtorun.run (सूचना_नाम, डेटा) का उपयोग करें।

यह एक कॉलबैक भेजेगा जहां आपने एक विशिष्ट अधिसूचना नाम के साथ एक पर्यवेक्षक बनाया है। जब आपका किया उन्हें हटाने के लिए मत भूलना!

कमजोर संदर्भों के लिए यह अच्छा संदर्भ है।

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

मैं इस कोड को जीथब पर अपलोड करने की प्रक्रिया में हूं। आंखें खुली रखें!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.