gpt4 book ai didi

android-databinding - 使用 ViewModel 和 DataBinding 更新 UI

转载 作者:行者123 更新时间:2023-12-04 01:53:32 30 4
gpt4 key购买 nike

我正在尝试在 android 中学习 ViewModel,在我的第一阶段学习中,我正在尝试使用 ViewModel 和 DataBinding 来更新 UI(TextView)。在 ViewModel 中,我有一个 AsyncTask 回调,它将调用 REST API 调用。我从 API 调用中得到响应,但 textview 中的值没有得到更新。
我的 ViewModel 类:

public class ViewModelData extends ViewModel {

private MutableLiveData<UserData> users;

public LiveData<UserData> getUsers() {
if (users == null) {
users = new MutableLiveData<UserData>();
loadUsers();
}

return users;
}

public void loadUsers() {
ListTask listTask =new ListTask (taskHandler);
listTask .execute();

}

public Handler taskHandler= new Handler() {
@Override
public void handleMessage(Message msg) {


UserData userData = (UserData) msg.obj;

users.setValue(userData);
}
};
}
和我的 MainActivity 类:
public class MainActivity extends AppCompatActivity implements LifecycleOwner {
private LifecycleRegistry mLifecycleRegistry;
private TextView fName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fName = (TextView)findViewById(R.id.text_name);
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.markState(Lifecycle.State.CREATED);
ViewModelData model = ViewModelProviders.of(this).get(ViewModelData.class);
model.getUsers().observe(this, new Observer<UserData>() {
@Override
public void onChanged(@Nullable UserData userData) {
Log.d("data"," = - - - - ="+userData.getFirstName());

}
});

}

@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
和我的数据类:
public class UserData extends BaseObservable{
private String firstName ;
@Bindable
public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
}
和布局文件
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<variable name="data" type="com.cgi.viewmodelexample.UserData"/>
</data>
<RelativeLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.cgi.viewmodelexample.MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.firstName}"
android:id="@+id/text_name"/>
</RelativeLayout>
</layout>

最佳答案

我建议遵循以下基本原则:

  • 不要让业务或表示逻辑重载数据对象
  • 仅在表示层中获取数据所需的 View 模型
  • View 模型应该只向表示层公开准备使用的数据
  • (可选)后台任务应该暴露 LiveData提供数据

  • 实现说明:
  • firstName只读 View
  • lastName在 View 中可编辑
  • loadUser()不是线程安全的
  • 调用 save() 时出现错误消息直到未加载数据的方法

  • 不要让业务或表示逻辑重载数据对象

    假设,我们有 UserData具有名字和姓氏的对象。所以, setter/getter 它(通常)是我们所需要的:
    public class UserData {

    private String firstName;
    private String lastName;

    public UserData(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
    }

    public String getFirstName() {
    return firstName;
    }

    public String getLastName() {
    return lastName;
    }
    }

    仅在演示文稿中获取数据所需的 View 模型

    为了遵循这个建议,我们应该在数据绑定(bind)布局中只使用 View 模型:
    <?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"
    xmlns:tools="http://schemas.android.com/tools"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.vmtestapplication.MainActivity">

    <data>

    <import type="android.view.View" />

    <!-- Only view model required -->
    <variable
    name="vm"
    type="com.example.vmtestapplication.UserDataViewModel" />
    </data>

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:orientation="vertical">

    <!-- Primitive error message -->
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{vm.error}"
    android:visibility="@{vm.error == null ? View.GONE : View.VISIBLE}"/>

    <!-- Read only field (only `@`) -->
    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{vm.firstName}" />

    <!-- Two-way data binding (`@=`) -->
    <EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@={vm.lastName}" />

    </LinearLayout>
    </layout>

    注意:您可以在一个布局中使用几个 View 模型,但不能使用原始数据

    View 模型应该只公开准备使用的数据来展示

    这意味着,您不应该直接从 View 模型中公开复杂的数据对象(在我们的例子中是 UserData)。最好公开 View 可以按原样使用的私有(private)类型。在下面的示例中,我们不需要持有 UserData对象,因为它仅用于加载分组数据。我们可能需要创建 UserData保存它,但这取决于您的存储库实现。
    public class UserDataViewModel extends ViewModel {

    private ListTask loadTask;

    private final MutableLiveData<String> firstName = new MediatorLiveData<>();
    private final MutableLiveData<String> lastName = new MediatorLiveData<>();
    private final MutableLiveData<String> error = new MutableLiveData<>();

    /**
    * Expose LiveData if you do not use two-way data binding
    */
    public LiveData<String> getFirstName() {
    return firstName;
    }

    /**
    * Expose MutableLiveData to use two-way data binding
    */
    public MutableLiveData<String> getLastName() {
    return lastName;
    }

    public LiveData<String> getError() {
    return error;
    }

    @MainThread
    public void loadUser(String userId) {
    // cancel previous running task
    cancelLoadTask();
    loadTask = new ListTask();
    Observer<UserData> observer = new Observer<UserData>() {
    @Override
    public void onChanged(@Nullable UserData userData) {
    // transform and deliver data to observers
    firstName.setValue(userData == null? null : userData.getFirstName());
    lastName.setValue(userData == null? null : userData.getLastName());
    // remove subscription on complete
    loadTask.getUserData().removeObserver(this);
    }
    };
    // it can be replaced to observe() if LifeCycleOwner is passed as argument
    loadTask.getUserData().observeForever(observer);
    // start loading task
    loadTask.execute(userId);
    }

    public void save() {
    // clear previous error message
    error.setValue(null);
    String fName = firstName.getValue(), lName = lastName.getValue();
    // validate data (in background)
    if (fName == null || lName == null) {
    error.setValue("Opps! Data is invalid");
    return;
    }
    // create and save object
    UserData newData = new UserData(fName, lName);
    // ...
    }

    @Override
    protected void onCleared() {
    super.onCleared();
    cancelLoadTask();
    }

    private void cancelLoadTask() {
    if (loadTask != null)
    loadTask.cancel(true);
    loadTask = null;
    }
    }

    后台任务应该暴露 LiveData传递数据
    public class ListTask extends AsyncTask<String, Void, UserData> {

    private final MutableLiveData<UserData> data= new MediatorLiveData<>();

    public LiveData<UserData> getUserData() {
    return data;
    }

    @Override
    protected void onPostExecute(UserData userData) {
    data.setValue(userData);
    }

    @Override
    protected UserData doInBackground(String[] userId) {
    // some id validations
    return loadRemoiteUser(userId[0]);
    }
    }

    MainActivity.java
    public class MainActivity extends AppCompatActivity {

    private UserDataViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // get view model
    viewModel = ViewModelProviders.of(this).get(UserDataViewModel.class);
    // create binding
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    // set view model to data binding
    binding.setVm(viewModel);
    // don't forget to set LifecycleOwner to data binding
    binding.setLifecycleOwner(this);

    // start user loading (if necessary)
    viewModel.loadUser("user_id");
    // ...
    }
    }

    PS:尝试使用 RxJava 库而不是 AsyncTask执行后台工作。

    关于android-databinding - 使用 ViewModel 和 DataBinding 更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52890266/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com