我正在使用MVVM和DataBinding构建Android应用程序。我在ViewModel中有一个函数来启动一个Activity。 是否可以在ViewModel中进行onClick调用?
喜欢这个。
public class MyViewModel {
public void onClick(View view, long productId) {
Context context = view.getContext();
Intent intent = new Intent(context, ProductDetailActivity.class);
intent.putExtra("productId", productId);
context.startActivity(intent);
}
}
在我的XML中:
...
android:onClick="@{(v) -> viewModel.onClick(v, viewModel.product.id)}">
或者将它移到View并从EventBus或Rx调用它并在我的ViewModel中只有POJO是最佳做法吗?
答案 0 :(得分:18)
你的问题的答案是你的目标是什么?
如果您想使用 MVVM 分离关注点,以便对Viewmodel
进行单元测试,那么您应该尝试将需要Context
的所有内容与您的Viewmodel
分开Viewmodel
。 Viewmodel
包含您应用的核心业务逻辑,并且不应具有外部依赖关系。
但是我喜欢你要去的地方:)如果决定打开哪个Activity就在View中,那么为它编写JUnit测试是非常困难的。但是,您可以将对象传递到执行startActivity()
调用的Activity
。现在,在单元测试中,您只需模拟此对象并验证是否已打开正确的 =INDEX(SLAVE!C2:C4;MATCH(CONCATENATE(MASTER!A2;MASTER!B2);SLAVE!D2:D4;0))
答案 1 :(得分:8)
将它放在ViewModel
内是绝对完美的,但是您需要从ViewModel
/ Activity
设置Fragment
。
以下是学习MVVM架构时可以遵循的一些链接。
Approaching Android with MVVM
Android MVVM
https://github.com/ivacf/archi
People-MVVM
MVVM on Android: What You Need to Know
答案 2 :(得分:6)
我的操作方式是在您的ViewModel中
val activityToStart = MutableLiveData<Pair<KClass<*>, Bundle?>>()
这使您可以检查启动的Activity的类以及在Bundle中传递的数据。然后,您可以在“活动”中添加以下代码:
viewModel.activityToStart.observe(this, Observer { value ->
val intent = Intent(this, value.first.java)
if(value.second != null)
intent.putExtras(value.second)
startActivity(intent)
})
答案 3 :(得分:2)
MVVM的原理指出,只有视图(活动/片段)保留对ViewModel的引用,而ViewModel不应保留对任何View的引用。
对于您来说,要开始一项活动,我会这样做:
MyViewModel.class
public class MyViewModel {
public static final int START_SOME_ACTIVITY = 123;
@Bindable
private int messageId;
public void onClick() {
messageId = START_SOME_ACTIVITY;
notifyPropertyChanged(BR.messageId); //BR class is automatically generated when you rebuild the project
}
public int getMessageId() {
return messageId;
}
public void setMessageId(int message) {
this.messageId = messageId;
}
}
在您的 MainActivity.class
中@BindingAdapter({"showMessage"})
public static void runMe(View view, int messageId) {
if (messageId == Consts.START_SOME_ACTIVITY) {
view.getContext().startActivity(new Intent(view.getContext(), SomeActivity.class));
}
}
@Override
protected void onPause() {
super.onPause();
finish(); //only call if you want to clear this activity after go to other activity
}
最后,在您的 activity_main.xml
中<Button
android:onClick="@{()-> myViewModel.onClick()}"
bind:showMessage="@{myViewModel.messageId}" />
答案 4 :(得分:1)
在MVVM中,我们可以将LiveData
用于此Event。因为activity/Fragment
被销毁时ViewModel仍然有效!所以最好的方法是LiveData
1。从Event
创建类调用Extends
和ViewModel
:
class Event : ViewModel() {
2。从LiveData创建字段:
private val _showSignIn = MutableLiveData<Boolean?>()
此私有字段的3.create方法:
val showSignIn: LiveData<Boolean?>
get() = _showSignIn
4.create方法,您可以在liveData上设置值:
fun callSignIn() {
_showSignIn.value = true
}
最终活动类别:
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class Event : ViewModel() {
private val _showSignIn = MutableLiveData<Boolean?>()
val showSignIn: LiveData<Boolean?>
get() = _showSignIn
fun callSignIn() {
_showSignIn.value = true
}
eventViewModel中的实例:
private val eventViewModel = Event()
打电话给观察员:
eventViewModel.showSignIn.observe(this, Observer {
startActivity(Intent(this, MainActivity::class.java))
})
,如果您使用data binding
,则可以在callSignIn()
XML中调用onClick
:
在变量标记中:
<variable
name="eventViewModel"
type=packageName.Event" />
android:onClick="@{() -> eventViewModel.callSignIn()}"
注意:不要忘记在activity/fragment
中设置绑定:
binding.eventViewModel = eventViewModel
我搜索最佳方法并找到它。我希望可以帮助某人
答案 5 :(得分:0)
根据数据绑定文档。 有两种方法可以做到:
1- MethodReferences:您必须将视图作为参数传递给函数,否则会出现编译时错误。
如果您将使用这种方式,请在此处做一个单独的类作为示例来处理此类事件。
MyHandler
public class MyHandler {
public void onClick(View view, long productId) {
Context context = view.getContext();
Intent intent = new Intent(context, ProductDetailActivity.class);
intent.putExtra("productId", productId);
context.startActivity(intent);
}
}
XML
<data>
<variable
name="viewModel"
type="com.example.ViewModel"
<variable
name="myHandler"
type="com.example.MyHandler" />
</data>android:onClick="@{myHandler.onClick(viewModel.product.id)}">
2- Listener bindings:这里不需要通过视图作为示例。
但是,如果要启动Activity,则将viewModel扩展为AndroidViewModel,然后将使用applicaion对象。
ViewModel
public class MyViewModel extends AndroidViewModel {
public void onClick(long productId) {
Intent intent = new Intent(getApplication(), ProductDetailActivity.class);
intent.putExtra("productId", productId);
context.startActivity(intent);
}
}
XML
android:onClick="@{() -> viewModel.onClick(viewModel.product.id)}">