据我了解,当我们在片段中调用此代码时,我们将从 Activity ViewModelStore 获得一个视图模型实例:
viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)
当fragment结束其生命周期时,该viewmodel的实例将存在于ViewModelStore中,直到activity销毁。ViewModelStore 有一个clear()方法,但它会清除其中的所有视图模型。有什么方法可以清除特定的 ViewModel 吗?
另一个解决方案是将 ViewModel 的范围限定为父片段,但是我们如何通过 ViewModelProviders.of() 初始化另一个片段中的 ViewModel?我应该将片段或视图模型实例传递给下一个片段吗?
我想将数据绑定与视图模型一起使用,如此处所述
所以这里是摘录:
布局:
<data class="FragmentEditPersonDataBinding">
<import type="com.unludo.interview.persons.edit.Converter"/>
<variable
name="viewmodel"
type="com.unludo.interview.persons.edit.PersonEditViewModel" />
[...]
<EditText
android:id="@+id/editBirthday"
android:inputType="date"
android:text="@={Converter.dateToString(viewmodel.birthday)}"
Run Code Online (Sandbox Code Playgroud)
转换器:
object Converter {
@InverseMethod("stringToDate")
@JvmStatic
fun dateToString(
view: EditText, oldValue: String,
value: Date
): String {
val sdf = SimpleDateFormat("dd/MM/yyyy", Locale.FRANCE)
return sdf.format(value)
}
@JvmStatic
fun stringToDate(
view: EditText, oldValue: String,
value: String
): Date {
val sdf = SimpleDateFormat("dd/MM/yyyy", Locale.FRANCE)
return sdf.parse(value)
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型:
class PersonEditViewModel {
var birthday: Date = GregorianCalendar(1993, 5, 19).time
...
Run Code Online (Sandbox Code Playgroud)
现在我在构建时收到此错误:
e: [kapt] An exception …Run Code Online (Sandbox Code Playgroud) android android-databinding android-viewmodel android-architecture-components
我想在片段中加载任务,在片段的onViewCreated中,我注册观察者LiveData,在片段的onResume中,我异步加载任务,当第一次进入片段时,它工作正常,但是当我导航到其他片段然后返回任务时片段,回调onChanged()将被调用两次。
我知道如果LiveData已经有数据集,它会被传递给观察者,所以当回到任务片段时,onChanged会在注册观察者时触发onViewCreated,而在onResume中,会触发onChanged第二次,我想知道如何避免这种情况。我查了很多,知道有一个EventWrapper,可以标记 onChanged 第一次触发时消耗的内容。但我觉得这种做法太重了。抱歉我的英语不好...
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle
savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//...
mainViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);
mainViewModel.increaseTaskList.observe(getViewLifecycleOwner(), new
Observer<List<Task>>() {
@Override
public void onChanged(@Nullable List<Task> tasks) {
Log.d("ZZZ","data changed,IncreaseTaskListAdapter setData");
adapter.setData(tasks);
}
});
}
@Override
public void onResume() {
super.onResume();
mainViewModel.loadIncreasePointTaskList();
}
Run Code Online (Sandbox Code Playgroud) 我有一个RecyclerView。我想用 SearchView 让它可以过滤。我的应用程序基于Android Architecture Components.
我创建了一个过滤方法searchView。当我搜索某些内容时,它可以工作,但是当我清除其中的文本时searchView,列表不会更改,并且仍然显示搜索数据。
活动:
private StudentAdapter mAdapter;
mAdapter = new StudentAdapter(this);
recyclerView.setAdapter(mAdapter);
//ViewModel
StudentViewModelFactory factory = new StudentViewModelFactory(mDb, mClassId);
StudentViewModel viewModel = ViewModelProviders.of(this, factory).get(StudentViewModel.class);
viewModel.getStudentEntries().observe(this, studentEntries -> mAdapter.setStudents(studentEntries));
//SearchView
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
@Override
public boolean onQueryTextSubmit(String query){
return false;
}
@Override
public boolean onQueryTextChange(String newText){
mAdapter.getFilter().filter(newText);
return false;
}
});
Run Code Online (Sandbox Code Playgroud)
适配器:
public class StudentAdapter extends RecyclerView.Adapter<StudentAdapter.itemHolder> {
private List<StudentEntry> mStudentEntries;
private List<StudentEntry> filteredStudentEntries;
public StudentAdapter(Context context) {
this.context = context; …Run Code Online (Sandbox Code Playgroud) android searchview android-recyclerview android-livedata android-viewmodel
在里面Activity你可以得到这样的ViewModel范围Activity:
val viewModel = ViewModelProviders.of(this)[ViewModel::class.java] //deprecated way
val viewModel = ViewModelProvider(this)[ViewModel::class.java]
//or
val viewModel by viewModels<ViewModel>()
Run Code Online (Sandbox Code Playgroud)
同样,在 a 中Fragment你可以得到 a ViewModelby
//scoped to parent Activity
val viewModel: ViewModel by activityViewModels()
//scoped to parent Fragment
val viewModel: ViewModel by viewModels({ requireParentFragment() })
//scoped to navigation graph
val viewModel: ViewModel by navGraphViewModels(R.id.login_graph)
Run Code Online (Sandbox Code Playgroud)
现在,如果我尝试访问范围为导航图的ViewModel内部Activity,则没有辅助方法,所以我必须这样做
val viewModel by lazy {
ViewModelProvider(findNavController(R.id.nav_host_fragment)
.getViewModelStoreOwner(R.id.your_graph).viewModelStore,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(ViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)
有没有我错过的辅助方法?我必须通过导航图范围访问它吗?我可以只使用Activity范围来访问相同的吗ViewModel?
我有一个虚拟机,例如
class CityListViewModel(private val repository: Repository) : ViewModel() {
@VisibleForTesting
val allCities: LiveData<Resource<List<City>>> =
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
emit(Resource.Loading())
emit(repository.getCities())
}
}
Run Code Online (Sandbox Code Playgroud)
我的测试是:
@ExperimentalCoroutinesApi
class CityListViewModelTest {
@get:Rule
val rule = InstantTaskExecutorRule()
@get:Rule
val coroutineTestRule = CoroutinesTestRule()
@Test
fun `allCities should emit first loading and then a Resource#Success value`() =
runBlockingTest {
val fakeSuccessResource = Resource.Success(
listOf(
City(
1,
"UK",
"London",
Coordinates(34.5, 56.2)
)
)
)
val observer: Observer<Resource<List<City>>> = mock()
val repositoryMock: Repository = mock()
val sut …Run Code Online (Sandbox Code Playgroud) android kotlin android-testing android-viewmodel kotlin-coroutines
我正在使用 Android Jetpack 导航组件开发单个活动应用程序。在其中一个片段上,我使用了内置的数据绑定工具。奇怪的是,尽管它在前一周还可以工作,但今天却无缘无故地彻底坏了。
\n\n设置:
\n我与绑定一起使用的片段具有以下布局文件:
<?xml version="1.0" encoding="utf-8"?>\n<layout \n xmlns:android="http://schemas.android.com/apk/res/android"\n xmlns:app="http://schemas.android.com/apk/res-auto"\n xmlns:tools="http://schemas.android.com/tools">\n\n <data>\n </data>\n\n <ScrollView\n android:layout_width="match_parent"\n android:layout_height="match_parent"\n android:id="@+id/example_layout_root"\n tools:context=".example.ExampleFragment"\n android:background="@color/main_1"\n >\n\n ...\n\n </ScrollView>\n</layout>\nRun Code Online (Sandbox Code Playgroud)\n\n我已经删除了主要内容,但它显示我有一个<layout>元素作为根,同时定义了数据和片段布局部分。
片段代码如下:
\n\nclass ExamleFragment : Fragment() {\n\n private val viewModel: ExampleViewModel by sharedViewModel()\n\n override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n // Inflate the layout for this fragment\n val binding : FragmentExampleBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_example, container, false)\n // This one also does not work\n // val binding …Run Code Online (Sandbox Code Playgroud) android android-layout android-fragments android-databinding android-viewmodel
所以我的一般问题是如何从 @Query 的视图模型调用函数,您必须传递一些内容然后返回一些内容。我的简单例子:
DAO
@Query ("SELECT * FROM table_name WHERE id = :id LIMIT 1")
fun getItemById (id: Long) : MyItem
Run Code Online (Sandbox Code Playgroud)
回购协议
fun getItemById (id: Long) : MyItem {
return itemDao.getItemById(id)
}
Run Code Online (Sandbox Code Playgroud)
我知道它不能也不应该在 ui 线程上完成。为了插入和删除项目,我使用 viewModelScope 作业,但我不能(也许只是不知道如何)使用它来返回任何内容。如果我将它作为 LiveData 返回到任何地方,那么它的工作原理就像这样:
视图模型
fun itemById(id: Long): LiveData<MyItem> {
return itemRepo.getItemById(id)
}
Run Code Online (Sandbox Code Playgroud)
然后我在片段/活动中观察它:
viewModel.itemById(id).observe(this, Observer {
// using it
})
Run Code Online (Sandbox Code Playgroud)
问题是,我真的不需要它成为可观察的实时数据。我只需要拿到一次,检查一下状况就可以了。所以也许有人可以建议如何做到这一点,而不需要它是实时数据。或者我应该将其保留为实时数据?
我在创建测试类时遇到问题。基本上我想测试执行网络调用的视图模型类。使用 dagger 注入类网络组件需要上下文参数来检查连接,这是我的视图模型:
class MyViewModel(application: Application): AndroidViewModel(application) {
@Inject lateinit var network: NetworkService
init {
DaggerNetworkComponent.builder().networkModule(NetworkModule(application.applicationContext))
.build().inject(this)
network.callNetwork()
}
}
Run Code Online (Sandbox Code Playgroud)
测试类是这样的
lateinit var myViewModel: MyViewModel
@Test
fun testMyNetwork() {
application = Mockito.mock(Application::class.java)
myViewModel = MyViewModel(application)
}
Run Code Online (Sandbox Code Playgroud)
总是application.applicationContext返回 null,然后返回IllegalStateException
有什么解决办法吗?
我正在尝试使用 Android ViewModel 添加 Room 数据库。我按照此链接进行了相同的https://codelabs.developers.google.com/codelabs/android-room-with-a-view/#13
我遇到了一个例外:
导致:java.lang.RuntimeException:无法创建类 com.example.dailyfaithapp.ViewModels.FavouritesViewModel 的实例
我检查了一些问题和答案,但没有一个对我有用。
这是我的视图模型
public class FavouritesViewModel extends ViewModel {
public FavouriteRepository mRepository;
public LiveData<List<Favourites>> mAllFavourites;
public FavouritesViewModel (Application application) {
mRepository = new FavouriteRepository(application);
mAllFavourites = mRepository.getmAllFavourites();
}
public LiveData<List<Favourites>> getmAllFavourites() { return mAllFavourites; }
public void insert(Favourites favourites) { mRepository.insertFavourite(favourites); }
}
Run Code Online (Sandbox Code Playgroud)
我还尝试使用视图模型工厂调用视图模型,但在这里不起作用
public class FavouritesViewModelFactory implements ViewModelProvider.Factory {
private Application mApplication;
private String mParam;
public FavouritesViewModelFactory(Application application) {
mApplication = application;
}
@Override
public <T extends ViewModel> T …Run Code Online (Sandbox Code Playgroud) android ×10
kotlin ×2
android-architecture-components ×1
android-architecture-navigation ×1
android-mvvm ×1
android-room ×1
dao ×1
fragment ×1
java ×1
mockito ×1
mvvm ×1
searchview ×1
unit-testing ×1