MVVM - 如何将上下文传递给存储库类?

Posted

技术标签:

【中文标题】MVVM - 如何将上下文传递给存储库类?【英文标题】:MVVM - how do I pass context to the repository class? 【发布时间】:2021-04-06 22:36:03 【问题描述】:

我正在尝试学习 MVVM,但遇到了一些我不知道如何解决的问题。我想创建一个存储库,它将在后台线程中获取用户坐标。事情是为了让它工作,我必须为它传递上下文,但我不知道如何为存储库传递上下文。我不能像在某些活动课程中那样轻松地通过它。

存储库

    public class LocationRepository 
    
    private void test() 
        
        FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(CONTEXT);
        
            if (ContextCompat.checkSelfPermission(CONTEXT, Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(CONTEXT, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(CONTEXT, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) 

                client.getLastLocation().addOnSuccessListener(CONTEXT, new OnSuccessListener<Location>() 
                    @Override
                    public void onSuccess(Location location) 
                        if (location != null)
                            //TODO
                        
                    
                );
            
            else
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
                    requestPermissions(new String[]
                            Manifest.permission.INTERNET, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION
                    , 1);
                
            
        
    

【问题讨论】:

您不需要传递上下文来创建FusedLocationProviderClient。您应该通过构造函数传递/注入FusedLocationProviderClient。使用 DependencyInjection,您可以创建一次FusedLocationProviderClient(来自 ApplicationContext)并将其传递给需要它的任何人。否则,您可以将上下文从 Activity/Fragment 传递到 ViewModel 到 Repository。 目前我没有使用任何 DependencyInjection。您指的第二种方式实际上是下面的答案吗? 【参考方案1】:

如果您不想使用依赖注入,请考虑这一点。

这是一个最小的示例,留下了许多有待改进的地方!

在这个例子中,我们不会传递Context,因为这会导致内存泄漏(如果没有彻底处理),而是在 Activity 中创建 FusedLocationProviderClient 并将其传递给 ViewModel 和 Repository。

注意:避免将与 android 相关的内容(例如 ContextView 等)传递到您的 ViewModel 和较低层。它将使测试和重构更容易,因为您对 Android 的依赖更少。

在您的 Activity 中,您将获得您的 ViewModel 并创建您的 FusedLocationProviderClient

public class YourActivity : Activity() 

  private FusedLocationProviderClient locationProvider = LocationServices.getFusedLocationProviderClient(this.applicationContext);

  // Either you pass FusedLocationProviderClient via constructor to the ViewModel, or via a setter later
  private YourViewModel viewModel = // ...       

  override void onCreate() 
     super.onCreate();
     // if you wanna set the locationProvider via setter
     viewModel.setLocationProvider(locationProvider); // this should not leak when the activity finishes as there is no reference to the Activity or its view 
  

然后在您的 ViewModel 中,您可以通过 Constructor 或 setter 获得 locationProvider

public class YourViewModel extends ViewModel 
  
  // You can either create a new LocationRepository in the viewModel,
  // or you can pass an instance via Constructor (which I recommend for better testability)
  // or you pass it via a setter
  private LocationRepository locationRepository;

  public YourViewModel(FusedLocationProviderClient locationProvider) 
    locationRepository = new LocationRepository(locationProvider);
  

  // alternatively using a setter
  public void setFusedLocationProviderClient(FusedLocationProviderClient locationProvider) 
    locationRepository = new LocationRepository(locationProvider);
  

  // this function calls your repository
  public void foo() 
    // ensure LocationRepository is initialized or you will get a Nullpointer here,
    // or check if (locationRepository != null)  ...  before accessing it
    localRepository.test()
  

  @Override
  public void onCleared() 
    // do cleanup
    // stop ongoing work (in your repository)
    // unregister listeners (in your repository)
   

public class LocationRepository 

  private FusedLocationProviderClient locationProvider;

  public LocationRepository(FusedLocationProviderClient locationProvider) 
    this.locationProvider = locationProvider;
  

  public void test() 
    // ... now you can use FusedLocationProviderClient (without the need of having a context
  

【讨论】:

感谢您的帮助。非常感谢。

以上是关于MVVM - 如何将上下文传递给存储库类?的主要内容,如果未能解决你的问题,请参考以下文章

如何将上下文对象传递给 NSValueTransformer

如何将 this 上下文传递给函数?

如何将 this 上下文传递给事件处理程序?

如何将上下文传递给提供者的第二个小部件树

如何将函数传递给自己的反应上下文提供程序,让您编辑状态?

如何将对象上下文传递给 jQuery.ajax JSONP 回调?