NSNotificationCenter와 동등한 Android


95

아이폰 애플리케이션을 안드로이드로 포팅하는 과정에서 앱 내에서 소통하는 가장 좋은 방법을 찾고 있습니다. 인 텐트가가는 길인 것 같습니다. 이것이 최선의 (유일한) 옵션입니까? NSUserDefaults는 성능과 코딩 모두에서 Intents보다 훨씬 가볍습니다.

또한 상태에 대한 애플리케이션 하위 클래스가 있지만 다른 활동에서 이벤트를 인식하도록해야합니다.


3
이 주제를 처음 접하는 사람들에게는 두 번째 답변이 가장 좋습니다. 아래로 스크롤 ...
Stephan

답변:


6

이것을 시도해 볼 수 있습니다 : http://developer.android.com/reference/java/util/Observer.html


42
아래 Shiki의 답변이 훨씬 좋습니다.
dsaff

5
@dsaff는 더 완전한 대답 임에도 불구하고 내 대답이 틀린 것은 아니지만 분명히 -1을받을 자격이 없습니다. 당신이 Shiki의 대답을 +1하는 것이 의미가 있습니다.
Rui Peres

4
시키의 질문에 대한 좋은 답변입니다
Ramz

4
기술적으로 부정확하고 스팸 답변 만 반대 투표해야합니다.이 답변은 어느 쪽에도 적합하지 않습니다. 보상에 +1하고 Shiki에 대해서도 +1합니다.

351

내가 찾은 가장 좋은 것은 Android 지원 패키지의 일부인 LocalBroadcastManager 입니다 .

LocalBroadcastManager 문서에서 :

프로세스 내의 로컬 개체에 인 텐트 브로드 캐스트를 등록하고 전송하는 도우미입니다. 이것은 sendBroadcast (Intent)를 사용하여 글로벌 브로드 캐스트를 보내는 것보다 많은 이점이 있습니다.

  • 브로드 캐스팅중인 데이터가 앱을 떠나지 않을 것임을 알고 있으므로 개인 데이터 유출에 대해 걱정할 필요가 없습니다.
  • 다른 애플리케이션이 이러한 브로드 캐스트를 앱에 보낼 수 없으므로 악용 할 수있는 보안 허점에 대해 걱정할 필요가 없습니다.
  • 시스템을 통해 글로벌 브로드 캐스트를 보내는 것보다 더 효율적입니다.

이것을 사용할 때 an 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

알림을 보내거나 브로드 캐스트하는 두 번째 활동입니다.

@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
시간을내어 유용하고 상세한 답변을 작성해 주셔서 대단히 감사합니다.
Chris Lacy 2012

14
onCreate 메서드에서 registerReceiver를 호출하면 활동이 유출되고 onDestroy 메서드가 호출되지 않으므로 아마 호출해서는 안됩니다. onResume은 registerReceiver를 호출하는 것이 더 나은 선택이고, onPause는 unregisterReceiver를 호출하는 것 같습니다.
스테판 Jais에

4
에 완벽하게 해당하는 NSNotificationCenter답이 허용되어야합니다!
Leon Storey

전역 알림을 사용하면 디자인이 엉망이 될 수 있음을 지적하고 싶습니다. 쉬운 방법으로 이동하기 전에 구성 요소 간의 최상의 결합이 무엇인지 생각해보십시오. 때로는 리스너 또는 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();
    }
}

마지막으로 콜백 또는 휴식 서비스 등에서 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것이 다른 유형의 매개 변수를 전달하는 데 더 편리 하다는 것을 알았습니다 . 이 사이 좋은 연결은 IntentBundle:intent.putExtras(params)
zubko

4

비슷한 동작을 제공하는 http://developer.android.com/reference/android/content/BroadcastReceiver.html을 사용할 수 있습니다 .

Context.registerReceiver (BroadcastReceiver, IntentFilter)를 통해 프로그래밍 방식으로 수신자를 등록 할 수 있으며 Context.sendBroadcast (Intent)를 통해 전송 된 인 텐트를 캡처합니다.

하지만 수신자는 활동 (컨텍스트)이 일시 중지 된 경우 알림을받지 않습니다.


빠른 디자인 노트 : BroadcastReceivers 및 NSNotificationCenter는 둘 다 이벤트 수집기로 작동 할 수 있습니다. 델리게이트 또는 옵저버에 비해 장점은 발신자와 수신자가 분리된다는 것입니다 (실제로 메시지 또는 데이터 결합이 있지만 가장 약한 결합 유형 중 하나입니다). 수정하여 편집했습니다.
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 Studio에서 간단히이 lib를 추가 할 수 있습니다.

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

플랫폼에 덜 의존 할 수있는 '모델'측 코드에 더 적합합니다.
karmakaze

2

Kotlin : 조각에서 약간의 리팩터링이있는 Kotlin의 @Shiki 버전이 있습니다.

  1. 조각에 관찰자를 등록합니다.

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를 추가 할 수 있습니다. 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.