कोई दूसरी गतिविधि शुरू करना. भले ही, वह आपके ऐप्लिकेशन में हो या किसी दूसरी गतिविधि ऐप्लिकेशन, एकतरफ़ा कार्रवाई ज़रूरी नहीं है. कोई गतिविधि शुरू की जा सकती है और उन्हें वापस नतीजे में शामिल किया जा सकता है. उदाहरण के लिए, आपका ऐप्लिकेशन, कैमरा ऐप्लिकेशन शुरू कर सकता है और तो खींची गई फ़ोटो मिल सकती है. या आप Contacts ऐप्लिकेशन चालू कर सकते हैं इस सुविधा का इस्तेमाल करके, उपयोगकर्ता किसी संपर्क को चुनकर, उसे पा सकता है की जानकारी शामिल की जा सकती है.
हालांकि, इस्तेमाल की गई
startActivityForResult()
और
onActivityResult()
एपीआई, Activity
क्लास में सभी एपीआई लेवल पर उपलब्ध हैं. Google आपको पूरी जानकारी देता है
AndroidX में शुरू किए गए, गतिविधि के नतीजे वाले एपीआई इस्तेमाल करने का सुझाव देता है
Activity
और Fragment
क्लास.
ऐक्टिविटी रिज़ल्ट का एपीआई, नतीजे के लिए रजिस्टर करने के लिए कॉम्पोनेंट उपलब्ध कराता है, नतीजा जनरेट करने वाली गतिविधि को लॉन्च करना और उसके बाद नतीजे को मैनेज करना उसे सिस्टम की मदद से भेजा जाता है.
गतिविधि के किसी नतीजे के लिए कॉलबैक रजिस्टर करें
किसी नतीजे के लिए कोई गतिविधि शुरू करते समय, यह मुमकिन है—और कुछ मामलों में कैमरे के उपयोग जैसी मेमोरी-इंटेंसिव ऑपरेशन के बारे में, यह निश्चित रूप से पता है कि— प्रक्रिया पूरी हो जाएगी और कम मेमोरी की वजह से आपकी गतिविधि खत्म हो जाएगी.
इस वजह से, Activity नतीजे API, नतीजे को अलग कर देते हैं कॉलबैक की सुविधा का इस्तेमाल अपने कोड में उस जगह से करें जहां आपने अन्य गतिविधि लॉन्च की है. क्योंकि नतीजे का कॉलबैक तब उपलब्ध होना चाहिए, जब आपकी प्रोसेस और गतिविधि फिर से बनाया गया, तो कॉलबैक को हर बार बिना किसी शर्त के गतिविधि बनाई जाती है, भले ही दूसरी गतिविधि को लॉन्च करने का आधार सिर्फ़ उपयोगकर्ता इनपुट या अन्य कारोबारी नियम के मुताबिक होता है.
जब
ComponentActivity
या
Fragment
, गतिविधि का नतीजा
एपीआई,
registerForActivityResult()
नतीजा कॉलबैक रजिस्टर करने के लिए एपीआई. registerForActivityResult()
ने
ActivityResultContract
और एक
ActivityResultCallback
और यह
ActivityResultLauncher
,
जिसे अन्य गतिविधि को लॉन्च करने के लिए इस्तेमाल किया जाता है.
ActivityResultContract
, नतीजा देने के लिए ज़रूरी इनपुट टाइप के बारे में बताता है
के साथ नतीजे के आउटपुट टाइप के साथ. एपीआई से
डिफ़ॉल्ट अनुबंध
सामान्य कार्रवाइयों के लिए इस्तेमाल किया जा सकता है, जैसे कि तस्वीर लेना, अनुमतियों का अनुरोध करना वगैरह
चालू करें. आप यह भी कर सकते हैं
पसंद के मुताबिक अनुबंध बनाएं.
ActivityResultCallback
एक तरीका वाला इंटरफ़ेस है.
onActivityResult()
वह तरीका जो
ActivityResultContract
:
Kotlin
val getContent = registerForActivityResult(GetContent()) { uri: Uri? -> // Handle the returned Uri }
Java
// 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 } });
अगर आपके पास एक से ज़्यादा गतिविधि के नतीजे के लिए कॉल हैं और आपने दो में से किसी एक का इस्तेमाल किया है
कॉन्ट्रैक्ट
या अलग-अलग कॉलबैक चाहिए, तो registerForActivityResult()
को एक से ज़्यादा कॉल करें
एक से ज़्यादा ActivityResultLauncher
इंस्टेंस रजिस्टर करने के लिए. आपको ऐसा ज़रूर करना चाहिए
अपनी प्रत्येक रचना के लिए registerForActivityResult()
को एक ही क्रम में कॉल करें
खंडित या गतिविधि करनी चाहिए ताकि इनफ़्लाइट परिणाम
सही कॉलबैक.
फ़्रैगमेंट या गतिविधि से पहले registerForActivityResult()
को कॉल किया जा सकता है
बनाया जाता है और मेंबर वैरिएबल का एलान करते समय इसे सीधे इस्तेमाल करने की अनुमति दी जाती है
लौटाए गए ActivityResultLauncher
इंस्टेंस के लिए.
नतीजे के लिए कोई गतिविधि लॉन्च करें
registerForActivityResult()
आपके कॉलबैक को रजिस्टर करता है, लेकिन यह आपके कॉलबैक को रजिस्टर नहीं करता है
अन्य गतिविधि लॉन्च करें और नतीजे के लिए अनुरोध करें. इसके बजाय, इस
लौटाए गए ActivityResultLauncher
इंस्टेंस की ज़िम्मेदारी है.
अगर इनपुट मौजूद है, तो लॉन्चर वह इनपुट लेता है जो
ActivityResultContract
. कॉल से जुड़ी सुविधा
launch()
नतीजा तैयार करने की प्रोसेस शुरू करता है. जब उपयोगकर्ता
आने वाली गतिविधि और वापस लौटने का समय, onActivityResult()
इसके बाद, ActivityResultCallback
को एक्ज़ीक्यूट किया जाता है, जैसा कि इस उदाहरण में दिखाया गया है:
Kotlin
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/*") } }
Java
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
क्लास
ActivityResultCaller
इंटरफ़ेस आपको registerForActivityResult()
API का उपयोग करने देता है, तो आप
गतिविधि के नतीजे को किसी ऐसी क्लास में पाएं जो लागू नहीं होती
ActivityResultCaller
का इस्तेमाल करके
ActivityResultRegistry
सकता है.
उदाहरण के लिए, हो सकता है कि आप
LifecycleObserver
जो लॉन्चर को लॉन्च करने के साथ ही, कॉन्ट्रैक्ट रजिस्टर करने का काम करती है:
Kotlin
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() } } }
Java
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(); } }); } }
Google का सुझाव है कि आप ActivityResultRegistry
एपीआई का इस्तेमाल करते समय
ऐसे एपीआई जो अपने-आप LifecycleOwner
को LifecycleOwner
के रूप में लेते हैं
Lifecycle
के खत्म होने पर, आपके रजिस्टर किए गए लॉन्चर को हटा देता है. हालांकि,
उन मामलों में जहां LifecycleOwner
उपलब्ध नहीं है, हर एक
ActivityResultLauncher
क्लास की मदद से, मैन्युअल तरीके से कॉल किया जा सकता है
unregister()
विकल्प के तौर पर.
टेस्ट
डिफ़ॉल्ट रूप से, registerForActivityResult()
अपने-आप
ActivityResultRegistry
गतिविधि के ज़रिए उपलब्ध कराया जाता है. साथ ही, इस क्षमता के साथ एक ओवरलोड भी हो जाता है, जिसकी वजह से
ActivityResultRegistry
के अपने इंस्टेंस में जोड़ सकते हैं, जिसे आप
किसी अन्य गतिविधि को लॉन्च किए बिना, उसकी गतिविधि के नतीजे वाले कॉल दिखाए जाते हैं.
अपने ऐप्लिकेशन के फ़्रैगमेंट की जांच करते समय,
टेस्ट करने के लिए ActivityResultRegistry
का इस्तेमाल करें.
पास होने के लिए FragmentFactory
फ़्रैगमेंट के कंस्ट्रक्टर के लिए ActivityResultRegistry
में.
उदाहरण के लिए, ऐसा फ़्रैगमेंट जो पाने के लिए TakePicturePreview
कॉन्ट्रैक्ट का इस्तेमाल करता है
थंबनेल
इमेज में मौजूद टेक्स्ट, नीचे दिए गए टेक्स्ट जैसा हो सकता है:
Kotlin
class MyFragment( private val registry: ActivityResultRegistry ) : Fragment() { val thumbnailLiveData = MutableLiveData<Bitmap?> val takePicture = registerForActivityResult(TakePicturePreview(), registry) { bitmap: Bitmap? -> thumbnailLiveData.setValue(bitmap) } // ... }
Java
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
, इसे फ़्रैगमेंट में पास करता है, लॉन्चर को ट्रिगर करता है
या तो सीधे तौर पर या 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
क्लास मौजूद हैं. इनका इस्तेमाल किया जा सकता है
आपको अपने अनुबंध से जुड़े सटीक टाइप-सेफ़ एपीआई उपलब्ध कराने होंगे.
हर ActivityResultContract
में, पहले से तय इनपुट और आउटपुट क्लास की ज़रूरत होती है,
Void
को इनपुट टाइप के तौर पर इस्तेमाल करके, अगर आपने
उसे किसी इनपुट की ज़रूरत नहीं है (Kotlin की मदद से, Void?
या Unit
का इस्तेमाल करें).
हर अनुबंध में
createIntent()
तरीका, जो Context
और इनपुट को लेकर Intent
को बनाता है
का इस्तेमाल किया गया है
startActivityForResult()
के साथ.
हर कानूनी समझौते को
parseResult()
,
जो दिए गए resultCode
से आउटपुट देता है, जैसे
Activity.RESULT_OK
या Activity.RESULT_CANCELED
और Intent
.
कानूनी समझौते को वैकल्पिक तौर पर लागू किया जा सकता है
getSynchronousResult()
अगर दिए गए इनपुट के बिना नतीजे तय किए जा सकते हैं
createIntent()
को कॉल करने, अन्य गतिविधि शुरू करने, और इसका इस्तेमाल करने की ज़रूरत नहीं है
नतीजा बनाने के लिए parseResult()
.
नीचे दिए गए उदाहरण में, ActivityResultContract
बनाने का तरीका बताया गया है:
Kotlin
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) } }
Java
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
को एक्सट्रैक्ट करने की सुविधा देता है,
जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है:
Kotlin
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)) } }
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)); } }); }