标签: android-viewmodel

Kotlin:对不可变类型的内部变量的只读访问

在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 kotlin android-viewmodel

5
推荐指数
1
解决办法
1020
查看次数

在片段视图模型之间传递数据

让我先说一句,这更像是一个“结构性”问题,我不是要求任何人编写代码;我只是想弄清楚我应该如何构建我的应用程序。

我正在为我的应用程序使用 Android 的DrawerLayout/ NavigationView。这意味着这MainActivity是我所有片段的宿主。

我目前有三个片段(实际上它更多,但它们或多或少与这三个片段完全一样,只是针对不同的数据集)。

  • 列表片段
  • 细节片段
  • EditFragment(用于添加和编辑)

在我的ListFragment我(惊喜!)项目清单。这是一个(与的生命周期相关联)LiveData上的集合。当一个项目被点击时,我通过接口侦听器将事件传递给。SharedViewModelMainActivityMainActivity

MainActivity然后加载DetailFragment. 在同一个调用中,我加载了SharedViewModel(再次绑定到MainActivity)的实例。我设置SharedViewModel.selectedItem为被点击的项目。然后,在DetailFragmentonCreate函数中,我通过ViewModelProviders.of(activity).get(SharedViewModel::class.java).selectedItem.

在 上DetailFragment,有一个编辑按钮。这或多或少地经历了与上述相同的例程,但EditFragment改为加载。保存编辑/添加的项目后,我SharedViewModel通过MainActivity的接口侦听器添加/替换的集合中的项目。

显然这不是最佳的,原因有几个。一方面,这意味着我至少有 5 组大数据在MainActivity的生命周期内(本质上是应用程序的整个生命周期)。此外,MainActivity由于我必须添加越来越多的函数来处理事件,因此变得一发不可收拾。

想要做的是有,例如,我在一个项目列表ListFragmentViewModel绑定在ListFragment的生命周期。我在 a 上选择的项目DetailFragmentViewModel,我在 上的编辑项目EditFragmentViewModel,等等。

我的问题是我不确定在这种情况下如何正确传递数据。例如,假设我在EditFragment. 我如何将其放入ListFragmentViewModel的项目集合中?ListFragment位于后端堆栈中,因此它的视图模型会在导航回时挂起并且不会重新加载数据,因为它仍然具有之前的集合。这是有道理的,并且可能应该 …

android android-fragments kotlin android-viewmodel

5
推荐指数
1
解决办法
4618
查看次数

将LiveData与包含的不同对象合并

所以我正在使用Room和LiveData编写应用程序。这是一个财务应用程序。我有两个要合并的实体,即PayeeTransaction交易有一个ForeignKey将其链接到Payee。我一直在使用Room中的LiveData,一直到(Daos,Repository,ViewModels)到我的UI(片段)。

在到达“片段”级别之前,我想在某种程度上合并这两个数据集,但不确定如何去做。我知道我可以直接从数据库中使用查询创建POJO,但我有点想在其中包含一个带有PayeeTransaction 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

5
推荐指数
1
解决办法
2362
查看次数

Android ViewModel无法在片段更改后继续存在

我一直在尝试使用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

5
推荐指数
1
解决办法
1724
查看次数

如何在单个活动中加载多个 AndroidViewModel 以访问使用 Room 从多个表返回值的 LiveData

我正在 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

5
推荐指数
1
解决办法
855
查看次数

Android Navigation 组件和 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 android-architecture-navigation

5
推荐指数
2
解决办法
2140
查看次数

在 MVVM 中,谁的工作是决定导航流?视图模型还是视图?

在 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

5
推荐指数
0
解决办法
1590
查看次数

如何让这个 ViewModelFactory 更加灵活并接受不同种类的 ViewModel 类?

我复制了一个带有 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)

android android-mvvm android-viewmodel

5
推荐指数
1
解决办法
1634
查看次数

带有 MVVM 架构组件的 StartActivityForResult

在其中一个 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

5
推荐指数
1
解决办法
2323
查看次数

在 ViewModel 中加载已在 SplashActvity 中检索到的数据

我是 ViewModel 的新手,我知道它是一种与片段通信的强大而简单的方式。

我的问题如下: 如何加载在 mainActivity 的 ViewModel 中的 SplashActivity 中检索到的数据?

我的应用程序架构如下:

  1. SplashActivity:通过改造检索数据并将其存储到列表中
  2. 主要活动:包含两个以不同方式显示数据的片段

这是一段代码,显示了我的实现。

飞溅活动

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

5
推荐指数
1
解决办法
3566
查看次数