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

startActivityForResult 에러

0 추천
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    static final int getimagesetting=1001;//for request intent
    static Context mContext;
    ImageView image;
    Button get,send,reflash;
    ListView bloblist;
    static listView list;
    static public int list_cnt;
    String temp="";
    static ProgressDialog pd;
    private static final int REQUEST_CAMERA = 1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init() {
        image=(ImageView)findViewById(R.id.image);
        get=(Button) findViewById(R.id.get);
        send=(Button)findViewById(R.id.send);
        reflash=(Button)findViewById(R.id.reflash);
        bloblist=(ListView)findViewById(R.id.bloblist);
        list=new listView(this);
        get.setOnClickListener(this);
        send.setOnClickListener(this);
        reflash.setOnClickListener(this);
        bloblist.setAdapter(list);
        mContext=this;
        list_cnt=0;
        permission_init();
    }

    void permission_init(){
        if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {    //권한 거절
            // Request missing location permission.
            // Check Permissions Now

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    android.Manifest.permission.CAMERA)) {
                // 이전에 권한거절
                // Toast.makeText(this,getString(R.string.limit),Toast.LENGTH_SHORT).show();

            } else {
                ActivityCompat.requestPermissions(
                        this, new String[]{android.Manifest.permission.CAMERA},
                        REQUEST_CAMERA);
            }

        } else {   //권한승인
            //Log.e("onConnected","else");
            // mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

        }

    }


    @Override
    public void onClick(View view) {
        switch(view.getId()){
            case R.id.get:
                addImage();
                break;
            case R.id.send:
                if(temp.length()>0)
                    insert_blob();
                else
                    Toast.makeText(this,"이미지가 없습니다.",Toast.LENGTH_SHORT).show();
                break;
            case R.id.reflash:

                reflash_list();
                break;
        }
    }

    void reflash_list(){
        pd=new ProgressDialog(this);
        pd.setMessage("이미지를 DB에서 가져오는 중입니다. 잠시만 기다리세요.");
        pd.show();
        loadMysql getting=new loadMysql();
        loadMysql.active=true;
        getting.start();
    }

    void addImage(){
        Intent intent=new Intent(getApplicationContext(),SetImageActivity.class);

        startActivityForResult(intent, getimagesetting);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==getimagesetting){  //if image change

            if(resultCode==RESULT_OK){
                Bitmap selPhoto = null;
                selPhoto=(Bitmap) data.getParcelableExtra("bitmap");
                image.setImageBitmap(selPhoto);//썸네일
                BitMapToString(selPhoto);
            }
        }
    }
    /**
     * bitmapstring으로
     * @param bitmap
     * @return
     */
  
 startActivityForResult에  startActivityForResult << 표시가 떠서 해당 줄이 왜 뜨는지 해결하기 위해서는 무엇을 바꿔야 하는지 궁금합니다
Qaunsd (120 포인트) 님이 2021년 10월 9일 질문

1개의 답변

0 추천

requestPermission과 startActivityForResult는 Result API가 추가됨에 따라 deprecated 되었습니다. 따라서 ResultAPI를 이용해 처리하세요.

먼저, 아래와 같이 dependency 를 app 폴더에 있는 build.gradle 에 추가하세요.

androidx.activity:activity:1.3.1

(https://maven.google.com/web/index.html 에서 필요한 구글 라이브러리를 검색하실 수 있습니다.)


Result API를 사용하기 위해서는 두가지를 제공해 주어야 합니다. 첫번째 어떤 Intent 생성과 처리에 대한 부분, 두번째로는 Activity를 띄우기위해 콜백을 등록하는 부분.

첫번째는 아래와 같이 ActivityResultContract 클래스를 구현해 주면 됩니다. 이 부분을 기존의 startActivityForResult 에 넘겨줄Intent를 생성하는 부분과  onActivityResult 콜백 처리부분을 합쳐놓은 것으로 보시면 됩니다.

public abstract class ActivityResultContract<I, O> {
  /* Create an intent that can be used for Activity.startActivityForResult */
   public abstract @NonNull Intent createIntent(@NonNull Context context,
            @SuppressLint("UnknownNullness") I input);

    /** Convert result obtained from {@link Activity#onActivityResult} to O */
    @SuppressLint("UnknownNullness")
    public abstract O parseResult(int resultCode, @Nullable Intent intent);
}

public class GetContent extends ActivityResultContract<String, Uri> {
    ...
}

 

두번째는,  기존처럼 onActivityResult콜백을 사용하지 않기 때문에 콜백을 미리 등로해주어야 합니다. 
중요한 점은, 아래처럼 등록하는 코드를 사용할 때, 멤버변수등으로 처리해서 액티비티나 프레그먼트가 생성시 바로 등록될 수 있도록 해주어야 합니다.

val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
    // Handle the returned Uri
}

 

다음에는  startActivityForResult 호출하는 대신,   
 

getContent.launch("image/*")

처럼 호출하면 됩니다.

 해당 API에서는 많이 사용하는 Intent들은 미리 만들어서 제공하고 있습니다. ActivityResultContrats 나 아래 링크를 보시면 어떤 Contract이 제공되는지 확인하실 수 있습니다.
https://developer.android.com/reference/androidx/activity/result/contract/package-summary

Permission과 이미지를 고르는 Intent들도 이미 제공되고 있습니다.

아래처럼 처리하시면 되는데, 제가 테스트해 본 코드는 코틀린으로 작성되었기 때문에 자바로 변환하시길 바라고, 테스트는 많이 안되었기 때문에 세부적인 처리는 추가하시기 바랍니다.

fun onCreate(saveInstance: Bundle?) {
    super.onCreate(saveinstance)
     ...
    pickImageButon.setOnClickListener {
        if(ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {    //여기는 님의 코드 그대로 사용
            permissionActivityForResult.launch(android.Manifest.permission.CAMERA)
        } else {
            startActivityForImageSelection()
        }
    }
}

private val permissionActivityForResult = registerForActivityResult(ActivityResultContracts.RequestPermission()) { accepted ->
        if (accepted) {
            startActivityForImageSelection()
        }
    }

    private val pickImageActivityForResult = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
        uri?.let {
           previewImage.setImageURI(uri)
        }
    }

   private fun startActivityForImageSelection() {
        pickImageActivityForResult.launch("image/*")
    }

그리고 아마 안드로이드 버전이 올라가면서  File provider라는 걸 제공해야 하는 걸로 기억하는데, 그 부분은 아랫처럼 AndroidManifest.xml에 File provider를 등록하시고, 

<application
 ....

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
    </application>

 

xml 리소스 폴더에 아래와 같이 provider_paths.xml 을 추가해주셔야 할 것 같습니다. 이렇게 해야 이미지를 선택할 때 캐시폴더에 접근하는데 문제가 생기지 않을 듯합니다.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path
        name="cached_files"
        path="." />
    <files-path
        name="images"
        path="." />
</paths>

 

ResultAPI의 개발자 문서는 아래 링크에 있습니다.

https://developer.android.com/training/basics/intents/result

spark (226,420 포인트) 님이 2021년 10월 10일 답변
spark님이 2021년 10월 10일 수정
...