MVVM - 如何将上下文传递到存储库 class?
MVVM - how do I pass context to the repository class?
我正在尝试学习 MVVM,但遇到了一些我不知道如何解决的问题。我想创建一个存储库,它将在后台线程中获取用户坐标。问题是为了让它工作,我必须为其传递上下文,但我不知道如何为存储库传递上下文。我不能像在某些 activity class.
中那样轻松地通过它
存储库
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);
}
}
}
}
}
如果你不想使用依赖注入,请考虑这个。
这是一个最小的例子,还有很多地方有待改进!
在这个例子中我们不会传递 Context
因为这会导致内存泄漏(如果没有彻底处理)但是在 Activity 中创建 FusedLocationProviderClient
并传递它到 ViewModel 和存储库。
注意:避免将 Android 相关的东西(例如 Context
、View
等)传递到您的 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 中,您可以通过构造函数获得 locationProvider
或 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
}
我正在尝试学习 MVVM,但遇到了一些我不知道如何解决的问题。我想创建一个存储库,它将在后台线程中获取用户坐标。问题是为了让它工作,我必须为其传递上下文,但我不知道如何为存储库传递上下文。我不能像在某些 activity class.
中那样轻松地通过它存储库
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);
}
}
}
}
}
如果你不想使用依赖注入,请考虑这个。
这是一个最小的例子,还有很多地方有待改进!
在这个例子中我们不会传递 Context
因为这会导致内存泄漏(如果没有彻底处理)但是在 Activity 中创建 FusedLocationProviderClient
并传递它到 ViewModel 和存储库。
注意:避免将 Android 相关的东西(例如 Context
、View
等)传递到您的 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 中,您可以通过构造函数获得 locationProvider
或 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
}