如何在ViewModel中授予权限?

时间:2017-06-14 17:10:52

标签: android android-activity permissions android-mvvm

我需要请求联系人的权限,当应用程序启动时我要求,在ViewModel部分我需要调用需要权限的方法。我需要检查权限是否由用户授予然后调用,但是对于检查权限,我需要访问Activity。而在我的ViewModel中,我没有对Activity的引用,也不想拥有,我怎么能克服这个问题呢?

3 个答案:

答案 0 :(得分:1)

您可以创建一个PermissionRequester类,使用LocalBroadcastManager来请求具有自定义意图的权限。您的基本活动会解析此权限请求,并使用PermissionRequester将结果发送回LocalBroadcastManager。然后,您的ViewModel可以使用PermissionRequester.getInstance().requestPermission(permission),而无需与您的活动建立任何关联。这里是PermissionRequester.java的示例代码:

public class PermissionRequester {

    private static PermissionRequester instance;

    public static synchronized PermissionRequester getInstance() {
        instance = instance == null ? new PermissionRequester() : instance;
        return instance;
    }

    private final Map<String, WeakReference<OnResultListener>> pendingListeners = new HashMap<>();

    private PermissionRequester() {
        LocalBroadcastManager.getInstance(MyApplication.getInstance()).registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent != null ? intent.getAction() : "";
                if ("ACTION_PERMISSION_REQUEST_RESPONSE".equals(action)) {
                    callbackListener(intent.getStringExtra("LISTENER"), intent.getIntExtra("RESULT", -1));
                }
            }
        }, new IntentFilter("ACTION_PERMISSION_REQUEST_RESPONSE"));
    }

    public void requestPermission(@NonNull OnResultListener listener, @NonNull String permission) {
        pendingListeners.put(listener.getClass().getName() + listener.hashCode(), new WeakReference<>(listener));

        Intent requestPermissionIntent = new Intent("ACTION_REQUEST_PERMISSION");
        requestPermissionIntent.putExtra("PERMISSION", permission);
        LocalBroadcastManager.getInstance(MyApplication.getInstance().getApplicationContext()).sendBroadcast(requestPermissionIntent);
    }

    private void callbackListener(String listener, int result) {
        WeakReference<OnResultListener> listenerReference = pendingListeners.get(listener);
        OnResultListener onResultListener = listenerReference != null ? listenerReference.get() : null;
        if (onResultListener != null) {
            pendingListeners.remove(listenerReference);
            if (result == 1) {
                onResultListener.onPermissionGranted();
            } else if (result == 0) {
                onResultListener.onPermissionDenied();
            }
        }
    }

    public interface OnResultListener {
        void onPermissionGranted();
        void onPermissionDenied();
    }
}

在基本活动中接收自定义意图的代码类似于在PermissionRequester构造函数中接收结果。但请注意在registerReceiveronResumeunregisterReceiver拨打onPause

答案 1 :(得分:1)

我刚遇到这个问题,我决定使用LiveData代替。

核心概念:

  • ViewModel有一个关于需要提出权限请求的LiveData

  • ViewModel有一个方法(基本上是回调),如果授予了权限,则返回

SomeViewModel.kt

class SomeViewModel : ViewModel() {
    val permissionRequest = MutableLiveData<String>()

    fun onPermissionResult(permission: String, granted: Boolean) {
        TODO("whatever you need to do")
    }
}

FragmentOrActivity.kt

class FragmentOrActivity : FragmentOrActivity() {
    private viewModel: SomeViewModel by lazy {
        ViewModelProviders.of(this).get(SomeViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        ......
        viewModel.permissionRequest.observe(this, Observer { permission -> 
            TODO("ask for permission, and then call viewModel.onPermissionResult aftwewards")
        })
        ......
    }
}

答案 2 :(得分:0)

我做了这样的事情:

创建一个扩展AndroidViewModel的抽象类,该类使您可以访问应用程序上下文:

abstract class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope {

    private val job = Job()

    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main

    override fun onCleared() {
        super.onCleared()
        job.cancel()
    }
}

现在,通过扩展BaseViewModel类来创建视图模型,您将可以访问应用程序上下文

class AdminViewModel(application: Application) : BaseViewModel(application) {
    .....
}

现在,您始终可以访问可以用于访问资源的上下文。