DataBinding 和 LiveData :两种实现(Kotlin 和 Java),不能使 Java impl 工作
Posted
技术标签:
【中文标题】DataBinding 和 LiveData :两种实现(Kotlin 和 Java),不能使 Java impl 工作【英文标题】:DataBinding & LiveData : two implementations (Kotlin & Java) and can't make the Java impl working 【发布时间】:2020-01-22 16:45:33 【问题描述】:我在 Java 项目中使用 DataBinding 和 LiveData 时遇到问题。我在 Kotlin 中学习了以前的课程,当我尝试实现相同的行为时,我就是无法让它发挥作用。在理解方面,我显然遗漏了一些东西,所以我想听听你的想法。
我将粘贴 Kotlin(工作)示例中的代码,然后粘贴 Java(不工作)示例。
科特林
score_fragment.xml
...
<data>
<variable
name="scoreViewModel"
type="com.example.android.guesstheword.screens.score.ScoreViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/score_layout"
android:layout_
android:layout_
tools:context=".screens.score.ScoreFragment">
<TextView
android:id="@+id/score_text"
...
android:text="@String.valueOf(scoreViewModel.score)"
.../>
...
ScoreFragment.kt
class ScoreFragment : Fragment()
private lateinit var viewModelFactory: ScoreViewModelFactory
private lateinit var viewModel: ScoreViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View?
// Inflate view and obtain an instance of the binding class.
val binding: ScoreFragmentBinding = DataBindingUtil.inflate(
inflater,
R.layout.score_fragment,
container,
false
)
// Get args using by navArgs property delegate
val scoreFragmentArgs by navArgs<ScoreFragmentArgs>()
viewModelFactory = ScoreViewModelFactory(scoreFragmentArgs.score)
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ScoreViewModel::class.java)
binding.scoreViewModel = viewModel
binding.lifecycleOwner = this
return binding.root
ScoreViewModel.kt
class ScoreViewModel(finalScore: Int) : ViewModel()
private val _score = MutableLiveData<Int>()
val score: LiveData<Int>
get() = _score
private val _eventPlayAgain = MutableLiveData<Boolean>()
val eventPlayAgain: LiveData<Boolean>
get() = _eventPlayAgain
init
Timber.i("ScoreViewModel created")
_score.value = finalScore
fun onPlayAgain()
_eventPlayAgain.value = true
fun onPlayAgainComplete()
_eventPlayAgain.value = false
override fun onCleared()
super.onCleared()
Timber.i("ScoreViewModel cleared")
解释:让我们只关注分值。在 ScoreViewModel 中,该值属于 LiveData 类型。当片段启动时,该值通过“@String.valueOf(scoreViewModel.score)”正确显示在屏幕上。这可以正常工作。
JAVA
activity_main.xml
<data>
<variable
name="noteViewModel"
type="com.example.architectureapp.viewModel.NoteViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_
android:layout_
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:text="@noteViewModel.test" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
public class MainActivity extends AppCompatActivity
private ActivityMainBinding binding;
private NoteViewModel mNoteViewModel;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
binding = ActivityMainBinding.inflate(getLayoutInflater());
mNoteViewModel = ViewModelProviders.of(this).get(NoteViewModel.class);
binding.setNoteViewModel(mNoteViewModel);
binding.setLifecycleOwner(this);
NoteViewModel
public class NoteViewModel extends AndroidViewModel
public MutableLiveData<String> test = new MutableLiveData<>("TesT");
public NoteViewModel(@NonNull Application application)
super(application);
说明:这里我设置了一个 MutableLiveData 测试,其值为“TestT”,然后我打算使用 android:text="@noteViewModel.test" 显示它。但文本永远不会显示并保持空白。
显然有问题,但尽管两种实现之间存在语法差异,但我就是不明白为什么 Java 版本没有在 Textview 中显示值。
编辑
感谢 Rajnish suryavanshi,我没有以正确的方式装订,我只能使用:
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
这一项使用提供的布局设置内容视图并返回绑定。 或者你可以这样做:
binding = ActivityMainBinding.inflate(getLayoutInflater());(返回绑定但不设置内容视图)
setContentView(binding.getRoot());(使用绑定根视图设置内容视图)
我发现这具有误导性 -> https://developer.android.com/topic/libraries/data-binding/expressions
它表明我们可以替换
ActivityMainBinding 绑定 = DataBindingUtil.setContentView(this, R.layout.activity_main);
由
ActivityMainBinding 绑定 = ActivityMainBinding.inflate(getLayoutInflater());
这是不一样的!
现在很高兴获得精妙!
【问题讨论】:
添加测试可变实时数据的getter方法。 使用 android:text="@safeUnbox(viewModel.test)" @Rajnishsuryavanshi,我试过但没有运气。顺便说一下,为了示例测试的目的,它被声明为 public,所以不需要 getter。 @ZaferCelaloglu,我得到一个“在类 androidx.databinding.ViewDataBinding 中找不到方法 safeUnbox(java.lang.String)”。我在某处读到使用双向绑定时可能会发生这种情况,但这里不是这种情况。 【参考方案1】:看看这两行。
setContentView(R.layout.activity_main);
binding = ActivityMainBinding.inflate(getLayoutInflater());
您在扩展布局时并未创建绑定。而不是setContentView
使用DataBindingUtil.setContentView(this, R.layout.activity_main);
现在您可以使用布局充气器获取视图
binding = ActivityMainBinding.inflate(getLayoutInflater());
【讨论】:
哼实际上这不起作用,但你让我走上了正确的道路。我对充气实际上做了什么感到困惑。做: DataBindingUtil.setContentView(this, R.layout.activity_main); binding = ActivityMainBinding.inflate(getLayoutInflater()); 不起作用,但是这个: binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); 和 this : binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 工作。这是误导 -> developer.android.com/topic/libraries/data-binding/expressions以上是关于DataBinding 和 LiveData :两种实现(Kotlin 和 Java),不能使 Java impl 工作的主要内容,如果未能解决你的问题,请参考以下文章
Android MVVM框架搭建ViewModel + LiveData + DataBinding
Android MVVM框架搭建ViewModel + LiveData + DataBinding
Lifecycle+liveData+DataBinding三部曲
Android Architecture(中文官方文档)——MVVM、DataBinding、Lifecycle、Room、LiveData