OnActivityResult 메서드는 더 이상 사용되지 않습니다. 대안은 무엇입니까?
에 그것을 했습니다.onActivityResult사용되지 않습니다.그것을 처리하기 위해 우리는 무엇을 해야 합니까?
그것을 위해 도입된 대안이 있습니까?
기본 교육은 developer.android.com 에서 받을 수 있습니다.
다음은 기존 코드를 새 코드로 변환하는 방법의 예입니다.
기존 방식:
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
startActivityForResult(intent, 123);
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == 123) {
doSomeOperations();
}
}
새로운 방법(Java):
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
someActivityResultLauncher.launch(intent);
}
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
doSomeOperations();
}
}
});
새로운 방법(Kotlin):
fun openSomeActivityForResult() {
val intent = Intent(this, SomeActivity::class.java)
resultLauncher.launch(intent)
}
var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
doSomeOperations()
}
}
편집. 더 나은 방법은 더 일반화하여 재사용할 수 있도록 하는 것입니다.아래의 스니펫은 제 프로젝트 중 하나에 사용되지만, 잘 테스트되지 않았고 모든 사례를 다루지 못할 수도 있습니다.
Better Activity Result.java
import android.content.Intent;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCaller;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class BetterActivityResult<Input, Result> {
/**
* Register activity result using a {@link ActivityResultContract} and an in-place activity result callback like
* the default approach. You can still customise callback using {@link #launch(Object, OnActivityResult)}.
*/
@NonNull
public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract,
@Nullable OnActivityResult<Result> onActivityResult) {
return new BetterActivityResult<>(caller, contract, onActivityResult);
}
/**
* Same as {@link #registerForActivityResult(ActivityResultCaller, ActivityResultContract, OnActivityResult)} except
* the last argument is set to {@code null}.
*/
@NonNull
public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract) {
return registerForActivityResult(caller, contract, null);
}
/**
* Specialised method for launching new activities.
*/
@NonNull
public static BetterActivityResult<Intent, ActivityResult> registerActivityForResult(
@NonNull ActivityResultCaller caller) {
return registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());
}
/**
* Callback interface
*/
public interface OnActivityResult<O> {
/**
* Called after receiving a result from the target activity
*/
void onActivityResult(O result);
}
private final ActivityResultLauncher<Input> launcher;
@Nullable
private OnActivityResult<Result> onActivityResult;
private BetterActivityResult(@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract,
@Nullable OnActivityResult<Result> onActivityResult) {
this.onActivityResult = onActivityResult;
this.launcher = caller.registerForActivityResult(contract, this::callOnActivityResult);
}
public void setOnActivityResult(@Nullable OnActivityResult<Result> onActivityResult) {
this.onActivityResult = onActivityResult;
}
/**
* Launch activity, same as {@link ActivityResultLauncher#launch(Object)} except that it allows a callback
* executed after receiving a result from the target activity.
*/
public void launch(Input input, @Nullable OnActivityResult<Result> onActivityResult) {
if (onActivityResult != null) {
this.onActivityResult = onActivityResult;
}
launcher.launch(input);
}
/**
* Same as {@link #launch(Object, OnActivityResult)} with last parameter set to {@code null}.
*/
public void launch(Input input) {
launch(input, this.onActivityResult);
}
private void callOnActivityResult(Result result) {
if (onActivityResult != null) onActivityResult.onActivityResult(result);
}
}
위의 접근 방식을 사용하더라도 활동 또는 조각 첨부 파일을 시작하기 전이나 시작하는 동안 등록해야 합니다.정의된 후에는 활동 또는 조각 내에서 재사용할 수 있습니다.예를 들어, 대부분의 활동에서 새로운 활동을 시작해야 하는 경우 다음을 정의할 수 있습니다.BaseActivity그리고 새로운 것을 등록합니다.BetterActivityResult다음과 같이:
기본 활동.java
public class BaseActivity extends AppCompatActivity {
protected final BetterActivityResult<Intent, ActivityResult> activityLauncher = BetterActivityResult.registerActivityForResult(this);
}
그런 다음 다음과 같은 하위 활동에서 활동을 시작할 수 있습니다.
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
activityLauncher.launch(intent, result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
doSomeOperations();
}
})
}
할 수 에,백 설 기 있 때 문 기Intent모든 활동에 재사용할 수 있습니다.
마찬가지로, 다른 두 개의 생성자를 사용하여 다른 활동 계약을 사용할 수도 있습니다.
지부터금.startActivityForResult()는 더 이상 사용되지 않으므로 해당 방법 대신 새 방법을 사용하십시오.
코틀린 예제
fun openActivityForResult() {
startForResult.launch(Intent(this, AnotherActivity::class.java))
}
val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// Handle the Intent
//do stuff here
}
}
사용되지 않는 방법을 교체하는 동안 4가지 간단한 단계를 수행할 수 있습니다.startActivityForResult(...).
된 메서드
onActivityResult(..)-ActivityResultLauncher<Intent> activityResultLaunch = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == 123) { // ToDo : Do your stuff... } else if(result.getResultCode() == 321) { // ToDo : Do your stuff... } } });
여러 사용자 지정 요청의 경우 다음과 같이 조건을 추가합니다.
if (result.getResultCode() == 123) {
..
} else if(result.getResultCode() == 131){
..
} // so on..
가져오기:
import androidx.activity.result.ActivityResult; import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts;startActivityForResult(목적, 123) 대신 다음을 사용합니다.
Intent intent = new Intent(this, SampleActivity.class); activityResultLaunch.launch(intent);SampleActivity.java 클래스에서는 소스 활동으로 되돌아가는 동안 코드는 다음과 같이 동일하게 유지됩니다.
Intent intent = new Intent(); setResult(123, intent); finish();
해피 코딩! :)
Java 8에서는 다음과 같이 작성할 수 있습니다.
ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
Intent data = result.getData();
// ...
}
}
);
Intent intent = new Intent( ... );
startActivityForResult.launch(intent);
KOTLIN에서 코드를 변경했습니다.
startActivityForResult(intent, Constants.MY_CODE_REQUEST)
그리고.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
Constants.MY_CODE_REQUEST -> {
...
}
로.
registerForActivityResult(StartActivityForResult()) { result ->
onActivityResult(Constants.MY_CODE_REQUEST, result)
}.launch(intent)
그리고.
private fun onActivityResult(requestCode: Int, result: ActivityResult) {
if(result.resultCode == Activity.RESULT_OK) {
val intent = result.data
when (requestCode) {
Constants.MY_CODE_REQUEST -> {
...
당신에게 효과가 있기를 바랍니다. :D
에 둘 의 fragment가 requestCode그리고 만약 당신이 그것들에 의해 복수의 결과들을 다루는 방법을 확신하지 못한다면.requestCodes, 당신은 그것을 이해할 필요가 있습니다.requestCode새로운 접근법에서는 쓸모가 없습니다.
나는 당신이 이렇게 코딩하는 오래된 방식을 상상합니다.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_CODE) {
when (requestCode) {
REQUEST_TAKE_PHOTO -> {
// handle photo from camera
}
REQUEST_PICK_IMAGE_FROM_GALLERY -> {
// handle image from gallery
}
}
}
}
를 별도의 .ActivityResultContract:
val takePhotoForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// handle photo from camera
}
}
val pickImageFromGalleryForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// handle image from gallery
}
}
그런 다음 다음 다음과 같은 활동/의도를 시작해야 합니다.
private fun startTakePhotoActivity() {
takePhotoForResult.launch(Intent(requireActivity(), TakePhotoActivity::class.java))
}
private fun pickImageFromGallery() {
val pickIntent = Intent(Intent.ACTION_PICK)
pickIntent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*"
)
pickImageFromGalleryForResult.launch(pickIntent)
}
이렇게 함으로써, 당신은 수백 명의 사람들을 제거할 수 있습니다.const val REQUEST_값을 입력합니다.
onActivityResult,startActivityForResult,requestPermissions,그리고.onRequestPermissionsResult에 대해 더 이상 사용되지 않습니다.androidx.fragment1.3.0-alpha04에 없는android.app.Activity.
대신 와 함께 사용할 수 있습니다.
참조: Kotlin - 갤러리에서 이미지 선택
내가 지금까지 찾은 가장 단순한 알러너티브
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.id.activity_main)
var ivPhoto = findViewById<ImageView>(R.id.ivPhoto)
var btnChoosePhoto = findViewById<Button>(R.id.btnChoosePhoto)
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
ivPhoto.setImageURI(uri) // Handle the returned Uri
}
btnChoose.setOnClickListener {
getContent.launch("image/*")
}
}
여기 새로운 방법을 설명합니다.
private val scan =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result: ActivityResult ->
if (result.resultCode == AppCompatActivity.RESULT_OK && result.data != null) {
var selected_hub = result!!.data!!.getParcelableExtra<ExtendedBluetoothDevice>(Utils.EXTRA_DEVICE)
Log.d(TAG,"RECONNECT PROCESS "+selected_hub!!.name)
reconnect(selected_hub!!)
}
}
활동 또는 단편에서 이를 호출합니다.
private fun callScan() {
val intent = Intent(requireActivity(), ScanningMeshDevices::class.java)
scan.launch(intent)
}
제 솔루션은 다음과 같습니다.
우리 프로젝트에서는 20회 이상의 startActivityForResult(및 ActivityResult)가 발생했습니다.
우리는 코드를 가능한 한 적게 변경하고(그리고 요청 코드를 계속 사용하고) 향후 사용을 위한 우아한 솔루션을 도입하기를 원했습니다.
많은 개발자들이 BaseActivity 개념을 사용하고 있기 때문에 이 개념을 활용하는 것은 어떨까요?
기본 활동은 다음과 같습니다.
abstract class BaseActivity : AppCompatActivity()
{
private var requestCode: Int = -1
private var resultHandler: ActivityResultLauncher<Intent>? = null
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
registerForActivityResult()
}
private fun registerForActivityResult()
{
if (shouldRegisterForActivityResult())
{
resultHandler = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
onActivityResult(result.data, requestCode, result.resultCode)
this.requestCode = -1
}
}
}
fun startActivityForResult(requestCode: Int, intent: Intent)
{
this.requestCode = requestCode
resultHandler?.launch(intent)
}
protected open fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
{
// For sub activities
}
protected open fun shouldRegisterForActivityResult(): Boolean
{
// Sub activities that need the onActivityResult "mechanism", should override this and return true
return false
}
}
다음은 하위 활동입니다.
class SubActivity : BaseActivity()
{
companion object
{
private const val SOME_REQUEST_CODE = 300
}
private fun testActivityResult()
{
val intent = Intent(this, OtherActivity::class.java)
startActivityForResult(SOME_REQUEST_CODE, intent)
}
override fun shouldRegisterForActivityResult(): Boolean
{
return true
}
override fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
{
if (requestCode == SOME_REQUEST_CODE)
{
// Yes!
}
}
}
누군가에게 도움이 되길 바랍니다.
제 목표는 현재의 구현을 재사용하는 것이었습니다.startActivityForResult최소 코드 변경이 있는 메서드입니다.이를 위해 onActivityResultFromLauncher 메서드로 래퍼 클래스와 인터페이스를 만들었습니다.
interface ActivityResultLauncherWrapper {
fun launchIntentForResult(activity: FragmentActivity, intent: Intent, requestCode: Int, callBack: OnActivityResultListener)
fun unregister()
interface OnActivityResultListener {
fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?)
}
}
class ActivityResultLauncherWrapperImpl : ActivityResultLauncherWrapper {
private var weakLauncher: WeakReference<ActivityResultLauncher<Intent>>? = null
override fun launchIntentForResult(
activity: FragmentActivity,
intent: Intent,
requestCode: Int,
callBack: ActivityResultLauncherWrapper.OnActivityResultListener
) {
weakLauncher = WeakReference(
activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
callBack.onActivityResultFromLauncher(requestCode, result.resultCode, result.data)
}
)
weakLauncher?.get()?.launch(intent)
}
override fun unregister() {
weakLauncher?.get()?.unregister()
}
}
나는 프로젝트에서 Dague를 사용하고 있으며 필요한 곳에 포장지를 주입했습니다.
@Inject
lateinit var activityResultLauncher: ActivityResultLauncherWrapper
그러나 래퍼는 직접 인스턴스화할 수도 있습니다.
val activityResultLauncher = ActivityResultLauncherWrapper()
그러면 당신은 그것을 바꿔야 합니다.startActivityForResult이 있는 방법.launchIntentForResult다음은 fragment에서 호출되는 예제입니다.
activityResultLauncher.launchIntentForResult(
requireActivity(),
intent,
REQUEST_CODE_CONSTANT,
object: ActivityResultLauncherWrapper.OnActivityResultListener {
override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {
/*do something*/
}
}
)
익명 개체로 결과를 받을 수 있습니다.사용할 수 있습니다.OnActivityResultListener인터페이스를 구현하고 현재 구현을 다음과 같이 리팩터링하는 경우 fragment 또는 fragment Activity:
class MyFragment : Fragment(), OnActivityResultListener {
...
override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {/*do somthing*/}
...
}
아시다시피, Kotlin 클래스 Activity Result LauncherWrapper는 Java 코드에서도 사용할 수 있습니다.제 프로젝트에도 자바 수업이 있습니다.프래그먼트에 콜백 인터페이스를 구현하는 예가 있습니다.
public class MyFragment extends Fragment implements OnActivityResultListener {
...
@Inject
ActivityResultLauncherWrapper activityResultLauncher;
//ActivityResultLauncherWrapper activityResultLauncher = new ActivityResultLauncherWrapper()
...
public void launnchActivity(@NotNull Intent intent) {
activityResultLauncher.launchIntentForResult(requireActivity(), intent, REQUEST_CODE_CONSTANT, this);
}
...
@Override
public void onActivityResultFromLauncher(int requestCode, int resultCode, Intent data) {/*do somthing*/}
...
}
이것이 당신의 사례에 대한 솔루션을 구축하는 데 도움이 되기를 바랍니다.
Koltin에 대해 확장 함수를 사용할 수 있습니다.예:
//random utils file
fun Fragment.buildGetContentRequest(function: (Uri) -> Unit): ActivityResultLauncher<String> {
return this.registerForActivityResult(ActivityResultContracts.GetContent()) {
function(it)
}
}
fun Fragment.buildTakePhotoRequest(function: (Boolean) -> Unit): ActivityResultLauncher<Uri> {
return this.registerForActivityResult(ActivityResultContracts.TakePicture()) {
function(it)
}
}
fun Fragment.buildSelectMultipleContentRequest(function: (MutableList<Uri>?) -> Unit): ActivityResultLauncher<String> {
return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) {
function(it)
}
}
그리고 당신의 파편 속에 이런 것이 있습니다.
//your actual fragment logic
class YourFragment : Fragment() {
//we can assign our request in init process
private val mRequestSelectFiles = buildSelectMultipleContentRequest {
onFilesSelected(it)
}
fun onSelectFiles() {
val mime = "*/*"
mRequestSelectFiles.launch(mime)
}
fun onFilesSelected(list: MutableList<Uri>?) {
//your logic
}
}
다음과 같이 여러 requestCodes를 교체했습니다(이 코드를 활동에 입력).
ActivityResultLauncher<Intent> launchCameraActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
Bitmap photoBitmap;
if(data != null && data.getExtras() != null){
photoBitmap = (Bitmap) data.getExtras().get("data");
if (photoBitmap != null) {
dataModel.setPhoto(ImageUtil.convert(photoBitmap));
imageTaken.setVisibility(View.VISIBLE);
imageTaken.setImageBitmap(photoBitmap);
}
}
}
}
});
ActivityResultLauncher<Intent> launchCameraAndGalleryActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
Uri imageUri;
if (data != null) {
imageUri = data.getData();
InputStream imageStream;
try {
imageStream = getContentResolver().openInputStream(imageUri);
Bitmap photoBitmap = BitmapFactory.decodeStream(imageStream);
dataModel.setOtherImage(ImageUtil.convert(photoBitmap));
documentImageTaken.setVisibility(View.VISIBLE);
documentImageTaken.setImageBitmap(photoBitmap);
}catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
});
다음과 같은 활동을 시작합니다.
Intent photoIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
launchCameraAndGalleryActivity.launch(photoIntent );
Intent galleryIntent= new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
launchCameraActivity.launch(galleryIntent);
저는 코틀린의 단편에서 그것을 올바르게 수행하는 방법을 생각해냈습니다. 이미지를 캡처하고 반환된 비트맵을 처리하기 위해서요.그것은 다른 경우에도 거의 같습니다.
먼저, 활동 결과를 들으려면 fragment를 등록해야 합니다.fragment를 시작하기 전에 이 작업을 수행해야 합니다. 즉, onCreate 함수 내에서 시작하는 대신 멤버 변수를 만듭니다.
class DummyFragment : Fragment() {
//registering fragment for camera listener
private val takePhoto = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
val imageBitmap = it.data?.extras?.get("data") as Bitmap
// do your thing with the obtained bitmap
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
그런 다음, 평소처럼 카메라 의도를 호출합니다.그리고 위에서 만든 변수를 사용하여 의도를 시작합니다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
someRandomButton.setOnClickListener {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
takePhoto.launch(takePictureIntent)
}
}
저의 경우 Google Sign In을 사용하지 않고 바로 다음 활동으로 이동하려는 의도를 사용하려고 했습니다.
나에게 효과가 있었던 것:
Inside OnCreate set the onClickListener for the sign-in button :
btnSignIn.setOnClickListener {
signIn()
}
private fun signIn() {
val intent = client.signInIntent
mainActivityResultLauncher.launch(intent)
}
갈, 위의코서다활가음의쓰려있만도었, 는써했다니습야저지고드를에고동에▁i▁in▁라고 써야 했습니다.client.signInIntent
var mainActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
if(result.resultCode == Activity.RESULT_OK){
val data = result.data
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// Google Sign In was successful, authenticate with Firebase
val account = task.getResult(ApiException::class.java)!!
Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
firebaseAuthWithGoogle(account.idToken!!)
} catch (e: ApiException) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e)
}
}
}
는 것 같습니다.onActivityResult슈퍼 클래스에서는 더 이상 사용되지 않지만 당신은 슈퍼 클래스 이름을 언급하지 않았습니다.compileSdkVersion여기 당신의 질문에.
Java 및 Kotlin에서 모든 클래스 또는 메서드는 단순히 다음을 추가하여 사용되지 않는 것으로 표시할 수 있습니다.@Deprecated슈퍼 클래스를 확인하기 위해 잘못된 클래스를 확장할 수 있습니다.
클래스가 더 이상 사용되지 않을 경우 클래스의 모든 메서드도 더 이상 사용되지 않습니다.
방법을 하지 않는 하고 를 누릅니다.Ctrl+QAndroid 스튜디오에서 방법 설명서를 보려면 해결책이 있어야 합니다.
내 프로젝트에서 다음을 사용합니다.androidx API 29 29는compileSdkVersion 및 되지 않습니다.
class BetterActivityResult<Input, Result> private constructor(
caller : ActivityResultCaller,
contract : ActivityResultContract<Input, Result>,
var onActivityResult : ((Result) -> Unit)?,
) {
private val launcher : ActivityResultLauncher<Input> =
caller.registerForActivityResult(contract) { onActivityResult?.invoke(it) }
/**
* Launch activity, same as [ActivityResultLauncher.launch] except that it
* allows a callback
* executed after receiving a result from the target activity.
*/
/**
* Same as [.launch] with last parameter set to `null`.
*/
@JvmOverloads
fun launch(
input : Input,
onActivityResult : ((Result) -> Unit)? = this.onActivityResult,
) {
this.onActivityResult = onActivityResult
launcher.launch(input)
}
companion object {
/**
* Register activity result using a [ActivityResultContract] and an in-place
* activity result callback like
* the default approach. You can still customise callback using [.launch].
*/
fun <Input, Result> registerForActivityResult(
caller : ActivityResultCaller,
contract : ActivityResultContract<Input, Result>,
onActivityResult : ((Result) -> Unit)?,
) : BetterActivityResult<Input, Result> {
return BetterActivityResult(caller, contract, onActivityResult)
}
/**
* Same as [.registerForActivityResult] except
* the last argument is set to `null`.
*/
fun <Input, Result> registerForActivityResult(
caller : ActivityResultCaller,
contract : ActivityResultContract<Input, Result>,
) : BetterActivityResult<Input, Result> {
return registerForActivityResult(caller, contract, null)
}
/**
* Specialised method for launching new activities.
*/
fun registerActivityForResult(
caller : ActivityResultCaller,
) : BetterActivityResult<Intent, ActivityResult> {
return registerForActivityResult(caller, StartActivityForResult())
}
}
}
이를 위한 다른 방법은 3단계입니다. (StartActivityForResult(0 및 onActivityResult())
- 를 식에변수 만다니듭 .
var resultLauncher:ActivityResultLauncher<Intent> - 이 기본 형식으로 resultLauncher를 초기화하는 개인 함수를 만듭니다.
resultLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult()){result ->
// copy paste the code from the onActivityResult replacing resultcode to result.resultCode
if(result.resultcode==Activity.Result_OK){
val data=result.data // this data variable is of type intent and you can use it
}else{
//code if you do not get the data
}
}
- 이동로으로 .
startActivityForResult()그리고 그것을 라인으로 대체합니다.resultLauncher.launch(intent)
dor506 답변은 제가 대부분의 프로젝트에서 BaseActivity를 사용하기 때문에 모든 활동보다 단일 파일에서 코드를 변경하는 것이 더 쉽습니다.저는 이 코드의 자바 버전을 작성했습니다.
기본 활동 코드:
private int requestCode = -1;
private ActivityResultLauncher<Intent> resultHandler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
registerForActivityResult();
}
private final void registerForActivityResult() {
if (shouldRegisterForActivityResult()) {
this.resultHandler = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback() {
public void onActivityResult(Object var1) {
this.onActivityResult((ActivityResult)var1);
}
public final void onActivityResult(ActivityResult result) {
Intrinsics.checkNotNullExpressionValue(result, "result");
AppActivityClass.onActivityResult(result.getData(), AppActivityClass.this.requestCode, result.getResultCode());
AppActivityClass.this.requestCode = -1;
}
});
}
}
public final void startActivityForResult(int requestCode, Intent intent) {
this.requestCode = requestCode;
if (resultHandler != null) {
resultHandler.launch(intent);
}
}
protected static void onActivityResult(Intent intent, int requestCode, int resultCode) {
}
protected Boolean shouldRegisterForActivityResult() {
return false;
}
이제 모든 활동에서 다음과 같은 코드를 사용합니다.
@Override
protected Boolean shouldRegisterForActivityResult() {
return true; // this will override the baseactivity method and we can use onactivityresult
}
private void someMethod(){
Intent i = new Intent(mContext,SomeOtherClassActivity.class);
startActivityForResult(101,i);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 101) {
if (resultCode == RESULT_OK) {
//revert from called class
}
}
}
찾은 공유 솔루션
이 합니다.registerForActivityResult 유의개반환다니 유형의 개체가 됩니다.ActivityResultLauncher<Intent!> 것처럼.
private val getResult =
registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
val value = it.data?.getStringExtra("input")
}
}
이제 결과를 위한 활동을 시작하고 싶은 곳이면 어디든 사용할 수 있습니다.getResult.launch(intent)
아래 코드는 코틀린 fragment에서 작동하여 블루투스 권한을 확인합니다.
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
bluetoothAdapter.enable()
Toast.makeText(context, "Permission Granted: ", Toast.LENGTH_SHORT).show()
dynamicButton()
}
else{Toast.makeText(context, "You have to enable bluetooth to use this app.", Toast.LENGTH_SHORT).show()}
}.launch(intent)
startActivityForResult and onActivityResult는 Android 10 API 30에서 더 이상 사용되지 않습니다. 이제 registerForActivityResult를 사용하여 결과를 얻을 수 있는 새로운 방법이 있습니다.
resultContract =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val country = result.data?.getParcelableExtra<Country>("Country")
showLiveDemoDialogue(country)
}
}
그리고 활동을 시작합니다.
val intent = Intent(this, CountriesListActivity::class.java)
resultContract.launch(intent)
하지만 시작을 부르기 전에 등록하고 원하는 곳 어디든 시작해야 합니다.그렇지 않으면, 당신은 이 예외를 얻게 될 것입니다.
attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
}
}
});
이렇게 기본 활동을 구현하면 startActivityForResult를 기존 방식으로 계속 사용할 수 있습니다.유일한 제한 사항은 활동 내에서 결과를 설정하려면 setResult(결과, 의도)를 사용해야 한다는 것입니다.핵심은 결과가 요청 코드를 결과 소비자에게 전달하도록 하는 것입니다.
public class MyBaseActivity extends AppCompatActivity {
private ActivityResultLauncher<Intent> activityLauncher;
protected static String ACTIVITY_REQUEST_CODE = "my.activity.request.code";
protected _originalIntent;
public void launchActivityForResult(Intent intent, int requestCode){
intent.putExtra(UGM_ACTIVITY_REQUEST_CODE, requestCode);
activityLauncher.launch(intent);
}
//
//In order to be signature compatible for the rest of derived activities,
//we will override the deprecated method with our own implementation!
//
@SuppressWarnings( "deprecation" )
public void startActivityForResult(Intent intent, int requestCode){
launchActivityForResult(intent, requestCode);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
_originalIntent = getIntent();
//set the default result
setResult(Activity.RESULT_OK, _originalIntent);
activityLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
Intent intent = result.getData();
int requestCode = intent.getIntExtra(ACTIVITY_REQUEST_CODE, -1);
MyBaseActivity.this.onActivityResult(requestCode, result.getResultCode(), intent);
}
});
}
}
위의 답변과 함께, 저는 이전 방식의 startActivityForResult()와 호환되는 접근 방식을 가지고 있습니다. 이전 코드 구조를 변경하지 않고 requestCode를 계속 사용합니다.
활동 Launcher.
public class ActivityLauncher {
private final ActivityResultLauncher<Intent> launcher;
private ActivityResultCallback<ActivityResult> activityResultCallback;
private ActivityLauncher(@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Intent, ActivityResult> contract,
@Nullable ActivityResultCallback<ActivityResult> activityResultCallback) {
this.activityResultCallback = activityResultCallback;
this.launcher = caller.registerForActivityResult(contract, this::onActivityResult);
}
public static ActivityLauncher registerActivityForResult(
@NonNull ActivityResultCaller caller) {
return new ActivityLauncher(caller, new ActivityResultContracts.StartActivityForResult(), null);
}
public void launch(Intent intent, @Nullable ActivityResultCallback<ActivityResult> activityResultCallback) {
if (activityResultCallback != null) {
this.activityResultCallback = activityResultCallback;
}
launcher.launch(intent);
}
private void onActivityResult(ActivityResult result) {
if (activityResultCallback != null) activityResultCallback.onActivityResult(result);
}
public interface OnActivityResult {
void onActivityResultCallback(int requestCode, int resultCode, Intent data);
}
}
BaseActivity.java의 코드
private final ActivityLauncher activityLauncher = ActivityLauncher.registerActivityForResult(this);
public void startActivityForResult(Intent intent, int requestCode, ActivityLauncher.OnActivityResult onActivityResult) {
activityLauncher.launch(intent, result -> onActivityResult.onActivityResultCallback(requestCode, result.getResultCode(), result.getData()));
}
그리고 마지막으로 기본 활동을 확장하는 각 활동에서 활동 시작자를 구현합니다.OnActivityResult에서 재정의 함수 "onActivityResult"의 이름을 "onActivityResultCallback"으로 변경합니다.또한 super.on Activity Result()를 제거해야 합니다.
사용 방법: 결과에 대한 ActivityForResult(entent, requestCode, this)를 시작합니다.
결과에 대한 활동 시작 및 활동 및 요청의 다중 사용 권한에 대한 활동 결과 레지스터의 간단한 예(Kotlin)
활동 결과에 대한 활동 요청
registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
//...
}
}
활동 결과 확인
활동에서 권한을 요청하시겠습니까?
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) {
//it: Map<String, Boolean>
}
조각에서?
동일한 방법을 사용하지만 이러한 구현을 다음에 배치해야 합니다.initialization, onAttach(), or onCreate()
SMS 동의 API를 사용하는 경우 다음 코드(Kotlin)를 사용합니다.
resultLauncher.launch( consentIntent
)
var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
// val data: Intent? = result.data
val message = result.data?.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
getOtpFromMessage(message)
}
}
나는 그것을 매우 간단하게 만들기 위해 코틀린 확장을 사용하고 있습니다.Extensions.kt 파일에 아래 확장 기능을 추가합니다.
fun AppCompatActivity.startForResult(intent: Intent,
onResult: (resultCode: Int, data: Intent?) -> Unit
) {
this.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {result ->
onResult(result.resultCode, result.data)
}.launch(intent)
}
이제 AppCompativity를 상속하는 모든 활동 내에서 아래와 같은 간단한 코드를 사용할 수 있습니다.
val i = Intent(this, TargetActivity::class.java)
startForResult(i) { resultCode, data ->
//put your code here like:
if (resultCode == RESULT_OK) {
//your code here...
}
}
}
위의 업데이트 구현으로 인해 java.lang이라는 예외가 발생할 수 있습니다.잘못된 상태 예외: 현재 상태가 다시 시작되는 동안 LifecycleOwner xxxxxx가 등록을 시도하고 있습니다. 라이프사이클 소유자는 시작하기 전에 레지스터를 호출해야 합니다.
따라서 registerForActivityResult는 Create에서 사전에 호출되어야 합니다.여기에 대안적인 해결책이 있습니다.
Extensions.kt 파일에 아래 확장 기능을 추가합니다.
fun AppCompatActivity.registerForResult(onResult: (resultCode: Int, data: Intent?) -> Unit):
ActivityResultLauncher<Intent> {
return this.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
onResult(result.resultCode, result.data)
}
}
이제 AppCompativity를 상속하는 모든 활동 내에서 아래와 같은 간단한 코드를 사용할 수 있습니다.
- 결과가 필요한 모든 작업에 대한 클래스 멤버 변수 정의
private val myActionResult = registerForResult { resultCode, data ->
//put your code here like:
if (resultCode == RESULT_OK) {
//your code here...
}
}
}
- 작업 시작
val i = Intent(this, TargetActivity::class.java)
myActionResult.launch(i)
muntashirakon 및 abhijeet에 의한 답변에 추가하여 다음과 같은 목적으로 값을 전달하여 이전 형식처럼 작동하도록 새 형식을 수정할 수 있습니다.
// calling class
....
val i = Intent(this@GEBShopActivity, BarcodeScannerActivity::class.java)
when(loadedFragment){
is ShopHomeFragment -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_LIST_MAINT) }
is ShopListFragment -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_LIST_MAINT) }
is ShopItemMaintFragment -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_ITEM_MAINT) }
is ShopPriceFragment -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_PRICE_CAPTURE) }
is ShopCompareFragment -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_PRICE_CAPTURE) }
}
shopFragmentLauncher.launch(i)
....
// called class
....
val resultIntent = Intent()
val bundle = Bundle()
bundle.putStringArrayList("scanned_barcodes", scanned_barcodes)
bundle.putInt("scan_count", scan_count)
resultIntent.putExtras(bundle)
resultIntent.putExtra("myapp.result.code", intent.getIntExtra("myapp.result.code", 0))
setResult(Activity.RESULT_OK, resultIntent)
....
이렇게 하면 원래 호출된 결과 코드를 추가하기 위해 한 줄만 추가해도 클래스를 동일하게 호출할 수 있습니다.또한 재사용 가능한 시작 프로그램 인스턴스를 만들 수 있습니다.
2023년 코틀린의 답은 다음과 같습니다.Uri.
이미지 라이브러리에서 이미지를 가져오고 처리하는 방법을 찾는 사용자를 위한 예제Urisuper.onActivityResult(requestCode, resultCode, data)삭제/사용되지 않음
저는 구글 문서에서 이 답을 얻었고 그것은 작동합니다.
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
// Handle Uri
}
참고로 당신은 이것을 사용하여 어떤 것이든 얻을 수 있어야 합니다.Uri이미지뿐만이 아닙니다.여기서는 아래에 사용됩니다.
import androidx.activity.result.contract.ActivityResultContracts
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
// ...
binding.selectPhotoButton.setOnClickListener {
selectPhoto()
}
}
fun selectPhoto() {
getContent.launch("image/*") // *** What Google said to do to launch the image library ***
}
// *** This is what Google posted to handle the Uri ***
val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
// Handle the returned Uri
binding.myImageView.setImageURI(uri)
}
}
언급URL : https://stackoverflow.com/questions/62671106/onactivityresult-method-is-deprecated-what-is-the-alternative
'programing' 카테고리의 다른 글
| 오류: psycopg2라는 모듈이 없습니다.내선 번호 (0) | 2023.06.02 |
|---|---|
| ExpressJS 애플리케이션을 구성하는 방법은 무엇입니까? (0) | 2023.06.02 |
| 이름/값 쌍이 있는 Excel 드롭다운 (0) | 2023.06.02 |
| alias 또는 alias_method를 사용해야 합니까? (0) | 2023.06.02 |
| 고정 위치이지만 용기에 상대적임 (0) | 2023.06.02 |

