마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

ContextCompat.checkSelfPermission 관련 NullPointerException

0 추천
안드로이드 초보입니다. 카메라 버튼을 누르고 권한을 받지않은 경우 권한요청하고 권한 받은 경우 카메라 앱을 실행하는 코드를 작성중인데  로그캣에 따르면 checkPermission에서 NullPointerException가 발생하고있습니다 ㅠ어떻게 해줘야할지요..

 

[코드]

package com.ooh.review

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.ooh.review.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    val REQ_CAMERA = 101
    val REQ_STORAGE = 102
    val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        setView()
    }
    fun setView(){
        binding.buttonCamera.setOnClickListener{
//            if (cameraPermission == PackageManager.PERMISSION_DENIED){
//                Log.d("my tag","권한이 필요하다고")
//            } else {
//
//            }

        }
        binding.buttonGallery.setOnClickListener{
            openGallery()
        }
    }
    fun openGallery(){
        val intent = Intent(Intent.ACTION_PICK)
        intent.type = MediaStore.Images.Media.CONTENT_TYPE
        startActivityForResult(intent, REQ_STORAGE)
    }
}

[에러]

2021-10-16 15:08:10.049 10454-10454/com.ooh.review E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.ooh.review, PID: 10454
    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.ooh.review/com.ooh.review.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.content.Context.checkPermission(java.lang.String, int, int)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3194)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.content.Context.checkPermission(java.lang.String, int, int)' on a null object reference
        at android.content.ContextWrapper.checkPermission(ContextWrapper.java:762)
        at androidx.core.content.ContextCompat.checkSelfPermission(ContextCompat.java:555)
        at com.ooh.review.MainActivity.<init>(MainActivity.kt:18)
        at java.lang.Class.newInstance(Native Method)
        at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
        at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1243)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3182)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
andchobo11 (150 포인트) 님이 2021년 10월 16일 질문

1개의 답변

0 추천
 
채택된 답변

퍼미션 체크하는 위치가 이상해 보입니다. 작성하신 코드는 액티비티가 초기화되기 이전에 퍼미션을 체크하고 있기 때문에 context가 null이 될 수 있습니다. 퍼미션 체크하는 

fun setView(){
        binding.buttonCamera.setOnClickListener{
              if (!hasCameraPermission()) {
                    //request permission
                    return
              }

//            if (cameraPermission == PackageManager.PERMISSION_DENIED){
//                Log.d("my tag","권한이 필요하다고")
//            } else {
//
//            }

        }

        binding.buttonGallery.setOnClickListener{
            if (!hasCameraPermission()) {
                    //request permission
                    return
              } 

            openGallery()
        }
    }
    fun openGallery(){
        val intent = Intent(Intent.ACTION_PICK)
        intent.type = MediaStore.Images.Media.CONTENT_TYPE
        startActivityForResult(intent, REQ_STORAGE)
    }
}

private fun hasCameraPermission(): Boolean {
   return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == Packagemanager.PERMISSION_GRANTED
}

위처럼, 코드를 퍼미션을 사용하기 직전에 호출해 보세요. 그래야 Context가 초기화 된 상태라 null이 되지 않을 것 같습니다.

 

 

spark (226,420 포인트) 님이 2021년 10월 16일 답변
andchobo11님이 2021년 10월 17일 채택됨
안녕하세요 답변 너무 감사드립니다.
cameraPermission 초기화 위치를 onCreate 전에 했었는데 위치를 해당 함수 속으로 바꿨더니 해결되었습니다. 무슨차이가 있는지 모르겠지만 ㅠㅠ 아무튼 감사합니다.
Activity를 보시면 님이 직접 생성할 수가 없습니다. startActvity등을 통해 안드로이드 시스템이 생성하도록 만들어 주어야 합니다. Activity클래스의 onCreate메소드의 소스를 따라가보면

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Restore the Saved State first so that it is available to
        // OnContextAvailableListener instances
        mSavedStateRegistryController.performRestore(savedInstanceState);
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }

public void dispatchOnContextAvailable(@NonNull Context context) {
        mContext = context;  // <--- 여기서 초기화가 됨.
        for (OnContextAvailableListener listener : mListeners) {
            listener.onContextAvailable(context);
        }
}
 

위처럼 onCreate 안에서 mContext가 초기화 되고 있습니다. 따라서 Activity안에서 context에 접근하려면 onCreate에서 super.onCreate가 호출된 뒤에 해야됩니다.
...