NS Notification Center와 동등한 Android
아이폰 앱을 안드로이드로 포팅하는 과정에서, 저는 앱 내에서 가장 좋은 의사소통 방법을 찾고 있습니다.의도가 최선인 것 같은데, 이게 최선의 선택인가요?NSUserDefaults는 성능과 코딩 모두에서 Intents보다 훨씬 가벼운 것 같습니다.
또한 상태를 위한 애플리케이션 하위 클래스가 있지만 다른 활동으로 이벤트를 알려야 합니다.
제가 찾은 가장 좋은 제품은 Android 지원 패키지의 일부인 Local Broadcast Manager입니다.
Local Broadcast Manager 설명서에서 다음을 참조하십시오.
프로세스 내의 로컬 개체에 의도 브로드캐스트를 등록하고 전송하는 도우미입니다.이는 sendBroadcast(의도)를 사용하여 글로벌 브로드캐스트를 전송하는 것에 비해 여러 가지 이점이 있습니다.
- 브로드캐스트하는 데이터가 앱에서 떠나지 않는다는 것을 알고 있으므로 개인 데이터 유출에 대해 걱정할 필요가 없습니다.
- 다른 응용 프로그램에서는 이러한 브로드캐스트를 사용자의 응용 프로그램으로 보낼 수 없으므로 악용할 수 있는 보안 구멍에 대해 걱정할 필요가 없습니다.
- 시스템을 통해 글로벌 방송을 보내는 것보다 효율적입니다.
할 때, 은 이을사용때, 은당말수있다니습할라고 수 .Intent
는 는에 해다니합에 합니다.NSNotification
다음은 예입니다.
수신기 활동.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!
여기 @Shiki 답변과 유사한 내용이 있지만 iOS 개발자와 Notification 센터의 관점에서 볼 수 있습니다.
먼저 다음과 같은 종류의 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();
}
}
마지막으로 콜백 또는 휴식 서비스 등에서 Notification Center에 알림을 게시하는 방법은 다음과 같습니다.
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);
}
바로 그거야, 건배!
당신은 이것을 시도할 수 있습니다: http://developer.android.com/reference/java/util/Observer.html
나는 구성 요소가 서로 명시적으로 등록할 필요 없이 구성 요소 간에 게시-구독 방식의 통신을 위한 가장 간단한 방법이 Guavalb의 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'
유사한 동작을 제공하는 http://developer.android.com/reference/android/content/BroadcastReceiver.html, 를 사용할 수 있습니다.
Context.registerReceiver(BroadcastReceiver, IntentFilter)를 통해 프로그래밍 방식으로 수신기를 등록할 수 있으며 Context를 통해 전송된 의도를 캡처합니다.브로드캐스트를 송신합니다.
그러나 활동(컨텍스트)이 일시 중지된 경우 수신기는 알림을 받지 않습니다.
코틀린: 여기 코틀린의 @Shiki 버전이 있습니다. 단편에 약간의 리팩터가 있습니다.
- 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))
}
}
아무 곳에나 알림을 게시합니다.당신만 상황을 파악하면 됩니다.
LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(Constant.NOTIFICATION_SOMETHING_HAPPEN))```
PS:
- 알림을 잘 구성하기 위해 저처럼 Constant.kt를 추가할 수 있습니다.상수.kt
object Constant {
const val NOTIFICATION_SOMETHING_HAPPEN = "notification_something_happened_locally"
}
- 는 fragment 컨트에대다사의용수있할다습니을음해텍스▁의▁use▁ 사용할 수 있습니다.
activity
)null
) 또는conext
내가 사용했던 것처럼.
라이브데이터를 사용하여 iOS와 동일한 작업을 수행할 수 있는 래퍼를 작성했습니다.
포장지:
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) }
}
}
관찰자 유형 선언:
object ObserverCenter {
val moveMusicToBeTheNextOne: ObserverNotifyWithData<Music> by lazy { ObserverNotifyWithData() }
val playNextMusic: ObserverNotify by lazy { ObserverNotify() }
val newFCMTokenDidHandle: ObserverNotifyWithData<String?> by lazy { ObserverNotifyWithData() }
}
관찰 활동:
ObserverCenter.newFCMTokenDidHandle.observe(this) {
// Do stuff
}
통지하기:
ObserverCenter.playNextMusic.postNotification()
ObserverCenter.newFCMTokenDidHandle.postNotification("MyData")
@Shiki의 답은 2020년 6월에 맞을 수 있지만, 2022년 1월에 Local Broadcast Manager는 사용되지 않게 되었습니다.
이틀 동안 조사한 결과, SharedFlow는 Android에서 "모든 콘텐츠가 동시에 정기적으로 새로 고쳐지도록 앱의 나머지 부분에 눈금을 보내라"고 지시했다는 사실을 알게 되었습니다.
NS Notification Center of Swift에서 기대할 수 있는 것을 의미합니다.
다음은 앱에서 Shared Flow를 구현한 방법입니다.
먼저 실제로 활동에 대한 공유 View 모델인 InAppNotif Singleton을 생성해야 합니다(마지막 시점까지 주의: 모든 앱^^이 아닌 활동에 대해 공유됨).
enum class InAppNotifName {
NotifNameNumber1,
NotifNameNumber2,
NotifNameNumber3
}
object InAppNotif: ViewModel() {
private val _sharedNotif = MutableSharedFlow<InAppNotifName>(0)
val sharedNotif: SharedFlow<InAppNotifName> = _sharedNotif.asSharedFlow()
private fun sendNotif(name: InAppNotifName) {
CoroutineScope(Default).launch {
_sharedNotif.emit(name)
}
}
public fun notifyNotif1() {
sendNotif(InAppNotifName.NotifNameNumber1)
}
public fun notifyNotif2() {
sendNotif(InAppNotifName.NotifNameNumber1)
}
public fun notifyNotif3() {
sendNotif(InAppNotifName.NotifNameNumber1)
}
}
두 번째 단계, 앱 알림에서 수신하는 조각이 많고 반복하지 않으려는 경우에만 필요한 것은 "수신 알림" 인터페이스를 만드는 것입니다.
fun AnyReceivingNotif.observeInAppNotif() {
CoroutineScope(Default).launch {
InAppNotif.sharedNotif.collect {
onReceivingInAppNotif(it)
}
}
}
interface AnyReceivingNotif {
suspend fun onReceivingInAppNotif(value: InAppNotifName)
}
그런데 "일시 중지"라는 단어는 알림을 수신할 때 UI를 업데이트해야 하는 경우에만 유용합니다.
마지막으로 InAppNotif를 수신할 개체에서 AnyReceivingNotif 인터페이스를 준수하도록 한 다음 onReceivingInAppNotif 함수를 완료하기만 하면 됩니다.
class MyFragment: Fragment(), AnyReceivingNotif {
override suspend fun onReceivingInAppNotif(value: InAppNotifName) {
when (value) {
InAppNotifName.NotifNameNumber1 -> { /* Do complicated things */ }
InAppNotifName.NotifNameNumber2 -> { /* Do some stuff */ }
InAppNotifName.NotifNameNumber3 -> {
withContext(Default){
/* Update the UI */
}
}
}
}
}
약한 참조를 사용할 수 있습니다.
이렇게 하면 직접 메모리를 관리하고 원하는 대로 관찰자를 추가하거나 제거할 수 있습니다.
관찰자를 추가할 때 - 추가할 활동에서 컨텍스트를 빈 인터페이스로 캐스트하고 알림 이름을 추가한 후 인터페이스를 실행할 메서드를 호출합니다.
인터페이스를 실행하는 방법은 다음과 같은 것을 전달하는 데이터를 반환하기 위해 실행이라고 하는 기능을 가지고 있을 것입니다.
public static interface Themethodtorun {
void run(String notification_name, Object additional_data);
}
빈 인터페이스를 사용하여 참조를 호출하는 관찰 클래스를 만듭니다.또한 추가 관찰자에서 전달되는 컨텍스트에서 실행할 메소드 인터페이스를 구성합니다.
관찰을 데이터 구조에 추가합니다.
동일한 방법으로 호출하지만 데이터 구조에서 특정 알림 이름을 찾기만 하면 됩니다. Themethodtorun.run(notificationn_name, data)을 사용하십시오.
그러면 특정 알림 이름을 가진 관찰자를 만든 곳으로 다시 호출이 전송됩니다.작업이 끝나면 그것들을 제거하는 것을 잊지 마십시오.
이것은 약한 참조에 대한 좋은 참조입니다.
http://learningviacode.blogspot.co.nz/2014/02/weak-references-in-java.html
나는 이 코드를 github에 업로드하는 중입니다.눈을 뜨고 지켜요!
언급URL : https://stackoverflow.com/questions/3947641/android-equivalent-to-nsnotificationcenter
'programing' 카테고리의 다른 글
NSMutableArray를 NSAray로 변환하려면 어떻게 해야 합니까? (0) | 2023.05.31 |
---|---|
:active pseudo-class는 모바일 사파리에서 작동하지 않습니다. (0) | 2023.05.31 |
iPhone의 NS 문자열에 대한 AES 암호화 (0) | 2023.05.31 |
Mac 키보드를 사용하여 iphone 시뮬레이터의 텍스트 필드를 입력할 수 없습니까? (0) | 2023.05.31 |
아이폰 사진 라이브러리에 사진을 저장하는 방법은 무엇입니까? (0) | 2023.05.31 |