如何在Fragment中向Broadcast Receiver传递类对象?
问题描述
我需要在Fragment中向Broadcast Receiver传递一个类对象,但直接在Receiver中new Fragment实例并调用其对象时,该对象始终为null。比如我实现了一个处理自定义Notification布局事件的Receiver类,除了record.pause()操作外其他功能都正常——Receiver中的MediaRecorder对象一直是null,但在录制音频的Sample_Fragment中该对象明明不为null,导致无法停止录制。
我的Receiver代码如下:
public class Sample_Receiver extends BroadcastReceiver { Sample_Fragment fragment = new Sample_Fragment(); @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("pause".equalsIgnoreCase(action)) { record.pause(); } } }
问题原因
核心问题是在Receiver中new了一个全新的Sample_Fragment实例,这个实例和正在运行的、持有有效MediaRecorder对象的Fragment完全不是同一个,所以自然无法获取到已初始化的record对象。
解决方法
方法一:使用Fragment内部的BroadcastReceiver
直接在Sample_Fragment中定义内部BroadcastReceiver,这样Receiver可以直接访问Fragment中的成员变量(包括MediaRecorder对象),无需跨实例传递:
public class Sample_Fragment extends Fragment { private MediaRecorder record; private BroadcastReceiver sampleReceiver; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化MediaRecorder record = new MediaRecorder(); //... 其他初始化操作 // 注册内部Receiver sampleReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("pause".equalsIgnoreCase(action)) { if (record != null) { record.pause(); } } } }; IntentFilter filter = new IntentFilter("pause"); requireContext().registerReceiver(sampleReceiver, filter); } @Override public void onDestroy() { super.onDestroy(); // 记得注销Receiver,避免内存泄漏 if (sampleReceiver != null) { requireContext().unregisterReceiver(sampleReceiver); } } }
方法二:通过ViewModel共享状态
通过ViewModel在Fragment和Receiver之间共享录制状态和控制逻辑,Receiver可以通过ViewModel获取到当前有效的MediaRecorder实例:
public class RecordViewModel extends ViewModel { private MediaRecorder record; public void initRecorder() { record = new MediaRecorder(); //... 初始化操作 } public void pauseRecord() { if (record != null) { record.pause(); } } }
在Fragment中初始化ViewModel:
public class Sample_Fragment extends Fragment { private RecordViewModel viewModel; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(requireActivity()).get(RecordViewModel.class); viewModel.initRecorder(); } }
在Receiver中获取ViewModel并调用方法:
public class Sample_Receiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("pause".equalsIgnoreCase(action)) { if (context instanceof Activity) { RecordViewModel viewModel = new ViewModelProvider((Activity) context).get(RecordViewModel.class); viewModel.pauseRecord(); } } } }
方法三:传递Parcelable封装对象(适用于独立Receiver)
如果必须使用独立的Receiver类,可以将录制相关状态封装成实现Parcelable接口的类,通过Intent传递给Receiver:
- 封装状态类:
public class RecordControlInfo implements Parcelable { // 可添加录制会话标识、状态等信息 private String sessionId; protected RecordControlInfo(Parcel in) { sessionId = in.readString(); } public RecordControlInfo(String sessionId) { this.sessionId = sessionId; } public static final Creator<RecordControlInfo> CREATOR = new Creator<RecordControlInfo>() { @Override public RecordControlInfo createFromParcel(Parcel in) { return new RecordControlInfo(in); } @Override public RecordControlInfo[] newArray(int size) { return new RecordControlInfo[size]; } }; public String getSessionId() { return sessionId; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(sessionId); } }
- Fragment发送广播时传递:
String sessionId = "current_record_session"; Intent intent = new Intent("pause"); intent.putExtra("record_info", new RecordControlInfo(sessionId)); requireContext().sendBroadcast(intent);
- Receiver中接收并处理:
public class Sample_Receiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("pause".equalsIgnoreCase(action)) { RecordControlInfo info = intent.getParcelableExtra("record_info"); // 根据sessionId获取对应的录制实例(比如通过全局单例、ViewModel等方式) } } }
更新:我已经通过使用内部BroadcastReceiver的方式解决了这个问题。
内容的提问来源于stack exchange,提问作者A.G

