我尝试制作具有两个字段(username, password
)的示例登录页面,并使用android体系结构组件保存按钮,使用android数据绑定,验证viewmodel
中的数据,并从视图模型进行调用如官方文档所述,用于远程服务器调用的存储库,远程服务器成功返回我userid,所以如何使用此成功从视图模型启动新片段?我了解了有关singleLiveEvent
和EventObserver
的一些知识,但是找不到清晰的用法示例:
LoginViewModel
private MutableLiveData<String> snackbarStringSingleLiveEvent= new MutableLiveData<>();
@Inject
public LoginViewModel(@NonNull AppDatabase appDatabase,
@NonNull JobPortalApplication application,
@NonNull MyApiEndpointInterface myApiEndpointInterface) {
super(application);
loginRepository = new LoginRepository(application, appDatabase, myApiEndpointInterface);
snackbarStringSingleLiveEvent = (loginRepository.getLogin(username.get(), password.get(), type.get()));
}
public MutableLiveData<String> getSnackbarStringSingleLiveEvent() {
return snackbarStringSingleLiveEvent;
}
存储库
public SingleLiveEvent<String> getLogin(String name, String password, String type) {
SingleLiveEvent<String> mutableLiveData = new SingleLiveEvent<>();
apiEndpointInterface.getlogin(name, password, type).enqueue(new Callback<GenericResponse>() {
@Override
public void onResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(response.body().getMessage());
}
@Override
public void onFailure(Call<GenericResponse> responseCall, Throwable t) {
mutableLiveData.setValue(Constant.FAILED);
}
});
return mutableLiveData;
}
登录片段
private void observeViewModel(final LoginViewModel viewModel) {
// Observe project data
viewModel.getSnackbarStringSingleLiveEvent().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
}
});
}
在上述情况下如何使用EventObserver
?有实际的例子吗?
答案 0 :(得分:0)
请查看以下示例,了解如何创建单个LiveEvent 以LiveData
的身份仅观察一次:
如下创建一个名为 Event
的类,该类将提供一次数据,并充当LiveData
包装器的子代:
public class Event<T> {
private boolean hasBeenHandled = false;
private T content;
public Event(T content) {
this.content = content;
}
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
public boolean isHandled() {
return hasBeenHandled;
}
}
然后像下面这样声明此EventObserver
类,以便我们不会遇到每次在任何地方都检查过的Event
时出现的放置条件:
public class EventObserver<T> implements Observer<Event<T>> {
private OnEventChanged onEventChanged;
public EventObserver(OnEventChanged onEventChanged) {
this.onEventChanged = onEventChanged;
}
@Override
public void onChanged(@Nullable Event<T> tEvent) {
if (tEvent != null && tEvent.getContentIfNotHandled() != null && onEventChanged != null)
onEventChanged.onUnhandledContent(tEvent.getContentIfNotHandled());
}
interface OnEventChanged<T> {
void onUnhandledContent(T data);
}
}
以及如何实现它:
MutableLiveData<Event<String>> data = new MutableLiveData<>();
// And observe like below
data.observe(lifecycleOwner, new EventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
// And this is how you add data as event to LiveData
data.setValue(new Event(""));
有关详细信息,请参考 here 。
编辑 O.P。:
是的,data.setValue(new Event(""));
用于存储库,当您从API获得响应 (请记住,返回与您在VM中相同的LiveData
类型) (SingleLiveEvent
类)。
因此,假设您已经在LiveData
中创建了ViewModel
,如下所示:
private MutableLiveData<Event<String>> snackbarStringSingleLiveEvent= new MutableLiveData<>();
您可以通过以下存储库中的 Single Event (单个事件)为该实时数据提供价值:
@Override
public void onResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(new Event(response.body().getMessage())); // we set it as Event wrapper class.
}
并在用户界面(片段)上进行观察,如下所示:
viewModel.getSnackbarStringSingleLiveEvent().observe(this, new EventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
答案 1 :(得分:0)
Event.java
public class Event<T> {
private T content;
private boolean hasBeenHandled = false;
public Event(T content) {
this.content = content;
}
/**
* Returns the content and prevents its use again.
*/
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
/**
* Returns the content, even if it's already been handled.
*/
public T peekContent() {
return content;
}
}
EventObserver.java
public class EventObserver<T> implements Observer<Event<? extends T>> {
public interface EventUnhandledContent<T> {
void onEventUnhandledContent(T t);
}
private EventUnhandledContent<T> content;
public EventObserver(EventUnhandledContent<T> content) {
this.content = content;
}
@Override
public void onChanged(Event<? extends T> event) {
if (event != null) {
T result = event.getContentIfNotHandled();
if (result != null && content != null) {
content.onEventUnhandledContent(result);
}
}
}
}
示例,在ViewModel类中
public class LoginViewModel extends BaseViewModel {
private MutableLiveData<Event<Boolean>> _isProgressEnabled = new MutableLiveData<>();
LiveData<Event<Boolean>> isProgressEnabled = _isProgressEnabled;
private AppService appService;
private SchedulerProvider schedulerProvider;
private SharedPreferences preferences;
@Inject
LoginViewModel(
AppService appService,
SchedulerProvider schedulerProvider,
SharedPreferences preferences
) {
this.appService = appService;
this.schedulerProvider = schedulerProvider;
this.preferences = preferences;
}
public void login(){
appService.login("username", "password")
.subscribeOn(schedulerProvider.executorIo())
.observeOn(schedulerProvider.ui())
.subscribe(_userLoginDetails::setValue,
_userLoginDetailsError::setValue,
() -> _isProgressEnabled.setValue(new Event<>(false)),
d -> _isProgressEnabled.setValue(new Event<>(true))
)
}
}
在登录片段中,
viewModel.isProgressEnabled.observe(this, new EventObserver<>(hasEnabled -> {
if (hasEnabled) {
// showProgress
} else {
// hideProgress
}
}));
使用Event和EventObserver类可以实现与SingleLiveEvent类相同的功能,但是如果您想使用很多样板代码,则请避免使用此方法。希望对您有所帮助,并提供一些有关为什么我们在LiveData中使用SingleEvent的想法。
答案 2 :(得分:0)
我知道 Google 提供了在 ViewModel 和 UI 之间使用 LiveData 的指南,但在某些极端情况下,将 LiveData 用作 SingleLiveEvent 就像重新发明轮子。对于视图模型和用户界面之间的单次消息传递,我们可以使用委托设计模式。在活动中初始化视图模型时,我们只需将活动设置为接口的实现者。然后在我们的视图模型中,我们可以调用委托方法。
界面
public interface Snackable:
void showSnackbarMessage(String message);
界面
public class MyActivity extends AppCompatActivity implements Snackable {
private MyViewModel myViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
this.myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
this.myViewModel.setListener(this);
}
@Override
public void showSnackbarMessage(String message) {
Toast.makeText(this, "message", Toast.LENGTH_LONG).show();
}
}
查看模型
public class MyViewModel extends AndroidViewModel {
private Snackable listener;
public MyViewModel(@NonNull Application application) {
super(application);
}
public void setListener(MyActivity activity){
this.listener = activity;
}
private void sendSnackbarMessage(String message){
if(listener != null){
listener.showSnackbarMessage(message);
}
}
private void anyFunctionInTheViewModel(){
sendSnackbarMessage("Hey I've got a message for the UI!");
}
}