如何在Android中通过ViewModel Class在Activity和Fragment之间共享数据?
How to Share Data between Activity and Fragment via ViewModel Class in Android?
我想知道是否可以将在 Activity class 中声明的字符串数据传递给 ViewModel class 然后将数据传递给片段 class.
ViewModel Class
class TimeTableViewModel extends ViewModel {
private MutableLiveData<String> start_time_str = new MutableLiveData<>();
void send_StartTime(String start_Time){
start_time_str.setValue(start_Time);
}
LiveData<String> get_StartTime(){
return start_time_str;
}}
在 ViewModel Class 中,我有 MutableLiveData<String> start_time_str
并且它已被初始化为 new MutableLiveData<>();
我想在 Activity class 中使用 void send_StartTime(String start_Time)
函数来设置参数 String start_Time
的值并在 Fragment [=55] 中调用 start_time_str
=].
Activity Class
@Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case android.R.id.home:
finish();
break;
case R.id.add_schedule_save:
String start_time_str = startTime.getText().toString();
Intent intent_restart0 = new Intent(TimeTable_Add_New_Schedule.this, MainActivity.class);
startActivity(intent_restart0);
TimeTableViewModel timeTableViewModel = new TimeTableViewModel();
timeTableViewModel.send_StartTime(start_time_str);
Toast.makeText(this,""+start_time_str,Toast.LENGTH_LONG).show();
break;
}
return super.onOptionsItemSelected(item);
}
片段Class
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TimeTableViewModel timeTableViewModel = new TimeTableViewModel();
timeTableViewModel.get_StartTime().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
mon_textView_11.setText(s);
}
});
}
在片段 class 中,我调用 get_StartTime()
函数来获取 start_time_str
并将字符串值设置为我的 TextView。我认为 start_time_str
已通过 Activity Class 中的 timeTableViewModel.send_StartTime(start_time_str);
的功能成功设置,因为 Toast.maketext 就像一个魅力。 但是 TextView 没有显示任何内容。我已经测试过 Text Color is not white 所以如果字符串值被正确调用,它应该出现在屏幕上。 如果您有任何建议,我很想听听您的建议。
非常感谢。
这实际上取决于您如何创建 ViewModel
实例。现在您正在通过其构造函数创建 ViewModel
,但这不是正确的方法。您应该使用 ViewModelProvider
或 Google 团队创建的扩展方法。
如果你选择 ViewModelProvider
你应该这样做:
TimeTableViewModel viewModel = new ViewModelProvider(this).get(TimeTableViewModel.class);
将正确的上下文传递给 ViewModelProvider
构造函数调用很重要。如果您在片段中并且您将只使用 getContext()
而不是 getActivity()
,您将不会获得与在 Activity 中创建的实例相同的实例。您将创建一个 ViewModel
的新实例,该实例的作用域仅在片段生命周期内。因此,重要的是在两个部分中使用 activity 上下文以获得相同的实例。
Activity部分:
TimeTableViewModel viewModel = new ViewModelProvider(this).get(TimeTableViewModel.class);
片段部分:
TimeTableViewModel viewModel = new ViewModelProvider(getActivity()).get(TimeTableViewModel.class);
重要的是您的片段位于使用此 ViewModel
的同一 activity 内。
但是 Google 的人通过一些扩展方法让我们更容易。但据我所知,他们只在 Kotlin 类 中工作。所以如果你有 Kotlin 代码,你可以像这样简单地声明你的 ViewModel
:
private val quizViewModel: TimeTableViewModel by activityViewModels()
对于片段范围 ViewModel
你需要这样写:
private val quizViewModel: TimeTableViewModel by viewModels()
但是您必须将 Kotlin ktx 依赖项添加到您的项目 build.gradle
文件中。例如像这样:
implementation 'androidx.fragment:fragment-ktx:1.1.0'
如果您正在使用 Android 架构并希望在您的 fragments
中共享 activityViewModel
。
要在 fragment
中获取 viewModels
,请使用以下代码:
private val fragmentViewModel: Fragment1ViewModel by viewModels()
private val activityViewModel: MainActivityViewModel by activityViewModels()
并在 MainActivity
中使用以下代码:
private val activityViewModel: MainActivityViewModel by viewModels()
我找到了解决此问题的最简单方法,而不是将所有者作为“this”更改为 getActivity()。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mvm == null) {
mvm = new ViewModelProvider(getActivity()).get(CounterFgViewModel.class);
}
}
我正在使用科特林语言
我使用与教程相同但不工作
下面是如何声明我的 ViewModel
的示例代码
在build.gradle中添加依赖:
implementation 'androidx.fragment:fragment-ktx:1.4.1'
Activity的例子class
class HomepageActivity : AppCompatActivity() {
private lateinit var sharedViewModel: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomepageBinding.inflate(layoutInflater)
setContentView(binding.root)
sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
sharedViewModel.isMenuOpen.observe(this, {
onMenuOpen(it)
})
}
片段中的示例 class
class HomeFragment : Fragment() {
private lateinit var sharedViewModel: SharedViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedViewModel = activity!!.run{
ViewModelProvider(this).get(SharedViewModel::class.java)
}
}
我想知道是否可以将在 Activity class 中声明的字符串数据传递给 ViewModel class 然后将数据传递给片段 class.
ViewModel Class
class TimeTableViewModel extends ViewModel {
private MutableLiveData<String> start_time_str = new MutableLiveData<>();
void send_StartTime(String start_Time){
start_time_str.setValue(start_Time);
}
LiveData<String> get_StartTime(){
return start_time_str;
}}
在 ViewModel Class 中,我有 MutableLiveData<String> start_time_str
并且它已被初始化为 new MutableLiveData<>();
我想在 Activity class 中使用 void send_StartTime(String start_Time)
函数来设置参数 String start_Time
的值并在 Fragment [=55] 中调用 start_time_str
=].
Activity Class
@Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case android.R.id.home:
finish();
break;
case R.id.add_schedule_save:
String start_time_str = startTime.getText().toString();
Intent intent_restart0 = new Intent(TimeTable_Add_New_Schedule.this, MainActivity.class);
startActivity(intent_restart0);
TimeTableViewModel timeTableViewModel = new TimeTableViewModel();
timeTableViewModel.send_StartTime(start_time_str);
Toast.makeText(this,""+start_time_str,Toast.LENGTH_LONG).show();
break;
}
return super.onOptionsItemSelected(item);
}
片段Class
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TimeTableViewModel timeTableViewModel = new TimeTableViewModel();
timeTableViewModel.get_StartTime().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
mon_textView_11.setText(s);
}
});
}
在片段 class 中,我调用 get_StartTime()
函数来获取 start_time_str
并将字符串值设置为我的 TextView。我认为 start_time_str
已通过 Activity Class 中的 timeTableViewModel.send_StartTime(start_time_str);
的功能成功设置,因为 Toast.maketext 就像一个魅力。 但是 TextView 没有显示任何内容。我已经测试过 Text Color is not white 所以如果字符串值被正确调用,它应该出现在屏幕上。 如果您有任何建议,我很想听听您的建议。
非常感谢。
这实际上取决于您如何创建 ViewModel
实例。现在您正在通过其构造函数创建 ViewModel
,但这不是正确的方法。您应该使用 ViewModelProvider
或 Google 团队创建的扩展方法。
如果你选择 ViewModelProvider
你应该这样做:
TimeTableViewModel viewModel = new ViewModelProvider(this).get(TimeTableViewModel.class);
将正确的上下文传递给 ViewModelProvider
构造函数调用很重要。如果您在片段中并且您将只使用 getContext()
而不是 getActivity()
,您将不会获得与在 Activity 中创建的实例相同的实例。您将创建一个 ViewModel
的新实例,该实例的作用域仅在片段生命周期内。因此,重要的是在两个部分中使用 activity 上下文以获得相同的实例。
Activity部分:
TimeTableViewModel viewModel = new ViewModelProvider(this).get(TimeTableViewModel.class);
片段部分:
TimeTableViewModel viewModel = new ViewModelProvider(getActivity()).get(TimeTableViewModel.class);
重要的是您的片段位于使用此 ViewModel
的同一 activity 内。
但是 Google 的人通过一些扩展方法让我们更容易。但据我所知,他们只在 Kotlin 类 中工作。所以如果你有 Kotlin 代码,你可以像这样简单地声明你的 ViewModel
:
private val quizViewModel: TimeTableViewModel by activityViewModels()
对于片段范围 ViewModel
你需要这样写:
private val quizViewModel: TimeTableViewModel by viewModels()
但是您必须将 Kotlin ktx 依赖项添加到您的项目 build.gradle
文件中。例如像这样:
implementation 'androidx.fragment:fragment-ktx:1.1.0'
如果您正在使用 Android 架构并希望在您的 fragments
中共享 activityViewModel
。
要在 fragment
中获取 viewModels
,请使用以下代码:
private val fragmentViewModel: Fragment1ViewModel by viewModels()
private val activityViewModel: MainActivityViewModel by activityViewModels()
并在 MainActivity
中使用以下代码:
private val activityViewModel: MainActivityViewModel by viewModels()
我找到了解决此问题的最简单方法,而不是将所有者作为“this”更改为 getActivity()。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (mvm == null) {
mvm = new ViewModelProvider(getActivity()).get(CounterFgViewModel.class);
}
}
我正在使用科特林语言 我使用与教程相同但不工作 下面是如何声明我的 ViewModel
的示例代码在build.gradle中添加依赖:
implementation 'androidx.fragment:fragment-ktx:1.4.1'
Activity的例子class
class HomepageActivity : AppCompatActivity() {
private lateinit var sharedViewModel: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomepageBinding.inflate(layoutInflater)
setContentView(binding.root)
sharedViewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
sharedViewModel.isMenuOpen.observe(this, {
onMenuOpen(it)
})
}
片段中的示例 class
class HomeFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedViewModel = activity!!.run{ ViewModelProvider(this).get(SharedViewModel::class.java) } }