扩展设备控制应用时,复用UI与ViewModel遇DeviceBaseViewModel实例创建异常,求DRY方案
多设备功能共享的正确实现方案(遵循DRY原则)
先解释你遇到的异常原因
你触发的RuntimeException本质是:DeviceBaseViewModel要么是抽象类,要么ViewModelProvider无法自动实例化它——ViewModelProvider默认只能创建有公共无参构造的非抽象类实例,直接请求父类ViewModel时,系统不知道该实例化哪个子类实现,自然抛出无法创建实例的错误。
调整后的完整实现方案
1. 重构ViewModel层级
- 将
DeviceBaseViewModel定义为抽象类,封装所有通用逻辑(比如设备连接、状态同步、通用控制方法),只保留共享功能的实现,设备专属逻辑用抽象方法预留:
public abstract class DeviceBaseViewModel extends ViewModel { // 共享功能:通用设备连接逻辑 public void connectDevice() { // 通用连接代码,比如蓝牙/网络连接模板 } // 共享功能:通用状态监听 public MutableLiveData<DeviceState> getDeviceState() { // 返回通用状态LiveData } // 抽象方法:设备专属操作,由子类实现 public abstract void executeExclusiveAction(); }
- 每个设备创建子类ViewModel(比如
DeviceXViewModel、DeviceYViewModel),继承DeviceBaseViewModel,实现专属逻辑,且确保子类有公共无参构造(如果需要依赖注入,可自定义ViewModelFactory,这里先讲基础场景):
public class DeviceXViewModel extends DeviceBaseViewModel { @Override public void executeExclusiveAction() { // 设备X的专属操作逻辑 } }
2. 共享Fragment的适配改造
共享Fragment不再直接请求父类ViewModel,而是通过泛型适配不同子类ViewModel,确保获取到的是当前Activity对应的设备专属ViewModel:
public class DeviceSharedFragment<T extends DeviceBaseViewModel> extends Fragment { protected T viewModel; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 通过泛型反射获取ViewModel类型 Class<T> viewModelClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; viewModel = new ViewModelProvider(getActivity()).get(viewModelClass); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_device_shared, container, false); // 绑定共享UI,调用ViewModel的共享方法 view.findViewById(R.id.btn_connect).setOnClickListener(v -> viewModel.connectDevice()); // 绑定专属操作按钮,调用ViewModel的抽象方法(由子类实现) view.findViewById(R.id.btn_exclusive).setOnClickListener(v -> viewModel.executeExclusiveAction()); return view; } } // 设备X的共享Fragment(直接复用通用逻辑) public class DeviceXSharedFragment extends DeviceSharedFragment<DeviceXViewModel> {}
3. Activity的组合逻辑
创建通用父类Activity封装模板代码,每个设备的Activity继承后仅需指定对应的ViewModel和Fragment:
public abstract class BaseDeviceActivity<T extends DeviceBaseViewModel> extends AppCompatActivity { protected T viewModel; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base_device); // 初始化当前设备的ViewModel viewModel = new ViewModelProvider(this).get(getViewModelClass()); // 加载共享Fragment getSupportFragmentManager().beginTransaction() .replace(R.id.fl_shared_container, getSharedFragment()) .commit(); // 加载设备专属Fragment getSupportFragmentManager().beginTransaction() .replace(R.id.fl_exclusive_container, getExclusiveFragment()) .commit(); } // 子类需实现的抽象方法:返回当前设备的ViewModel类 protected abstract Class<T> getViewModelClass(); // 返回当前设备的共享Fragment实例 protected abstract Fragment getSharedFragment(); // 返回当前设备的专属Fragment实例 protected abstract Fragment getExclusiveFragment(); } // 设备X的Activity public class DeviceXActivity extends BaseDeviceActivity<DeviceXViewModel> { @Override protected Class<DeviceXViewModel> getViewModelClass() { return DeviceXViewModel.class; } @Override protected Fragment getSharedFragment() { return new DeviceXSharedFragment(); } @Override protected Fragment getExclusiveFragment() { return new DeviceXExclusiveFragment(); } }
内容的提问来源于stack exchange,提问作者Niklas Dada
相关产品推荐
相关产品推荐

