我不确定我是否ViewModel正确理解 Android 中的架构。我认为 ViewModel 生命周期与活动相关,因此我们期望相同的实例,并且如果我们将活动或片段上下文传递给ViewModelProvider?
无论如何,这是我的 ViewModel:
class MainViewModel : ViewModel() {
var teamName: String = "Warriors";
}
Run Code Online (Sandbox Code Playgroud)
这是我的活动:
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
viewModel.teamName = "Cavaliers";
Log.d("YouQi", "activity viewModel.teamName: ${viewModel.teamName}");
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后这是我的片段:
class MainFragment : androidx.fragment.app.Fragment() {
companion object {
fun newInstance() = MainFragment()
}
private lateinit var viewModel: …Run Code Online (Sandbox Code Playgroud) 我目前有一个应用程序,其中包含用于所有服务器/API 交互的 ForegroundService 和用于本地持久性的 Room 数据库。我一直在尝试实现 AndroidViewModel 来帮助数据持久化和快速 UI 刷新。
然而,根据文档,ViewModels 不能在 Services 中实现,到目前为止,我已经使用 Service 在本地更新信息并使用 LocalBroadcasts 通知组件(这是我想使用 ViewModels 和 Observers 消除的)。
我需要让服务运行,因为应用程序需要在后台继续运行(它是一个关键任务应用程序,应用程序关闭意味着用户将无法提供关键服务),并定期更新某些信息(附近的请求等)。
所以要问核心问题——
我的一些ViewModel代码如下:
public class HouseCallViewModel extends AndroidViewModel {
private String TAG = HouseCallViewModel.class.getSimpleName();
private MutableLiveData<List<HouseCall>> housecallList;
private MutableLiveData<List<HouseCall>> openHousecalls, confirmedHousecalls, closedHousecalls, missedHousecalls, userCancelledHousecalls, respCancelledHousecalls;
private MutableLiveData<List<Incident>> incidentList, openIncidents;
private MutableLiveData<List<Incident>> closedIncidents, usercancelIncidents, respcancelIncidents;
RevivDatabase database; …Run Code Online (Sandbox Code Playgroud) 所以我有一个带有 Room 数据库的 Android 应用程序,这个后端由一个充当存储库的类管理,该存储库为我的视图模型提供数据,然后我的活动(片段)观察视图模型(每个人都还在我身边吗?)在我的一个片段中,我想获取数据库中点击值高于 X 的所有卡片(实体)的列表,但我也想获取所有标记为收藏夹的卡片,无论其点击值如何。
我当前的解决方案是通过我的存储库从我的视图模型运行 2 个单独的查询,并且我的活动观察这两个查询并组合返回给它的列表,这无法正常工作,因为我的列表加倍了,而且我没有当观察者在不同时间返回时清除列表的好地方,因为它们是异步的(我将发布所有代码)。
我认为我想要的是以某种方式组合查询,以便我只管理一个列表,但我的 SQL 知识不是很好,我不确定这是否可能,或者我可以以某种方式将这些列表合并到我的存储库类中但因为我正在使用实时数据,所以我不确定如何安全地获取数据来组合列表,但也许有一个我不知道的更好的解决方案,但我将在下面发布我正在做的事情
DAO 查询 这是我运行的两个查询,一个查询所有卡片被点击 x 次,另一个查询所有标记为收藏的卡片,两者都采用目前不相关的搜索字符串
@Query("SELECT * FROM card WHERE cardFavourite AND cardWord LIKE :searchWord ORDER BY cardWord ASC")
LiveData<List<Card>> searchFavourites(String searchWord);
@Query("SELECT * FROM card WHERE cardClicked >= :clicks AND cardKeyStage <= :keystage AND cardWord LIKE :searchWord ORDER BY cardFavourite ASC, cardClicked DESC, cardWord ASC")
LiveData<List<Card>> searchCardListRecents(String searchWord,int clicks, int keystage);
Run Code Online (Sandbox Code Playgroud)
存储库我的存储库是一个充满对数据库的调用的类,这些数据库将实时数据返回到其视图模型,所需的内容是:
public LiveData<List<Card>> searchFavouriteCards(String searchString){
return cardDao.searchFavourites(searchString);
}
public LiveData<List<Card>> searchRecentCards(String searchString, int clicks){ …Run Code Online (Sandbox Code Playgroud) viewModelScope用于将协程生命周期绑定到ViewModel生命周期。liveData构建器创建一个LiveData运行协程的 ,其生命周期与状态绑定LiveData,因此,当LiveData不活动时,协程会在超时后取消。由于超时,协程不会在配置更改时被取消。
如果我在 a 内创建一个LiveDatavia构建器,并观察到,生命周期已经绑定到生命周期。我还应该将其传递给构建者吗?我认为我不应该,但在 Android 文档示例之一中它通过了:liveDataViewModelLiveDataActivityLiveDataActivityviewModelScope.coroutineContextliveData
class MyViewModel: ViewModel() {
private val userId: LiveData<String> = MutableLiveData()
val user = userId.switchMap { id ->
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
emit(database.loadUserById(id))
}
}
}
Run Code Online (Sandbox Code Playgroud) android android-livedata android-viewmodel android-architecture-components kotlin-coroutines
我在哪里
我正在尝试使用 Room 用数据库中的数据填充微调器。数据是一个术语列表,这些术语具有与之关联的课程。
我想在创建新课程时使用微调器来选择与之关联的术语。
目前,微调器不显示默认选项,但如果您单击微调器,它会显示可供选择的数据列表。从微调器中选择某些内容后,它不会显示您选择的内容。
这是我将数据加载到微调器适配器的代码:
termsList = new ArrayList<>();
termIdList = new ArrayList<>();
mTermViewModel = new ViewModelProvider(this).get(TermViewModel.class);
mTermViewModel.getAllTerms().observe(this, new Observer<List<TermEntity>>() {
@Override
public void onChanged(@Nullable final List<TermEntity> terms) {
for (TermEntity term : terms) {
termsList.add(term.getTermName());
termIdList.add(term.getTermId());
}
}
});
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, termsList);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mTermSpinner.setAdapter(adapter);
}
Run Code Online (Sandbox Code Playgroud)
这是 TermDAO
@Dao
public interface TermDAO {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(TermEntity term);
@Query("DELETE FROM terms")
void deleteAllTerms();
@Query("SELECT * FROM terms ORDER BY termId ASC")
LiveData<List<TermEntity>> getAllTerms(); …Run Code Online (Sandbox Code Playgroud) 我的片段 UI 中有一个列表视图,它的元素设置取决于来自视图模型 LiveData 属性的值的状态。
我想为片段创建工具测试,该片段包含与该属性的值集相关的 3 个场景测试用例,但我不知道从哪里开始。
我的代码应该如下所示:
class MyViewModel : ViewModel() {
var status = MutableLiveData("")
}
class MyFragment : Fragment() {
private lateinit var myViewModel: MyViewModel
private lateinit var myListView: ListView
override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
myViewModel =
ViewModelProviders.of(this, ViewModelProvider.Factory).get(MyViewModel::class.java)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
when (myViewModel?.status) {
"status1":
setListContent(items1)
"status1":
setListContent(items2)
"status1":
setListContent(items3)
else
setListContent
(items1)
}
}
private fun setListContent(itemsList: List<?>) {
myListView.adapter = MyCustomadapter(context!!, …Run Code Online (Sandbox Code Playgroud) android unit-testing kotlin android-livedata android-viewmodel
我目前正在研究Android Room with a View示例应用程序,这里提供完整的源代码。在这个项目中,定义了一个WordViewModel类型AndroidViewModel:
class WordViewModel(application: Application) : AndroidViewModel(application)
Run Code Online (Sandbox Code Playgroud)
请注意构造函数如何要求Application传入一个实例。然而,当我检查 时MainActivity,WordViewModel检索了 而不传入
Application实例:
// Get a new or existing ViewModel from the ViewModelProvider.
mWordViewModel = new ViewModelProvider(this).get(WordViewModel.class);
Run Code Online (Sandbox Code Playgroud)
这怎么可能,如何在WordViewModel不传入Application实例和不使用自定义工厂的情况下检索?
我有单个活动应用程序和片段数量。其中一些片段正在使用我的视图模型,通常是这样的:
private val myViewModel: MyViewModel by sharedViewModel()
Run Code Online (Sandbox Code Playgroud)
如果我想同时拥有模型shared并使用 SavedStateHandle 保持其状态怎么办?我无法弄清楚这是否受支持,如果是,则需要如何使用它(在托管活动中将 viewmodel 声明为 stateViewModel 不起作用)。
我正在尝试使用Jetpack 教程在片段和活动之间创建共享注入视图模型。
共享视图模型成功注入到父 MyActivity 中,但是当子渲染时,由于依赖注入失败,应用程序崩溃。我在下面提供了创建问题的代码。
提供会话管理器:
@InstallIn(ApplicationComponent::class)
@Module
class AppModule {
@Provides
@Singleton
fun provideSessionManager(
networkClient: NetworkClient
): SessionManager {
return SessionManager(networkClient)
}
}
Run Code Online (Sandbox Code Playgroud)
要注入共享视图模型:
class SharedViewModel @ViewModelInject constructor(
private var sessionManager: SessionManager
) : ViewModel() {
var name = MutableLiveData<String>("Shared View Model")
}
Run Code Online (Sandbox Code Playgroud)
并且由父活动和子片段使用。
class MyActionFragment() : Fragment() {
private val viewModel: SharedViewModel by viewModels()
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Timber.d("View Model Name 1: ${viewModel.name.value}") // This line crashes
}
}
Run Code Online (Sandbox Code Playgroud)
class MyActivity : AuthenticatedBaseActivity() { …Run Code Online (Sandbox Code Playgroud) 我在这里找到了一个类似的问题。在撰写此问题时,只有此答案可用,这对我没有任何帮助,我相信对提出问题的人也没有任何帮助。
我检查了答案中链接的 repo,它通过在 viewmodel 中创建一个 init 方法并在 Activity/Fragment 中调用它来“解决”问题。
由于viewmodel已经被注入,这个方案对我来说似乎不太理想,我想知道在使用hilt时是否还有其他可用的选项。
android dependency-injection android-viewmodel android-jetpack-navigation dagger-hilt
android ×10
android-architecture-components ×2
android-room ×2
dagger-hilt ×2
kotlin ×2
android-mvvm ×1
androidx ×1
dao ×1
koin ×1
mvvm ×1
unit-testing ×1