使用 ViewModel 和 LiveData 递增变量的简单片段示例 - 变量始终为空
Posted
技术标签:
【中文标题】使用 ViewModel 和 LiveData 递增变量的简单片段示例 - 变量始终为空【英文标题】:Simple fragment example of incrementing a variable using ViewModel and LiveData - variable always null 【发布时间】:2019-02-19 19:36:42 【问题描述】:注意:我是编码新手,我正在尝试按照标题的行来遵循一个简单的示例。
一切似乎都很顺利,除了在Tab1Fragment
的onClick()
方法中增加变量时遇到问题。 value
变量的值总是出现null
。
我认为,这与将 Interger
与 LiveData<Integer>
混合使用有关,但我不确定如何处理它。我已经尝试了各种方法来将一种转换为另一种并返回 get/store 结果。我关注的指南 (link) 使用 .setValue()
方法,但 android studio 不允许我使用该方法。
我很想为解决这个问题提供意见,甚至只是一个超级简单的选项卡片段教程的链接,我可以将其复制粘贴到项目中并检查这一切是如何工作的。我确信有一种更简单的方法可以完成这项任务,但我想了解如何在未来的项目中使用这个概念。
谢谢。
Tab1Fragment.java
package com.example.android.tabsharer;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
public class Tab1Fragment extends Fragment
private static final String TAG = "Tab1Fragment";
public SharedViewModel model;
public LiveData<Integer> score;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
View view = inflater.inflate(R.layout.tab1_fragment, container, false);
// Get the viewmodel
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
// Create observer to update the fragment
TextView score1 = getActivity().findViewById(R.id.score1);
final Observer<Integer> scoreObserver = new Observer<Integer>()
@Override
public void onChanged(@Nullable Integer newScore)
//Update the textview that holds the score
score1.setText(newScore);
;
// Observe the live data
model.getScore().observe(getActivity(), scoreObserver);
// Create the button in java, set listener on it, increment score, and store to viewmodel
final Button button = view.findViewById(R.id.editScore1);
button.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
// Basically every version of this comes up as null
Integer value = model.getScore().getValue();
if (value != null)
model.storeScore(++value);
else
model.storeScore(0);
);
return view;
SharedModelView.java
package com.example.android.tabsharer;
import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.support.annotation.NonNull;
import android.util.Log;
public class SharedViewModel extends AndroidViewModel
public static final String TAG = "SharedViewModel";
private MutableLiveData<Integer> mScore = new MutableLiveData<>();
public SharedViewModel(@NonNull Application application)
super(application);
public Integer storeScore(Integer score)
Log.d(TAG, "Score is being stored is " + mScore);
mScore.setValue(score);
return score;
public LiveData<Integer> getScore()
Log.d(TAG, "Score is being retrieved");
if (mScore == null)
mScore = new MutableLiveData<>();
mScore.setValue(0);
return mScore;
MainActivity.java
package com.example.android.tabsharer;
import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProvider;
import android.arch.lifecycle.ViewModelProviders;
import android.support.design.widget.TabLayout;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity
private static final String TAG = "MainActivity";
public SharedViewModel model;
private SectionsPageAdapter mSectionsPageAdapter;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: Starting.");
model = ViewModelProviders.of(this).get(SharedViewModel.class);
mSectionsPageAdapter = new SectionsPageAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
setupViewPager(mViewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
private void setupViewPager(ViewPager viewPager)
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), "TAB1");
adapter.addFragment(new Tab2Fragment(), "TAB2");
viewPager.setAdapter(adapter);
【问题讨论】:
【参考方案1】:你的问题在于两件事,
问题 1:(可选)
// Observe the live data
model.getScore().observe(getActivity(), scoreObserver);
您在 Fragment
& 内部使用观察者,因此您应该使用它的 LifeCycle
进行这样的观察:
// Observe the live data
model.getScore().observe(this, scoreObserver);
问题 2: 是您使用 Integer
作为 LiveData
内部的包装器,在此方法期间未初始化:
public LiveData<Integer> getScore()
Log.d(TAG, "Score is being retrieved");
if (mScore == null)//This code won't execute because you've initialized it globally.
mScore = new MutableLiveData<>();
mScore.setValue(0);
return mScore;
所以,尝试将Interger
更改为int
& 它将被初始化为默认值0。
因为Integer
在此处将是null
:
// Basically every version of this comes up as null
Integer value = model.getScore().getValue();
解决方案:将 private MutableLiveData<Integer> mScore = new MutableLiveData<>();
更改为 private MutableLiveData<int> mScore = new MutableLiveData<>();
(它会在您使用 LiveData 的任何地方显示错误,因此将其更改为 int)
【讨论】:
感谢您的帮助。我可以看到您对问题 1 的看法。但是,对于问题 2,我最初尝试使用 MutableLiveDataViewModel
或LiveData
以上是关于使用 ViewModel 和 LiveData 递增变量的简单片段示例 - 变量始终为空的主要内容,如果未能解决你的问题,请参考以下文章
JetpackLiveData 架构组件 ( LiveData 简介 | LiveData 使用方法 | ViewModel + LiveData 示例 )
使用 ViewModel 和 LiveData 多次改造执行 API