如何在MVVM+DataBinding中无需Activity控制EditText焦点
嘿,这个需求完全可以通过 ViewModel + DataBinding 实现,不用在 Activity 里写任何业务逻辑,我给你拆解一下具体步骤和代码:
实现步骤详解
1. 编写 ViewModel 核心逻辑
ViewModel 要负责从 SharedPreference 读取用户信息,同时提供可观察的用户名和焦点请求事件。这里我们用 AndroidViewModel 获取 Application 上下文(避免直接持有 Activity Context),用 ObservableField 自动更新 UI,SingleLiveEvent 处理一次性的焦点请求:
public class StartGameViewModel extends AndroidViewModel { // 用于自动同步更新 EditText1 的用户名 public final ObservableField<String> userName = new ObservableField<>(); // 一次性触发 EditText2 获取焦点的事件(用 SingleLiveEvent 避免重复触发) public final SingleLiveEvent<Boolean> requestEditText2Focus = new SingleLiveEvent<>(); public StartGameViewModel(@NonNull Application application) { super(application); // 初始化时自动读取 SharedPreference loadUserFromSharedPrefs(); } private void loadUserFromSharedPrefs() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplication()); String savedUserName = prefs.getString("USER_NAME_KEY", null); if (savedUserName != null) { userName.set(savedUserName); // 成功获取到用户后,触发 EditText2 的焦点请求 requestEditText2Focus.setValue(true); } } }
2. 自定义 BindingAdapter 处理焦点请求
因为 DataBinding 没有原生属性直接绑定焦点请求,我们需要写一个自定义的 BindingAdapter,把 ViewModel 的事件和 EditText 的焦点操作关联起来:
public class ViewBindingAdapters { @BindingAdapter("requestFocus") public static void requestFocus(EditText editText, Boolean shouldRequestFocus) { if (shouldRequestFocus != null && shouldRequestFocus) { editText.requestFocus(); // 可选:自动弹出软键盘,提升用户体验 InputMethodManager imm = (InputMethodManager) editText.getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); } } }
3. 编写 XML 布局(DataBinding 绑定)
在布局里启用 DataBinding,绑定 ViewModel 的字段和自定义的焦点属性:
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewModel" type="com.yourpackage.StartGameViewModel" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <!-- EditText1 自动绑定用户名 --> <EditText android:id="@+id/editText1" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="用户名" android:text="@{viewModel.userName}" /> <!-- EditText2 绑定焦点请求事件 --> <EditText android:id="@+id/editText2" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="其他输入" app:requestFocus="@{viewModel.requestEditText2Focus}" /> </LinearLayout> </layout>
4. Activity 仅做初始化(无业务逻辑)
最后,Activity 只需要完成 DataBinding 和 ViewModel 的初始化,不用写任何业务逻辑:
public class StartGameActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityStartGameBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_start_game); StartGameViewModel viewModel = new ViewModelProvider(this).get(StartGameViewModel.class); binding.setViewModel(viewModel); binding.setLifecycleOwner(this); // 让 DataBinding 感知生命周期,正确处理 LiveEvent } }
关键说明:
ObservableField会自动通知 DataBinding 更新 EditText1 的文本,无需手动调用刷新方法。SingleLiveEvent是专门处理一次性事件的 LiveData 子类,避免屏幕旋转等配置变化后重复触发焦点请求。- 自定义
BindingAdapter实现了 ViewModel 事件到 View 操作的解耦,完全符合 MVVM 的架构思想。
内容的提问来源于stack exchange,提问作者Riddhi Shah
相关产品推荐
相关产品推荐

