在我的Android应用程序中,我使用mvvm模式跟随架构组件.我的应用程序进行网络调用以显示天气信息.正在从存储库进行调用,该存储库返回对视图模型的响应的居住数据,其中由我的主要活动观察到.
该应用程序工作正常,除了一个条件,每当我断开互联网测试失败的情况下,它会根据需要膨胀错误视图
在错误视图中我有一个重试按钮,这使得方法调用再次观察视图模型(这个方法也是第一次被oncreate()调用,这有效)
即使在打开互联网并点击侦听observable的重试按钮后,数据也会变为空.
我不知道为什么.请任何人帮助
REPOSITORY
@Singleton public class ContentRepository {
@Inject AppUtils mAppUtils;
private RESTService mApiService;
@Inject public ContentRepository(RESTService mApiService) {
this.mApiService = mApiService;
}
public MutableLiveData<ApiResponse<WeatherModel>> getWeatherListData() {
final MutableLiveData<ApiResponse<WeatherModel>> weatherListData = new MutableLiveData<>();
mApiService.getWeatherList().enqueue(new Callback<WeatherModel>() {
@Override public void onResponse(Call<WeatherModel> call, Response<WeatherModel> response) {
weatherListData.setValue(new ApiResponse<>(response.body()));
}
@Override public void onFailure(Call<WeatherModel> call, Throwable t) {
weatherListData.setValue(new ApiResponse<>(t));
}
});
return weatherListData;
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型
public class HomeViewModel extends AndroidViewModel {
private final LiveData<ApiResponse<WeatherModel>> weatherListObservable;
@Inject public HomeViewModel(Application …Run Code Online (Sandbox Code Playgroud) android android-livedata android-viewmodel android-architecture-components
我有一个数据存储库,负责与我的dao交谈
然后我有2个视图模型在存储库中获取实例但是一个ViewModel总是将我的实时数据对象返回为null,另一个工作正常
任何人都知道可能发生的事情,是因为其他ViewModel首先引用了LiveData对象,只允许一个?
android android-room android-livedata android-viewmodel android-architecture-components
在Android上中断两年后,我试图了解Android体系结构组件。在阅读官方文档和一些博客后,令我困惑的一件事是在哪里创建LiveData变量。
在下面的第一个变体中,我仅在存储库类中创建了一个livedata变量,而在存储库和View模型类的第二个变体中创建了一个livedata变量。两种变体均有效。
第一个变体:
public class ScoreViewModel extends AndroidViewModel {
private ScoreRepositorDB scoreRepo;
public ScoreViewModel(Application application) {
super(application);
scoreRepo = new ScoreRepositorDB(application);
}
public LiveData<Score> getScore(){
return scoreRepo.getScore();
}
...
}
Run Code Online (Sandbox Code Playgroud)
第二个变体:
public class ScoreViewModel extends AndroidViewModel {
private ScoreRepositorDB scoreRepo;
private LiveData<Score> score ;
public ScoreViewModel(Application application) {
super(application);
scoreRepo = new ScoreRepositorDB(application);
score = scoreRepo.getScore();
}
public LiveData<Score> getScore(){
// return scoreRepo.getScore();
return score;
}
...
}
Run Code Online (Sandbox Code Playgroud)
两种版本的存储库:
private LiveData<Score> score ;
ScoreRepositorDB(Application application) {
ScoreRoomDatabase db = ScoreRoomDatabase.getDatabase(application); …Run Code Online (Sandbox Code Playgroud) android mvvm android-room android-livedata android-viewmodel
尽管JetPack的Navigation组件看起来很有前途,但是我到了一个找不到实现我想要的东西的地方。
让我们看一个示例应用程序屏幕:
该应用程序有一个主要活动,一个顶部的工具栏,一个底部的工具栏,并带有fab。我面临着2个挑战,我想让它们以正确的方式进行。
1.我需要实现片段事务,以便允许基于用户交互来替换屏幕上的片段。 我可以想到并实现三种方法:
onFragmentAction在片段中有一个接口回调,并有活动来实现它。因此,基本上,当用户按下按钮时,FragmentA我可以onFragmentAction使用params 进行调用,以便该活动将触发并开始执行例如将其替换为的交易FragmentBNavigation从JetPack 实现组件。虽然我已经尝试过了,而且看起来很简单,但是由于无法检索当前片段,我遇到了一个问题。ViewModel在片段和活动之间使用共享,从片段更新它并在活动中观察它。这将是回调的“替代”2.由于FAB处于父活动中,因此在按下时,我需要能够与当前可见片段进行交互并执行操作。例如,在片段内的recyclerview中添加新项目。所以基本上是在活动和片段之间进行交流的一种
方式。我可以想到两种方式
Navigation那么我可以使用findFragmentById并检索当前片段,并运行一个公共方法来触发操作。因此,如您所见,推荐的导航方式是使用新的“ Navigation”架构组件,但是,目前它缺少检索当前片段实例的方法,因此我不知道如何在活动和片段。这可以通过以下方式实现,shared ViewModel但在这里我有一个遗漏的地方:我知道可以使用共享的ViewModel进行片段对片段的通信。我认为,当片段对此有一些共同点时(例如主/细节方案)并共享相同的视图模型,这很有用。
但是,然后在活动和所有片段之间进行交谈,如何使用共享ViewModel?每个片段都需要自己的复杂ViewModel。可能是GeneralViewModel在活动和所有片段中实例化的a ,以及常规片段视图模型,因此每个片段中都有2个视图模型。
能够通过视图模型在片段和活动之间进行交谈将使不需要主动片段的发现成为可能,因为视图模型将提供所需的机制,并且还将允许使用Navigation组件。
很高兴收到任何信息。
以后编辑。这是一些基于注释的示例代码。这是我的问题的解决方案吗?这可以处理片段和父级活动之间的更改吗,这是建议的方面。
private GlobalViewModel ():ViewModel(){
var eventFromActivity:MutableLiveData<Event>
var eventFromFragment:MutableLiveData<Event>
fun setEventFromActivity(event:Event){
eventFromActivity.value = event
}
fun setEventFromFragment(event:Event){
eventFromFragment.value = event
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的活动中
class HomeActivity: AppCompatActivity(){
onCreate{
viewModel = ViewModelProviders.of(this, factory)
.get(GlobalViewModel::class.java)
viewModel.eventsFromFragment.observe(){
//based …Run Code Online (Sandbox Code Playgroud) android android-livedata android-viewmodel android-architecture-components android-jetpack
在我内部,我Fragment初始化一个ViewModelusing ViewModelProviders。我希望它采用Activityif否则null,否则采用(Fragment)。
private val viewModel: MainViewModel by lazy {
ViewModelProviders.of(activity ?: this).get(MainViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)
使用提供的参数不能调用以下任何函数。
- 在androidx.lifecycle.ViewModelProviders中定义的(片段)
- 在androidx.lifecycle.ViewModelPro中定义的(FragmentActivity)
似乎该语言不允许我调用冲突的方法签名(在of(Activity)和之间of(Fragment)。(这是可以理解的,也许编译器必须仅引用一个方法并且不能在同一行上链接到这两个方法。)是吗?
我现在必须使用
activity?.let {
ViewModelProviders.of(it).get(MainViewModel::class.java)
} ?: run {
ViewModelProviders.of(this).get(MainViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)
有什么更好的方法吗?
我想将应用程序实现/重构为Android Architecture Components概念,请参阅https://developer.android.com/jetpack/docs/guide
在本主题Android体系结构组件ViewModel-与Service / IntentService的通信中,我找到了关于体系结构问题的很好的答案,请参阅/sf/answers/3271530251/
但我想问一下,如何从存储库绑定服务,因为我们在这里既没有上下文也没有活动。要明确地说,问题在于如何合并这两个概念。
我现在是什么情况
我需要具有boundService(请参阅https://developer.android.com/guide/components/bound-services),该服务来自第三方作为库(我们称其为“第三方SDK”)。这个“第三方SDK”将在与某些外部硬件的蓝牙连接上做一些异步工作,因此它作为或多或少的永久后台服务运行。但是,将其实现为服务(意图服务,因此活动可以绑定到服务),并且我们必须通过实现自定义事件侦听器接口来接收事件。
我要怎么办
我也想使用架构组件。我定义了View和ViewModel,我想使用一个存储库作为“ Dagger2 Singleton”,该存储库提供本地存储以及Web服务调用的数据形式,请参阅https://developer.android.com/jetpack/docs/guide#fetch -数据
我的初衷是,我也可以将“第三方第三方SDK”作为某种形式的异步准远程数据源来处理,因此,存储库也应绑定到“第三方第三方SDK”。
不幸的是,我们通常需要以下代码将后台服务绑定到活动:
Intent csIntent = new Intent(XXX, ThirdPartyService.class);
YYY.bindService(csIntent, <instance of ServiceConnection>, Context.BIND_AUTO_CREATE);
Run Code Online (Sandbox Code Playgroud)
其中XXX和YYY是上下文和活动(但不应同时出现在存储库中!)
问题是什么?
如果要从“架构组件存储库”访问该后台服务,必须如何根据https://developer.android.com/guide/components/bound-services修改以活动为中心的后台服务绑定的概念根据https://developer.android.com/jetpack/docs/guide#manage-dependencies实现为dagger2 @Singleton
不幸的是,我发现此问题的唯一半官方文件指出“应”进行演示(但票证已关闭):https : //github.com/googlesamples/android-architecture-components/issues/20
感谢您提供任何有关如何合并这两个概念的提示
android mvvm bindservice android-viewmodel android-architecture-components
我在onCreate活动的方法中创建了View Model的实例。
ticketViewModel = ViewModelProviders.of(this).get(TicketViewModel.class);
Run Code Online (Sandbox Code Playgroud)
然后,我有了方法,AddTicket该方法viewModel用于命中服务,并在响应时viewModel关闭了加载动画。
public void addTicket(View view){
ticketViewModel.AddTicket(id).observe(this, response ->{
dismissLoadingAnimation();
}
Run Code Online (Sandbox Code Playgroud)
现在,添加票证后,用户可以Add Ticket按下按钮,然后addTicket()将再次调用该方法。
但是这次observer在ViewModel中定义的时间被调用了2次,导致2次网络调用和2次dismissLoadingAnimation执行。
如果我一直按下addTicket按钮,则内部ViewModelkeep中定义的执行观察器的数量会增加。
这是我的视图模型代码。
public class TicketViewModel extends AndroidViewModel implements IServiceResponse {
MutableLiveData<String> mObservableResponse = new MutableLiveData<String>();
public MutableLiveData AddTicket(String id){
JsonObject jsonObject= new JsonObject();
jsonObject.addProperty("id", id);
NetworkUtility networkUtility= new NetworkUtility(this, ADD_TICKET);
networkUtility.hitService(URL, jsonObject, RequestMethods.POST);
return mObservableResponse;
}
@Override
public void onServiceResponse(String response, String …Run Code Online (Sandbox Code Playgroud) 我已经创建了示例应用来演示我的问题:
A TextView和a Button,文本视图可见性受到约束viewModel.bar
我希望按钮切换viewModel.bar单击时的值和UI以进行更新.
但是,这种情况并没有发生.值已更改,但UI未更新.
布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<variable name="viewModel"
type="com.example.bindingone.MainViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:visibility="@{viewModel.bar ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:text="Update UI"
android:onClick="clicked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>
</layout>
Run Code Online (Sandbox Code Playgroud)
MainActivity 文件:
class MainActivity : AppCompatActivity() {
private val viewModel = MainViewModel()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.viewModel = …Run Code Online (Sandbox Code Playgroud) android android-databinding android-livedata android-viewmodel
我正在研究一个查询github API的应用程序以获取用户列表,而我正在遵循推荐的android 体系结构组件指南。从网络中获取数据后,我将使用Room DB将其存储在本地,然后使用在LiveData对象上观察到的ViewModel将其显示在UI上(这很好)。但是,我希望有一个按钮,当且仅当存在网络连接时,单击该按钮将触发刷新操作并执行网络请求以从API获取新数据。问题是,当我单击该按钮时,将触发两个网络调用,一个来自refreshUserData(),另一个来自已存在的LiveData(在onCreate()期间触发)。我应如何最好地处理这种情况,以使刷新按钮仅执行一个网络请求,而不执行两个网络请求。这是我的存储库类:
public class UserRepository {
private final UserDao mUserDao;
private LiveData<List<GitItem>> mAllUsers;
private LiveData<GitItem> mUser;
private final GithubUserService githubUserService;
private final AppExecutors appExecutors;
private final Application application;
private static String LOG_TAG = UserRepository.class.getSimpleName();
private RateLimiter<String> repoListRateLimit = new RateLimiter<>(1, TimeUnit.MINUTES);
public UserRepository(Application application, GithubUserService githubUserService, AppExecutors appExecutors) {
this.application = application;
UserRoomDatabase db = UserRoomDatabase.getDatabase(application);
mUserDao = db.userDao();
this.githubUserService = githubUserService;
this.appExecutors = appExecutors;
}
public LiveData<GitItem> getUser(int userId) {
LiveData<GitItem> user = mUserDao.loadUser(userId);
Log.d(LOG_TAG, "retrieved …Run Code Online (Sandbox Code Playgroud) android android-room android-livedata android-viewmodel android-architecture-components
我使用viewModelScope在ViewModel其中要求暂停在库函数如下图所示:
视图模型
class DeepFilterViewModel(val repo: DeepFilterRepository) : ViewModel() {
var deepFilterLiveData: LiveData<Result>? = null
fun onImageCompressed(compressedImage: File): LiveData<Result>? {
if (deepFilterLiveData == null) {
viewModelScope.launch {
deepFilterLiveData = repo.applyFilter(compressedImage)
}
}
return deepFilterLiveData
}
}
Run Code Online (Sandbox Code Playgroud)
资料库
class DeepFilterRepository {
suspend fun applyFilter(compressedImage: File): LiveData<Result> {
val mutableLiveData = MutableLiveData<Result>()
mutableLiveData.value = Result.Loading
withContext(Dispatchers.IO) {
mutableLiveData.value = Result.Success("Done")
}
return mutableLiveData
}
}
Run Code Online (Sandbox Code Playgroud)
我正在观察片段中的LiveData,如下所示:
viewModel.onImageCompressed(compressedImage)?.observe(this, Observer { result ->
when (result) {
is Result.Loading -> {
loader.makeVisible() …Run Code Online (Sandbox Code Playgroud) android kotlin android-livedata android-viewmodel kotlin-coroutines
android ×10
android-architecture-components ×5
android-room ×3
kotlin ×2
mvvm ×2
bindservice ×1
performance ×1