在Android中学习ViewModels时,出现了一个问题,感觉像是要解决Kotlin。在下面的代码中,我们可以看到MutableLiveData值正在用于编辑值和指标。但是,我们不希望这些可变值暴露给其他任何事物,特别是Android生命周期的成员。我们确实希望Android Lifecycle成员有权读取值,但不能设置它们。因此,下面显示的3个公开函数是LiveData <>不可变类型。
有没有更简单或更简洁的方法来公开可以在内部编辑的只读值?这似乎是Kotlin要避免的事情:样板冗长。
class HomeListViewModel: ViewModel(){
//Private mutable data
private val repositories = MutableLiveData<List<Repo>>()
private val repoLoadError = MutableLiveData<Boolean>()
private val loading = MutableLiveData<Boolean>()
//Exposed uneditable LIveData
fun getRepositories():LiveData<List<Repo>> = repositories
fun getLoadError(): LiveData<Boolean> = repoLoadError
fun getLoadingStatuses(): LiveData<Boolean> = loading
init{...//Do some stuff to MutableLiveData<>
}
}
Run Code Online (Sandbox Code Playgroud)
可能类似的非Android场景是:
class ImmutableAccessExample{
private val theThingToBeEditedInternally = mutableListOf<String>()
fun theThingToBeAccessedPublicly(): List<String> = theThingToBeEditedInternally
init {
theThingToBeEditedInternally.add(0, "something")
}
}
Run Code Online (Sandbox Code Playgroud) 让我先说一句,这更像是一个“结构性”问题,我不是要求任何人编写代码;我只是想弄清楚我应该如何构建我的应用程序。
我正在为我的应用程序使用 Android 的DrawerLayout/ NavigationView。这意味着这MainActivity是我所有片段的宿主。
我目前有三个片段(实际上它更多,但它们或多或少与这三个片段完全一样,只是针对不同的数据集)。
在我的ListFragment我(惊喜!)项目清单。这是一个(与的生命周期相关联)LiveData上的集合。当一个项目被点击时,我通过接口侦听器将事件传递给。SharedViewModelMainActivityMainActivity
MainActivity然后加载DetailFragment. 在同一个调用中,我加载了SharedViewModel(再次绑定到MainActivity)的实例。我设置SharedViewModel.selectedItem为被点击的项目。然后,在DetailFragment的onCreate函数中,我通过ViewModelProviders.of(activity).get(SharedViewModel::class.java).selectedItem.
在 上DetailFragment,有一个编辑按钮。这或多或少地经历了与上述相同的例程,但EditFragment改为加载。保存编辑/添加的项目后,我SharedViewModel通过MainActivity的接口侦听器添加/替换的集合中的项目。
显然这不是最佳的,原因有几个。一方面,这意味着我至少有 5 组大数据在MainActivity的生命周期内(本质上是应用程序的整个生命周期)。此外,MainActivity由于我必须添加越来越多的函数来处理事件,因此变得一发不可收拾。
我想要做的是有,例如,我在一个项目列表ListFragmentViewModel绑定在ListFragment的生命周期。我在 a 上选择的项目DetailFragmentViewModel,我在 上的编辑项目EditFragmentViewModel,等等。
我的问题是我不确定在这种情况下如何正确传递数据。例如,假设我在EditFragment. 我如何将其放入ListFragmentViewModel的项目集合中?ListFragment位于后端堆栈中,因此它的视图模型会在导航回时挂起并且不会重新加载数据,因为它仍然具有之前的集合。这是有道理的,并且可能应该 …
所以我正在使用Room和LiveData编写应用程序。这是一个财务应用程序。我有两个要合并的实体,即Payee和Transaction。 交易有一个ForeignKey将其链接到Payee。我一直在使用Room中的LiveData,一直到(Daos,Repository,ViewModels)到我的UI(片段)。
在到达“片段”级别之前,我想在某种程度上合并这两个数据集,但不确定如何去做。我知道我可以直接从数据库中使用查询创建POJO,但我有点想在其中包含一个带有Payee的Transaction Object,而不仅仅是两个字段中的所有字段。
有没有办法做到这一点?也许使用其中一种转换(map或switchMap)?还是使用MediatorLiveData?他们可以观察不止一种数据类型(例如LiveData和LiveData)吗?
Payee.java
@Entity
public class Payee {
@PrimaryKey (autoGenerate = true)
@ColumnInfo (name = "id")
private int id;
. . .
}
Run Code Online (Sandbox Code Playgroud)
Transaction.java
@Entity (foreignKeys =
@ForeignKey(entity = Payee.class,
parentColumns = "id",
childColumns = "payee_id",
onDelete = RESTRICT))
public class Transaction {
@PrimaryKey (autoGenerate = true)
@ColumnInfo (name = "id")
private int id;
@ColumnInfo (name = "payee_id")
private int payeeId;
@Ignore
private Payee payee;
. . …Run Code Online (Sandbox Code Playgroud) android android-room android-livedata android-viewmodel android-architecture-components
我一直在尝试使用viewmodel和livedata来分享片段之间的信息.
但是当我从第一个片段更改为另一个片段时,我的viewmodel似乎重新初始化,使我丢失了以前存储的所有数据.
我在我的片段中以相同的方式获得了两次我的viewmodel:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
interventionViewModel = ViewModelProviders.of(this).get(InterventionsViewModel.class);
}
Run Code Online (Sandbox Code Playgroud)
这就是我在我的活动中替换我的framgents的方式(我猜问题必须来自片段生命周期,但我无法弄清楚错误在哪里:/)
public void showFragment(Fragment fragment) {
String TAG = fragment.getClass().getSimpleName();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment, TAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
}
public void backstackFragment() {
Log.d("Stack count", getSupportFragmentManager().getBackStackEntryCount() + "");
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
finish();
}
getSupportFragmentManager().popBackStack();
removeCurrentFragment();
}
private void removeCurrentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFrag = getSupportFragmentManager()
.findFragmentById(R.id.fragment_container);
if (currentFrag != null) {
transaction.remove(currentFrag);
}
transaction.commitAllowingStateLoss();
}
Run Code Online (Sandbox Code Playgroud)
当我需要一个片段时,我会调用backStackFragment()删除当前片段然后调用showFragment(MyFragment.newInstance());
该片段是AndroidStudio生成的片段 …
android android-fragments android-livedata android-viewmodel android-architecture-components
我正在 android 中开发一个电子商务应用程序,我必须在其中创建多个表,在其上插入数据并从该表中获取活动/片段中的数据(Spinner 中的加载值,基于运行条件的子查询等)。为此,我声明了 2 个表。地址,银行如下
银行.java
@Entity
public class Bank {
@PrimaryKey(autoGenerate = true)
public int id;
public String bankId;
public String bankName;
public String bankType;
public Bank() {
}
public String getBankId() {
return bankId;
}
public String getBankName() {
return bankName;
}
public String getBankType() {
return bankType;
}
}
Run Code Online (Sandbox Code Playgroud)
地址.java
@Entity
public class Address {
@PrimaryKey(autoGenerate = true)
public int id;
public String state;
public String district;
public String block;
public String id_panchayat;
public String panchayat; …Run Code Online (Sandbox Code Playgroud) sqlite android android-room android-livedata android-viewmodel
Android Viewmodel 可以具有活动或片段的范围/生命周期,但这在导航组件中如何工作?
考虑我是否有以下情况:
主要活动 - 包含 NavHostFragment 客户列表片段 - 导航的起点 - 单击列表中的任何客户,将导航 CustomerDetailsFragment 客户详细信息片段 - 包含一个带有 3 个片段的选项卡:CustomerDetailFragment、CustomerContactFragment 和 CustomerOrderHistoryFragment 客户详细信息片段 - 显示客户的一般信息,如姓名、年龄、性别等... - 从 CustomerViewModel 获取数据 客户联系片段 - 显示客户地址、电话、传真等 - 从 CustomerViewModel 获取数据 客户订单历史片段 - 显示客户的订单历史 - 从 OrderHistoryViewModel 获取数据
在上面的场景中,是否可以为 CustomerDetailFragment 和 CustomerContactFragment 共享相同的 CustomerViewModel 实例?
如果我没有使用导航组件,我可以让 CustomerDetailsFragment 成为一个活动并将我的视图模型初始化为该活动,但由于在导航中我们只有片段,我怎样才能最好地实现这一点?
我想:
公共类 CustomerDetailsFragment 扩展 Fragment {
...
CustomerViewModel 模型 = ViewModelProviders.of(this).get(CustomerViewModel .class);
...
但是如何将这个 viewmodel 实例传递给 CustomerDetailFragment 和 CustomerContactFragment?
或者有没有更好的方法来构造上面的代码以达到相同的结果?
在 Android 上下文中,当收到响应时,决策点是否应该在 ViewModel 中,类似于我的 ViewModel:
if (response.isSuccess()) {
nextScreenLiveData.value = GO_TO_NEXT_SCREEN
} else if(response.isNeedAnotherScreen()) {
anotherScreenLiveData.value = ANOTHER_SCREEN
} else {
backToBeforeScreen = BACK_TO_BEFORE_SCREEN
}
Run Code Online (Sandbox Code Playgroud)
然后所有这些 LiveData 将在 Activity/Fragment 中被观察到。意味着每个 LiveData 有一个观察者。
或者最好在我的 ViewModel 中做这样的事情:
liveData.value = response
Run Code Online (Sandbox Code Playgroud)
然后在我的活动/片段中做出决定:
liveData.observe(this, Observer { response ->
if (response.isSuccess()) {
goToNextScreen()
} else if(response.isNeedAnotherScreen()) {
goToAnotherScreen()
} else {
goBack()
}
}
Run Code Online (Sandbox Code Playgroud)
提前致谢。
android mvvm android-viewmodel android-architecture-components android-jetpack
我复制了一个带有 Android 架构组件、Retrofit、Dagger 和数据绑定的 MVVM 示例。我使用此代码作为我的应用程序的起点,以便开始在 Android 应用程序开发中使用更好的架构。但是,请使用以下代码:
interface ViewModelInjector {
/**
* Injects required dependencies into the specified PostListViewModel.
* @param postListViewModel PostListViewModel in which to inject the dependencies
*/
fun inject(postListViewModel: PostListViewModel)
@Component.Builder
interface Builder {
fun build(): ViewModelInjector
fun networkModule(networkModule: NetworkModule): Builder
}
}
Run Code Online (Sandbox Code Playgroud)
和
class ViewModelFactory(private val activity: AppCompatActivity) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(PostListViewModel::class.java)) {
val db = Room.databaseBuilder(
activity.applicationContext,
AppDatabase::class.java,
"posts"
).build()
@Suppress("UNCHECKED_CAST")
return PostListViewModel(db.postDao()) as …Run Code Online (Sandbox Code Playgroud) 在其中一个 Google Codelabs 中,Activity1显示一个RecyclerView和 按钮单击打开Activity2,可以在其中添加新条目。
他们不是访问ViewModelinActivity2并将条目直接添加到数据库中,而是将条目发送回Activity1并将其插入那里。
这背后的原因是什么?为什么要发回数据Activity1?为什么不叫ViewModelProviders.of(this)中Activity2和插入那里的项目吗?
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, NewWordActivity.class);
startActivityForResult(intent, NEW_WORD_ACTIVITY_REQUEST_CODE);
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == NEW_WORD_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
Word word = new Word(data.getStringExtra(NewWordActivity.EXTRA_REPLY));
mWordViewModel.insert(word);
} else {
Toast.makeText( …Run Code Online (Sandbox Code Playgroud) android android-mvvm android-viewmodel android-architecture-components
我是 ViewModel 的新手,我知道它是一种与片段通信的强大而简单的方式。
我的问题如下: 如何加载在 mainActivity 的 ViewModel 中的 SplashActivity 中检索到的数据?
我的应用程序架构如下:
这是一段代码,显示了我的实现。
飞溅活动
public class SplashActivity extends AppCompatActivity {
private final String TAG = "TAG.SplashActivity";
public static List<Toilet> toiletList = new ArrayList<>(); // HERE IS THE DATA I WANT TO
RETRIEVE IN THE MAIN ACTIVITY
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*Create handle for the RetrofitInstance interface*/
GetDataService service = ...;
// MY STUFF RETROFIT including
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.putExtra("toiletList", (Serializable) toiletList);
startActivity(intent); …Run Code Online (Sandbox Code Playgroud) android mvvm android-fragments android-activity android-viewmodel
android ×9
android-architecture-components ×4
android-mvvm ×2
android-room ×2
kotlin ×2
mvvm ×2
android-architecture-navigation ×1
sqlite ×1