You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVVM架构下如何向Repository类传递Context?

解决MVVM架构中Repository传递Context的问题

嘿,我来帮你搞定这个问题!在MVVM架构里,Repository确实不应该直接持有Activity/Fragment的Context(容易引发内存泄漏),但我们可以用Application Context来满足需求,同时还要调整你代码里权限请求的逻辑——因为requestPermissions是UI层(Activity/Fragment)的专属方法,Repository里可不能直接调用哦。

一、给Repository传递Context的正确姿势

1. 构造函数注入Application Context

这是最直接且安全的方式,创建Repository时传入Context,但内部要保存Application级别的Context,避免和UI组件绑定导致泄漏。

修改你的LocationRepository:

public class LocationRepository {
    private final Context appContext;

    // 通过构造函数传入Context,内部留存Application Context
    public LocationRepository(Context context) {
        this.appContext = context.getApplicationContext();
    }

    public void getLastLocation(LocationCallback callback) {
        FusedLocationProviderClient client = LocationServices.getFusedLocationProviderClient(appContext);
        
        // 用App Context做权限检查
        if (ContextCompat.checkSelfPermission(appContext, Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED 
            && ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED 
            && ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            
            client.getLastLocation().addOnSuccessListener(location -> {
                if (location != null) {
                    callback.onLocationReceived(location);
                } else {
                    callback.onLocationFailed("无法获取有效位置");
                }
            }).addOnFailureListener(e -> {
                callback.onLocationFailed(e.getMessage());
            });
        } else {
            // 权限不足,通知UI层去发起请求
            callback.onPermissionRequired();
        }
    }

    // 定义回调接口,让Repository和UI层解耦通信
    public interface LocationCallback {
        void onLocationReceived(Location location);
        void onPermissionRequired();
        void onLocationFailed(String error);
    }
}

接着在ViewModel里初始化Repository(推荐用AndroidViewModel直接拿到Application Context):

public class LocationViewModel extends AndroidViewModel {
    private LocationRepository locationRepository;

    public LocationViewModel(@NonNull Application application) {
        super(application);
        // 用Application Context初始化Repository
        locationRepository = new LocationRepository(application);
    }

    public void fetchLocation(LocationRepository.LocationCallback callback) {
        locationRepository.getLastLocation(callback);
    }
}

最后在Activity里处理回调和权限请求:

public class MainActivity extends AppCompatActivity {
    private LocationViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        viewModel = new ViewModelProvider(this).get(LocationViewModel.class);
        viewModel.fetchLocation(new LocationRepository.LocationCallback() {
            @Override
            public void onLocationReceived(Location location) {
                // 处理获取到的位置数据
            }

            @Override
            public void onPermissionRequired() {
                // 在这里调用权限请求,因为这是Activity的专属方法
                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);
                }
            }

            @Override
            public void onLocationFailed(String error) {
                // 处理位置获取失败的情况
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1) {
            // 权限请求结果处理完后,重新触发位置获取
            viewModel.fetchLocation(...);
        }
    }
}

2. 用依赖注入框架(比如Hilt/Dagger)

如果你的项目用了依赖注入框架,直接注入Application Context会更规范,不用手动传递。比如用Hilt的话,只需要在Repository的构造函数里标记@Inject:

public class LocationRepository {
    private final Context appContext;

    @Inject
    public LocationRepository(@ApplicationContext Context context) {
        this.appContext = context;
    }

    // 其余逻辑和上面一致
}

这样在ViewModel里直接注入Repository即可,不用手动创建实例,更符合MVVM的解耦思想。

二、为什么不能在Repository里调用requestPermissions?

requestPermissions是Activity或Fragment的方法,属于UI层的交互操作,而Repository的核心职责是数据获取与处理,不应该和UI层耦合。把权限请求放到Activity/Fragment里,能让各层职责更清晰,也完全符合MVVM的架构原则。

内容的提问来源于stack exchange,提问作者BackToDream

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:24:25