অন্য অ্যাক্টিভিটি শুরু করা, সেটা আপনার অ্যাপের মধ্যেই হোক বা অন্য অ্যাপ থেকে, একমুখী অপারেশন হওয়ার দরকার নেই। আপনি একটি কার্যকলাপ শুরু করতে এবং একটি ফলাফল ফিরে পেতে পারেন. উদাহরণস্বরূপ, আপনার অ্যাপ একটি ক্যামেরা অ্যাপ শুরু করতে পারে এবং ফলস্বরূপ ক্যাপচার করা ফটো গ্রহণ করতে পারে। অথবা আপনি একটি পরিচিতি নির্বাচন করার জন্য ব্যবহারকারীর জন্য পরিচিতি অ্যাপটি শুরু করতে পারেন এবং তারপরে যোগাযোগের বিশদ ফলাফল হিসাবে পেতে পারেন৷
যদিও অন্তর্নিহিত startActivityForResult()
এবং onActivityResult()
APIগুলি সমস্ত API স্তরের Activity
ক্লাসে উপলব্ধ, Google দৃঢ়ভাবে AndroidX Activity
এবং Fragment
ক্লাসে চালু করা Activity Result APIগুলি ব্যবহার করার সুপারিশ করে৷
অ্যাক্টিভিটি রেজাল্ট এপিআইগুলি ফলাফলের জন্য নিবন্ধন করার জন্য উপাদানগুলি প্রদান করে, ফলাফলটি উৎপন্ন করে এমন ক্রিয়াকলাপ চালু করে এবং সিস্টেম দ্বারা এটি পাঠানোর পরে ফলাফলটি পরিচালনা করে।
একটি কার্যকলাপ ফলাফলের জন্য একটি কলব্যাক নিবন্ধন করুন
একটি ফলাফলের জন্য একটি কার্যকলাপ শুরু করার সময়, এটি সম্ভব-এবং, ক্যামেরা ব্যবহারের মতো মেমরি-নিবিড় ক্রিয়াকলাপের ক্ষেত্রে, প্রায় নিশ্চিত- যে কম মেমরির কারণে আপনার প্রক্রিয়া এবং আপনার কার্যকলাপ ধ্বংস হয়ে যাবে।
এই কারণে, অ্যাক্টিভিটি রেজাল্ট এপিআইগুলি আপনার কোডের যে জায়গা থেকে আপনি অন্য অ্যাক্টিভিটি চালু করেন সেখান থেকে ফলাফল কলব্যাককে ডিকুপ করে। যেহেতু আপনার প্রক্রিয়া এবং কার্যকলাপ পুনরায় তৈরি করা হলে ফলাফল কলব্যাক উপলব্ধ হওয়া প্রয়োজন, প্রতিবার আপনার কার্যকলাপ তৈরি করার সময় কলব্যাকটি নিঃশর্তভাবে নিবন্ধিত হতে হবে, এমনকি যদি অন্য কার্যকলাপ চালু করার যুক্তি শুধুমাত্র ব্যবহারকারীর ইনপুট বা অন্যান্য ব্যবসায়িক যুক্তির উপর ভিত্তি করে ঘটে।
যখন একটি ComponentActivity
বা একটি Fragment
, কার্যকলাপ ফলাফল এপিআই ফলাফল কলব্যাক নিবন্ধনের জন্য একটি registerForActivityResult()
API প্রদান করে। registerForActivityResult()
একটি ActivityResultContract
এবং একটি ActivityResultCallback
নেয় এবং একটি ActivityResultLauncher
ফেরত দেয়, যা আপনি অন্য কার্যকলাপ চালু করতে ব্যবহার করেন।
একটি ActivityResultContract
ফলাফলের আউটপুট প্রকারের সাথে ফলাফল তৈরি করার জন্য প্রয়োজনীয় ইনপুট প্রকারকে সংজ্ঞায়িত করে। এপিআইগুলি একটি ছবি তোলা, অনুমতির অনুরোধ করা ইত্যাদির মতো মৌলিক অভিপ্রায় ক্রিয়াগুলির জন্য ডিফল্ট চুক্তি প্রদান করে৷ আপনি একটি কাস্টম চুক্তিও তৈরি করতে পারেন।
ActivityResultCallback
হল একটি onActivityResult()
পদ্ধতি সহ একটি একক পদ্ধতির ইন্টারফেস যা ActivityResultContract
এ সংজ্ঞায়িত আউটপুট প্রকারের একটি বস্তু নেয়।
কোটলিন
val getContent = registerForActivityResult(GetContent()) { uri: Uri? -> // Handle the returned Uri }
জাভা
// GetContent creates an ActivityResultLauncher<String> to let you pass // in the mime type you want to let the user select ActivityResultLauncher<String> mGetContent = registerForActivityResult(new GetContent(), new ActivityResultCallback<Uri>() { @Override public void onActivityResult(Uri uri) { // Handle the returned Uri } });
আপনার যদি একাধিক অ্যাক্টিভিটি ফলাফল কল থাকে এবং আপনি হয় ভিন্ন চুক্তি ব্যবহার করেন বা আলাদা কলব্যাক চান, আপনি একাধিক ActivityResultLauncher
দৃষ্টান্ত নিবন্ধন করতে registerForActivityResult()
একাধিকবার কল করতে পারেন। আপনার প্রতিটি খণ্ড বা কার্যকলাপের জন্য আপনাকে একই ক্রমে registerForActivityResult()
কল করতে হবে যাতে ইনফ্লাইট ফলাফল সঠিক কলব্যাকে বিতরণ করা হয়।
registerForActivityResult()
আপনার খণ্ড বা কার্যকলাপ তৈরি হওয়ার আগে কল করা নিরাপদ, ফিরে আসা ActivityResultLauncher
দৃষ্টান্তগুলির জন্য সদস্য ভেরিয়েবল ঘোষণা করার সময় এটি সরাসরি ব্যবহার করতে দেয়।
ফলাফলের জন্য একটি কার্যকলাপ চালু করুন
registerForActivityResult()
আপনার কলব্যাক নিবন্ধন করার সময়, এটি অন্য কার্যকলাপ চালু করে না এবং ফলাফলের জন্য অনুরোধটি শুরু করে না। পরিবর্তে, এটি ফিরে আসা ActivityResultLauncher
উদাহরণের দায়িত্ব।
ইনপুট বিদ্যমান থাকলে, লঞ্চারটি ActivityResultContract
এর প্রকারের সাথে মেলে এমন ইনপুট নেয়। কলিং launch()
ফলাফল তৈরির প্রক্রিয়া শুরু করে। যখন ব্যবহারকারী পরবর্তী কার্যকলাপ সম্পন্ন করে এবং ফিরে আসে, তখন ActivityResultCallback
থেকে onActivityResult()
কার্যকর করা হয়, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
val getContent = registerForActivityResult(GetContent()) { uri: Uri? -> // Handle the returned Uri } override fun onCreate(savedInstanceState: Bundle?) { // ... val selectButton = findViewById<Button>(R.id.select_button) selectButton.setOnClickListener { // Pass in the mime type you want to let the user select // as the input getContent.launch("image/*") } }
জাভা
ActivityResultLauncher<String> mGetContent = registerForActivityResult(new GetContent(), new ActivityResultCallback<Uri>() { @Override public void onActivityResult(Uri uri) { // Handle the returned Uri } }); @Override public void onCreate(@Nullable Bundle savedInstanceState) { // ... Button selectButton = findViewById(R.id.select_button); selectButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // Pass in the mime type you want to let the user select // as the input mGetContent.launch("image/*"); } }); }
launch()
এর একটি ওভারলোডেড সংস্করণ আপনাকে ইনপুট ছাড়াও একটি ActivityOptionsCompat
পাস করতে দেয়।
একটি পৃথক ক্লাসে একটি কার্যকলাপের ফলাফল পান
ComponentActivity
এবং Fragment
ক্লাসগুলি আপনাকে registerForActivityResult()
API ব্যবহার করতে দেওয়ার জন্য ActivityResultCaller
ইন্টারফেস প্রয়োগ করে, আপনি একটি পৃথক ক্লাসে কার্যকলাপের ফলাফলও পেতে পারেন যা ActivityResultRegistry
সরাসরি ব্যবহার করে ActivityResultCaller
প্রয়োগ করে না।
উদাহরণস্বরূপ, আপনি একটি LifecycleObserver
বাস্তবায়ন করতে চাইতে পারেন যা লঞ্চার চালু করার সাথে একটি চুক্তি নিবন্ধন পরিচালনা করে:
কোটলিন
class MyLifecycleObserver(private val registry : ActivityResultRegistry) : DefaultLifecycleObserver { lateinit var getContent : ActivityResultLauncher<String> override fun onCreate(owner: LifecycleOwner) { getContent = registry.register("key", owner, GetContent()) { uri -> // Handle the returned Uri } } fun selectImage() { getContent.launch("image/*") } } class MyFragment : Fragment() { lateinit var observer : MyLifecycleObserver override fun onCreate(savedInstanceState: Bundle?) { // ... observer = MyLifecycleObserver(requireActivity().activityResultRegistry) lifecycle.addObserver(observer) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val selectButton = view.findViewById<Button>(R.id.select_button) selectButton.setOnClickListener { // Open the activity to select an image observer.selectImage() } } }
জাভা
class MyLifecycleObserver implements DefaultLifecycleObserver { private final ActivityResultRegistry mRegistry; private ActivityResultLauncher<String> mGetContent; MyLifecycleObserver(@NonNull ActivityResultRegistry registry) { mRegistry = registry; } public void onCreate(@NonNull LifecycleOwner owner) { // ... mGetContent = mRegistry.register(“key”, owner, new GetContent(), new ActivityResultCallback<Uri>() { @Override public void onActivityResult(Uri uri) { // Handle the returned Uri } }); } public void selectImage() { // Open the activity to select an image mGetContent.launch("image/*"); } } class MyFragment extends Fragment { private MyLifecycleObserver mObserver; @Override void onCreate(Bundle savedInstanceState) { // ... mObserver = new MyLifecycleObserver(requireActivity().getActivityResultRegistry()); getLifecycle().addObserver(mObserver); } @Override void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { Button selectButton = findViewById(R.id.select_button); selectButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mObserver.selectImage(); } }); } }
ActivityResultRegistry
APIs ব্যবহার করার সময়, Google দৃঢ়ভাবে একটি APIs ব্যবহার করার সুপারিশ করে যেগুলি একটি LifecycleOwner
নেয়, কারণ LifecycleOwner
স্বয়ংক্রিয়ভাবে Lifecycle
ধ্বংস হয়ে গেলে আপনার নিবন্ধিত লঞ্চারকে সরিয়ে দেয়। যাইহোক, যে ক্ষেত্রে একজন LifecycleOwner
পাওয়া যায় না, প্রতিটি ActivityResultLauncher
ক্লাস আপনাকে ম্যানুয়ালি unregister()
বিকল্প হিসেবে কল করতে দেয়।
পরীক্ষা
ডিফল্টরূপে, registerForActivityResult()
স্বয়ংক্রিয়ভাবে কার্যকলাপ দ্বারা প্রদত্ত ActivityResultRegistry
ব্যবহার করে। এটি একটি ওভারলোডও প্রদান করে যা আপনাকে ActivityResultRegistry
এর আপনার নিজের উদাহরণে পাস করতে দেয় যা আপনি অন্য কোনো অ্যাক্টিভিটি আরম্ভ না করেই আপনার কার্যকলাপের ফলাফল কলগুলি পরীক্ষা করতে ব্যবহার করতে পারেন।
আপনার অ্যাপের খণ্ডগুলি পরীক্ষা করার সময়, আপনি একটি FragmentFactory
ব্যবহার করে ActivityResultRegistry
এ খণ্ডটির ActivityResultRegistry
পাস করার জন্য একটি পরীক্ষা প্রদান করেন।
উদাহরণ স্বরূপ, ছবির থাম্বনেইল পেতে TakePicturePreview
কন্ট্রাক্ট ব্যবহার করে এমন একটি খণ্ড নিচের মত লেখা হতে পারে:
কোটলিন
class MyFragment( private val registry: ActivityResultRegistry ) : Fragment() { val thumbnailLiveData = MutableLiveData<Bitmap?> val takePicture = registerForActivityResult(TakePicturePreview(), registry) { bitmap: Bitmap? -> thumbnailLiveData.setValue(bitmap) } // ... }
জাভা
public class MyFragment extends Fragment { private final ActivityResultRegistry mRegistry; private final MutableLiveData<Bitmap> mThumbnailLiveData = new MutableLiveData(); private final ActivityResultLauncher<Void> mTakePicture = registerForActivityResult(new TakePicturePreview(), mRegistry, new ActivityResultCallback<Bitmap>() { @Override public void onActivityResult(Bitmap thumbnail) { mThumbnailLiveData.setValue(thumbnail); } }); public MyFragment(@NonNull ActivityResultRegistry registry) { super(); mRegistry = registry; } @VisibleForTesting @NonNull ActivityResultLauncher<Void> getTakePicture() { return mTakePicture; } @VisibleForTesting @NonNull LiveData<Bitmap> getThumbnailLiveData() { return mThumbnailLiveData; } // ... }
একটি পরীক্ষা-নির্দিষ্ট ActivityResultRegistry
তৈরি করার সময়, আপনাকে অবশ্যই onLaunch()
পদ্ধতি প্রয়োগ করতে হবে। startActivityForResult()
কে কল করার পরিবর্তে, আপনার পরীক্ষা বাস্তবায়ন সরাসরি dispatchResult()
কল করতে পারে, আপনার পরীক্ষায় আপনি যে সঠিক ফলাফলগুলি ব্যবহার করতে চান তা প্রদান করে:
val testRegistry = object : ActivityResultRegistry() {
override fun <I, O> onLaunch(
requestCode: Int,
contract: ActivityResultContract<I, O>,
input: I,
options: ActivityOptionsCompat?
) {
dispatchResult(requestCode, expectedResult)
}
}
সম্পূর্ণ পরীক্ষা প্রত্যাশিত ফলাফল তৈরি করে, একটি পরীক্ষা ActivityResultRegistry
তৈরি করে, এটিকে খণ্ডে পাস করে, লঞ্চারটিকে সরাসরি বা অন্যান্য পরীক্ষা API যেমন Espresso ব্যবহার করে ট্রিগার করে এবং তারপর ফলাফল যাচাই করে:
@Test
fun activityResultTest {
// Create an expected result Bitmap
val expectedResult = Bitmap.createBitmap(1, 1, Bitmap.Config.RGBA_F16)
// Create the test ActivityResultRegistry
val testRegistry = object : ActivityResultRegistry() {
override fun <I, O> onLaunch(
requestCode: Int,
contract: ActivityResultContract<I, O>,
input: I,
options: ActivityOptionsCompat?
) {
dispatchResult(requestCode, expectedResult)
}
}
// Use the launchFragmentInContainer method that takes a
// lambda to construct the Fragment with the testRegistry
with(launchFragmentInContainer { MyFragment(testRegistry) }) {
onFragment { fragment ->
// Trigger the ActivityResultLauncher
fragment.takePicture()
// Verify the result is set
assertThat(fragment.thumbnailLiveData.value)
.isSameInstanceAs(expectedResult)
}
}
}
একটি কাস্টম চুক্তি তৈরি করুন
ActivityResultContracts
ব্যবহারের জন্য অনেকগুলি পূর্বনির্মাণকৃত ActivityResultContract
ক্লাস রয়েছে, আপনি আপনার নিজস্ব চুক্তিগুলি প্রদান করতে পারেন যা আপনার প্রয়োজনীয় সুনির্দিষ্ট প্রকার-নিরাপদ API প্রদান করে।
প্রতিটি ActivityResultContract
জন্য সংজ্ঞায়িত ইনপুট এবং আউটপুট ক্লাস প্রয়োজন, যদি আপনার কোনো ইনপুট না লাগে তাহলে Void
ইনপুট টাইপ হিসেবে ব্যবহার করে (কোটলিনে, Void?
অথবা Unit
ব্যবহার করুন)।
প্রতিটি চুক্তিকে createIntent()
পদ্ধতি প্রয়োগ করতে হবে, যা একটি Context
এবং ইনপুট নেয় এবং startActivityForResult()
এর সাথে ব্যবহৃত Intent
তৈরি করে।
প্রতিটি চুক্তিকে অবশ্যই parseResult()
প্রয়োগ করতে হবে, যা প্রদত্ত resultCode
থেকে আউটপুট তৈরি করে, যেমন Activity.RESULT_OK
বা Activity.RESULT_CANCELED
, এবং Intent
।
চুক্তিগুলি ঐচ্ছিকভাবে getSynchronousResult()
প্রয়োগ করতে পারে যদি createIntent()
কল করার প্রয়োজন ছাড়াই একটি প্রদত্ত ইনপুটের ফলাফল নির্ধারণ করা সম্ভব হয়, অন্য কার্যকলাপ শুরু করুন এবং ফলাফল তৈরি করতে parseResult()
ব্যবহার করুন৷
নিম্নলিখিত উদাহরণ দেখায় কিভাবে একটি ActivityResultContract
তৈরি করতে হয়:
কোটলিন
class PickRingtone : ActivityResultContract<Int, Uri?>() { override fun createIntent(context: Context, ringtoneType: Int) = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringtoneType) } override fun parseResult(resultCode: Int, result: Intent?) : Uri? { if (resultCode != Activity.RESULT_OK) { return null } return result?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) } }
জাভা
public class PickRingtone extends ActivityResultContract<Integer, Uri> { @NonNull @Override public Intent createIntent(@NonNull Context context, @NonNull Integer ringtoneType) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringtoneType.intValue()); return intent; } @Override public Uri parseResult(int resultCode, @Nullable Intent result) { if (resultCode != Activity.RESULT_OK || result == null) { return null; } return result.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); } }
আপনার যদি কাস্টম চুক্তির প্রয়োজন না হয়, আপনি StartActivityForResult
চুক্তি ব্যবহার করতে পারেন। এটি একটি জেনেরিক চুক্তি যা যেকোনো Intent
ইনপুট হিসেবে নেয় এবং একটি ActivityResult
ফেরত দেয়, যা আপনাকে আপনার কলব্যাকের অংশ হিসেবে resultCode
এবং Intent
বের করতে দেয়, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
val startForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Activity.RESULT_OK) { val intent = result.data // Handle the Intent } } override fun onCreate(savedInstanceState: Bundle) { // ... val startButton = findViewById(R.id.start_button) startButton.setOnClickListener { // Use the Kotlin extension in activity-ktx // passing it the Intent you want to start startForResult.launch(Intent(this, ResultProducingActivity::class.java)) } }
জাভা
ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(new StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { if (result.getResultCode() == Activity.RESULT_OK) { Intent intent = result.getData(); // Handle the Intent } } }); @Override public void onCreate(@Nullable savedInstanceState: Bundle) { // ... Button startButton = findViewById(R.id.start_button); startButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // The launcher with the Intent you want to start mStartForResult.launch(new Intent(this, ResultProducingActivity.class)); } }); }