【问题标题】:How to use AndroidViewModel inside Fragment. More importantly, Fragments which are generated on the go, through other Fragments?如何在 Fragment 中使用 AndroidViewModel。更重要的是,通过其他 Fragment 在旅途中生成的 Fragments?
【发布时间】:2021-03-30 03:55:01
【问题描述】:

Android Architechture Compnents 建议使用 ViewModel、LiveData、Room、Repository quadology 从本地数据库中获取数据。 正如Android Developers 和许多其他资源所描述的那样,我正在遵循路径:

数据库 -> Room (Dao) -> Repository -> ViewModel (AndroidViewModel) -> LiveData Observers

正如它所说,Repository 需要向数据库提供应用程序级别的上下文,这就是我们使用 AndroidViewModel 类来创建 Repository 的原因。 AndroidViewModel 在其构造函数中需要 Application 对象。

现在在 Fragments 中,每当我使用 getActivity().getApplication() 时,Android Studio 都会警告我 getActivity() 可能会返回 null 并生成 NullPointerException

我搜索了 Stackflow 并尝试了 requireActivity().getApplication()。有效。开发人员说总是在 onActivityCreated() 肉食中使用它。我注意到它仅适用于由 Activity 创建的那些片段。它不适用于在另一个 Fragment 中创建的那些 Fragment。他们从不接听onActivityCreated() 电话。

现在我不知道如何从此类访问 AndroidViewModel 对象。希望有人明白这里的问题是什么。请帮忙。

这是 BranchDetailsViewModel 类:

public class BranchDetailsViewModel extends AndroidViewModel {
    final BranchRepository branchRepository;
    final BankRepository bankRepository;
    final CityRepository cityRepository;
    final DistrictRepository districtRepository;
    final StateRepository stateRepository;

    LiveData<Branch> branch;


    public BranchDetailsViewModel(Application application) {
        super(application);
        branchRepository = new BranchRepository(application);
        bankRepository = new BankRepository(application);
        cityRepository = new CityRepository(application);
        districtRepository = new DistrictRepository(application);
        stateRepository = new StateRepository(application);
    }
}

这是另一个 Fragment 的子 BranchDetailsFragment。目前我正在从 Activity 创建的顶级片段中传递 Application 对象以使事情正常进行。:

public class BranchDetailsFragment extends Fragment {

    private final Application application;
    private final int branchIid;

    private FragBranchDetailsBinding binding;

    public BranchDetailsFragment(Application application, int branchIid) {
        this.application = application;
        this.branchIid = branchIid;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = FragBranchDetailsBinding.inflate(inflater, container, false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        BranchDetailsViewModel branchDetailsViewModel = new BranchDetailsViewModel(application);
    }
}

【问题讨论】:

  • 您不需要在 Fragment 中传递应用程序对象,您已经在传递的 @NonNull 视图视图中的 onViewCreated() 方法中拥有它,该视图始终不为空,因此您可以执行类似的操作即:Application application = (Application)view.getContext().getApplicationContext();

标签: android android-fragments android-viewmodel


【解决方案1】:

只有存储库需要上下文来查询数据库。在片段中,我们可以轻松访问上下文。因此,与其在 View Model 中创建 Repository 实例,不如在 Fragment 中创建 Repository 实例然后将它的引用传递给 ViewModel 将是安全的以避免内存泄漏。在这里您不需要 Android 视图模型,因为在视图模型中不再需要上下文。

因此,在您的情况下,您可以将存储库实例从父片段传递到子片段而不是应用程序实例,并使用 ViewModel 而不是 AndroidViewModel。

BranchDetailsViewModel 可能如下所示:

class BranchDetailsViewModel (
 val branchRepository: BranchRepository,
 val bankRepository: BankRepository ,
 val cityRepository: CityRepository,
 val districtRepository: DistrictRepository,
 val stateRepository: StateRepository
) : ViewModel() {
   // Do your stuff using repositories here --------
}

【讨论】:

  • 所以这意味着我不能使用带有 Fragments 的 AndroidViewModel 类作为其构造函数,需要 Application 对象,而 getActivity().getApplication() 可能会产生 NPE。
  • 如果您的要求是在 ViewModel 中使用上下文,您可以使用 AndroidViewModel。假设您在片段的 UI 中使用 viewModel 作为数据绑定。但是 ViewModel 不应该处理任何与 UI 相关的东西。
  • 为什么不使用依赖注入?如果你使用依赖注入,那么只有一个存储库类的实例将被创建为单例,你只需在整个项目中传递它的引用。
猜你喜欢
  • 2015-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多