Android 什么';使用MVP架构在运行时检查权限的最佳方法是什么?

Android 什么';使用MVP架构在运行时检查权限的最佳方法是什么?,android,android-permissions,mvp,Android,Android Permissions,Mvp,我正在开发一个android应用程序,在其中我必须在运行时请求权限。我想知道使用Model View Presenter体系结构实现该功能的最佳方法 我最初的想法是让演示者调用负责权限的组件(比如PermissionHandler),并相应地更新视图 问题在于检查权限的代码与活动类紧密耦合。以下是一些需要活动或上下文的方法: ContextCompat.checkSelfPermission() ActivityCompat.shouldShowRequestPermissionRegulat

我正在开发一个android应用程序,在其中我必须在运行时请求权限。我想知道使用Model View Presenter体系结构实现该功能的最佳方法

我最初的想法是让演示者调用负责权限的组件(比如
PermissionHandler
),并相应地更新视图

问题在于检查权限的代码与活动类紧密耦合。以下是一些需要活动或上下文的方法:

  • ContextCompat.checkSelfPermission()
  • ActivityCompat.shouldShowRequestPermissionRegulation()
  • ActivityCompat.requestPermissions()
  • onRequestPermissionsResult()
    (回调)
这意味着我必须向演示者传递一个活动对象,我不太喜欢它,因为我听说让演示者不受Android代码的影响对测试很有好处

因此,我考虑在视图级别(在活动中)处理权限,但我想这会损害视图只负责UI更新而不负责业务逻辑的目的

我不确定什么是最好的方法来解决这个问题,使代码尽可能地解耦和可维护。有什么想法吗?

我想做的是:

该视图将实现:

public Activity getViewActivity();
public void requestPermissions();
public void onPermissionsResult();
演示者将实现:

public Activity getViewActivity();
public void requestPermissions();
public void onPermissionsResult();
requestPermissions
中,演示者将执行以下操作:
getViewActivity();getViewActivity.requestPermissions();等等。

该视图将在
onRequestPermissionsResult
回调中调用
presenter.onPermissionsResult()

所有的逻辑都将在演示者内部实现

在我看来,演示者是解耦的:它不依赖于任何视图实现(它只依赖于视图接口)


“我听说让演示者远离Android代码有利于测试。”我不理解这一部分。如果代码良好,则可以毫无问题地对其进行测试。

如果仍然希望能够模拟权限访问/请求,则仍然可以创建类似于
PermissionHandler的内容,但只能在视图类中引用它。比如说-

接口:

public interface PermissionsHandler {
    boolean checkHasPermission(AppCompatActivity activity, String permission);
    void requestPermission(AppCompatActivity activity, String[] permissions, int requestCode);
}
生产实施:

public class PermissionsHandlerAndroid implements PermissionsHandler {
    @Override
    public boolean checkHasPermission(AppCompatActivity activity, String permission) {
        return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED;
    }

    @Override
    public void requestPermission(AppCompatActivity activity, String[] permissions, int requestCode){
        ActivityCompat.requestPermissions(activity, permissions, requestCode);
    }
}
模拟类(例如,测试并确保您的活动正确地处理了onRequestPermissionsResult


,则始终可以使视图实现更通用的方法,如
checkLocationPermissionGrassed()
requestLocationPermission()
。然后,您的视图实现可以根据需要引用活动,并且您的演示者永远不必触摸活动引用

权限请求和状态是视图(片段或活动)的责任,因为依赖于用户的操作来发出请求或授予权限。我使用MVP管理权限,如下所示(阅读外部存储示例):

我的合同

interface View {
    ...
    void requestReadPermission();
    boolean areReadPermissionGranted();
    void showPermissionError();
    void hidePermissionError();
    ...
}

interface Presenter {
    ...
    void setReadPermissions(boolean grantedPermissions);
    ...
}

interface Model {
    ...
}
我的观点是实现。(在本例中为片段,但它可以是活动或其他内容,演示者只希望得到响应)

以及演示者实现

public class MyPresenter implements Contract.Presenter {

...
Contract.View view;

public void doSomethingThatRequiresPermissions() {

    ...
        if ( !view.areReadPermissionGranted() ) {
            view.requestReadPermission();
            view.showPermissionError();
        } else {
            view.hidePermissionError();
            doSomethingWithPermissionsGranted();
        }
    ...
}

@Override
public void setReadPermissions(boolean grantedPermissions) {
    if( grantedPermissions ){
        view.hidePermissionError();
        doSomethingThatRequiresPermissions();

    } else {
        view.showPermissionError();
    }
}

public void doSomethingWithPermissionsGranted(){
    ...
}
然后你可以像这样做单元测试

Contract.View mockedView;
@Test
public void requestAlbumListWithoutPermissions() {
    when(mockedView.areReadPermissionGranted()).thenReturn(false);
    presenter.doSomethingWithPermissionsGranted();
    verify(mockedView).showPermissionError();
    verify(mockedView).requestReadPermission();
}

这种方法安全吗?它不应该产生内存泄漏吗?这种方法与MVP体系结构如何配合?演示者的全部要点是让您的业务逻辑代码基于纯java或kotlin,并且独立于任何android框架组件,以便可以轻松地进行单元测试。这不应该是公认的答案。这就是这个解决方案的作用。演示者依赖于视图与自身之间的契约,与任何其他框架都没有依赖关系。你们知道,模仿它来做测试是很简单的。@mromer实际上是在编写代码。您将看到演示者具有活动的导入语句。
Contract.View mockedView;
@Test
public void requestAlbumListWithoutPermissions() {
    when(mockedView.areReadPermissionGranted()).thenReturn(false);
    presenter.doSomethingWithPermissionsGranted();
    verify(mockedView).showPermissionError();
    verify(mockedView).requestReadPermission();
}