Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
384 views
in Technique[技术] by (71.8m points)

java - MVVM - how do I pass context to the repository class?

I'm trying to learn MVVM, and I faced some issue which I don't know how to resolve. I wanted to make a repository which will get user coordinates in background thread. The thing is in order to make it work, I have to pass context for it, but I don't know how to pass context for repository. I can't just pass it that easily like in some activity class.

Repository

    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);
                }
            }
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Consider this if you do not wanna use Dependency Injection.

This is a minimal example leaving lots of stuff open for improvements!

In this example we not gonna pass down the Context as this can lead to memory leaks (if not thoroughly handled) but creating the FusedLocationProviderClient in the Activity and passing it to the ViewModel and the Repository.

Note: Avoid passing Android related things like Context, View's etc down to your ViewModel and lower layers. It will make testing and refactorings easier, because you less depend on Android.

In your Activity you get your ViewModel and you create your 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 
  }
}

Then in your ViewModel you either get the locationProvider via Constructor or a setter:

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
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...