首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Android 給棧中非顯示 Activity 傳值:廣播/EventBus/共享 ViewModel 三種方案

     編輯:程式設計疑難解答

需求:向返回棧中**非當前頂部**的 `Activity` 傳遞資料(如登入成功後通知主頁面刷新)。該 `Activity` 可能處於 `onPause`/`onStop` 狀態。本文提供三種標準方案。

方案一:本地廣播 `LocalBroadcastManager` (輕量、無第三方依賴)

// 1. 發送端 (任意位置:Service、BroadcastReceiver、另一 Activity)
Intent intent = new Intent("ACTION_USER_LOGGED_IN");
intent.putExtra("userId", 12345);
intent.putExtra("token", "abcxyz");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

// 2. 接收端 (目標 Activity)
private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if ("ACTION_USER_LOGGED_IN".equals(intent.getAction())) {
            int userId = intent.getIntExtra("userId", -1);
            String token = intent.getStringExtra("token");
            // 更新 UI、刷新資料
            runOnUiThread(() -> refreshHeader(userId, token));
        }
    }
};

@Override
protected void onResume() {
    super.onResume();
    LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
        new IntentFilter("ACTION_USER_LOGGED_IN"));
}

@Override
protected void onPause() {
    super.onPause();
    LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}

方案二:EventBus / RxBus / LiveData Bus (解耦、支援粘性事件)

// 事件類別
public class UserLoginEvent {
    public final int userId;
    public final String token;
    public UserLoginEvent(int userId, String token) {
        this.userId = userId; this.token = token;
    }
}

// 發送 (任意執行緒)
EventBus.getDefault().post(new UserLoginEvent(12345, "abcxyz"));
// 或粘性事件:postSticky(...) → 晚註冊者也能收到

// 接收 (目標 Activity)
@Subscribe(threadMode = ThreadMode.MAIN)  // 自動切主執行緒
public void onUserLogin(UserLoginEvent event) {
    refreshHeader(event.userId, event.token);
}

@Override protected void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
@Override protected void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}

方案三:共享 `ViewModel` (Jetpack 標準、生命週期感知、配置變更存活)

// 共享 ViewModel (範圍可為 Application 或 Activity)
public class SharedViewModel extends ViewModel {
    private final MutableLiveData _user = new MutableLiveData<>();
    public LiveData user = _user;

    public void setUser(User user) { _user.setValue(user); }
}

// 發送端 (登入 Activity/Fragment)
SharedViewModel vm = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
vm.setUser(new User(12345, "abcxyz"));

// 接收端 (主頁 Activity/Fragment)
SharedViewModel vm = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
vm.user.observe(getViewLifecycleOwner(), user -> {
    if (user != null) refreshHeader(user.id, user.token);
});

三方案對比

方案優點缺點適用場景
LocalBroadcastManager系統 API、無依賴、進程內安全需手動註冊/註銷、無粘性、跨進程需系統廣播簡單通知、無第三方庫限制
EventBusAPI 簡潔、支援粘性、執行緒模式豐富第三方庫、全域單例可能洩漏、過度使用導致流程難追蹤中大型專案、複雜事件流
共享 ViewModel生命週期感知、配置變更存活、型別安全、可測試需 Jetpack、範圍限定於同一 Activity/Application**現代首選**、Fragment/Activity 間共享資料

關鍵提醒

  • **不要嘗試直接持有目標 Activity 實例** → 記憶體洩漏、生命週期錯亂
  • 廣播/EventBus 發送時目標 Activity 可能處於 `onStop`,**接收端在 `onResume`/`onStart` 註冊**即可收到後續事件
  • 需「即時收到最後一次資料」→ 用 EventBus `postSticky` 或 `LiveData` (觀察者自動拿最新值)
  • 跨進程傳值 → 必須用系統廣播 `sendBroadcast` + `Intent` + 完整權限聲明

根據專案架構選擇:輕量用 `LocalBroadcastManager`,現代 Jetpack 用 `Shared ViewModel`,複雜事件流用 `EventBus`。核心都是**發送端不持有接收端引用,接收端在生命週期方法中註冊監聽**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved