İster uygulamanızın içinden ister başka bir yerden başka bir etkinlik başlatma uygulamanızın tek yönlü bir işlem olması gerekmez. Bir etkinlik de başlatabilirsiniz. ve sonucu geri alırsınız. Örneğin, uygulamanız bir kamera uygulaması başlatabilir ve Böylece, çekilen fotoğrafı alabilirsiniz. Alternatif olarak Kişiler uygulamasını başlatabilirsiniz kullanıcının bir kişi seçmesi ve ardından kişiyi karar vermektir.
Temelde
startActivityForResult()
ve
onActivityResult()
API'ler Activity
sınıfında tüm API düzeylerinde kullanılabilir.
AndroidX'te sunulan Activity Result API'lerinin kullanılmasını önerir.
Activity
ve Fragment
sınıfa sahip.
Activity Result API'leri bir sonuca kaydolmaya yönelik bileşenleri sağlar. Sonucu üreten etkinliği başlatmak ve sonuçtan sonra sistem tarafından gönderilir.
Bir etkinlik sonucu için geri çağırma kaydedin
Bir sonuç için etkinlik başlatırken bu mümkün kamera kullanımı gibi belleği yoğun bir şekilde kullanan işlemlerdir. işlemi tamamlamaz. Düşük bellek nedeniyle etkinliğiniz yok olur.
Bu nedenle, Activity Result API'leri sonucu ayırır. kodunuzda diğer etkinliği başlattığınız yerden çağrılıyor. Çünkü İşleminiz ve etkinliğiniz aşağıdaki durumlarda olduğunda geri çağırma işlevinin kullanılabilir olması gerekir: geri çağırmanın, oluşturduğunuz her yalnızca diğer etkinliğin başlatılmasının mantığıyla dahi olsa bir etkinlik oluşturulur. kullanıcı girişlerine veya diğer iş mantığına bağlı olarak gerçekleşir.
Bir
ComponentActivity
veya bir
Fragment
, Etkinlik Sonucu
API'ler
registerForActivityResult()
Sonuç geri çağırmasını kaydetme API'si. registerForActivityResult()
ActivityResultContract
ve
ActivityResultCallback
ve
ActivityResultLauncher
başka bir aktiviteye başlamak için
kullanacağınız araç var.
ActivityResultContract
, sonuç üretmek için gereken giriş türünü tanımlar
ve sonucun çıkış türüyle birlikte gösterilir. API'ler,
varsayılan sözleşmeler
Resim çekme, izin isteme gibi temel amaca yönelik işlemler için
beklemeye gerek yoktur. Ayrıca transkriptinizi
özel bir sözleşme oluşturabilirsiniz.
ActivityResultCallback
, tek yöntemli arayüzdür.
onActivityResult()
yönteminde tanımlanan çıkış türündeki bir nesneyi alan
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 } });
Birden fazla etkinlik sonucu çağrınız varsa ve bunlardan birini kullanıyorsanız
sözleşmeler
veya ayrı geri çağırmalar isterseniz registerForActivityResult()
için birden çok
kez kaydedin.ActivityResultLauncher
Şunu yapmalısınız:
her oluşturulduğunda registerForActivityResult()
öğesini aynı sırayla çağırın
parça veya etkinlik ile birlikte yayındaki sonuçların
doğru geri arama.
registerForActivityResult()
, parçanızdan veya etkinliğinizden önce güvenle çağrılabilir
oluşturulur ve üye değişkenleri bildirilirken doğrudan kullanılmasına izin verilir
döndürülen ActivityResultLauncher
örnektir.
Sonuç için etkinlik başlat
registerForActivityResult()
geri aramanızı kaydeder ancak kaydetmez
diğer etkinliği başlatın ve sonuç isteğini başlatın. Bunun yerine,
döndürülen ActivityResultLauncher
örneğinin sorumluluğundadır.
Giriş mevcutsa başlatıcı
ActivityResultContract
Telefon etme
launch()
ve sonucu üretme sürecini başlatır. Kullanıcı
etkinlikleri ve getirileri gösteren onActivityResult()
Ardından ActivityResultCallback
aşağıdaki örnekte gösterildiği gibi yürütülür:
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/*"); } }); }
Şunun aşırı yüklenmiş sürümü:
launch()
bir
ActivityOptionsCompat
olduğunu düşünelim.
Etkinlik sonucunu ayrı bir sınıfta alın
ComponentActivity
ve Fragment
sınıfları
ActivityResultCaller
registerForActivityResult()
API'ları kullanmanıza olanak tanıyan arayüzü kullanarak
etkinlik sonucunu,
Şunu kullanarak ActivityResultCaller
:
ActivityResultRegistry
doğrudan ekleyebilirsiniz.
Örneğin, ekip arkadaşlarınızla
birlikte çalışmak isteyebilirsiniz.
LifecycleObserver
bir sözleşmenin kaydedilmesi ve başlatıcının başlatılmasıyla ilgili işlemler:
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
API'lerini kullanırken
otomatik olarak LifecycleOwner
gibi LifecycleOwner
alan API'ler
Lifecycle
silindiğinde kayıtlı başlatıcınızı kaldırır. Ancak,
LifecycleOwner
öğesinin kullanılamadığı durumlarda, her bir
ActivityResultLauncher
sınıfta manuel olarak arama yapabilirsiniz
unregister()
kullanabilirsiniz.
Test
Varsayılan olarak, registerForActivityResult()
otomatik olarak
ActivityResultRegistry
etkinliği tarafından sağlandığından emin olun. Ayrıca aşırı yüklenmeyi sağlayarak
test etmek için kullanabileceğiniz, kendi ActivityResultRegistry
örneğinizde
aslında başka bir etkinlik başlatmadan etkinlik sonucu çağrıları.
Uygulamanızın parçalarını test ederken,
kullanarak bir test ActivityResultRegistry
sağlayın:
Geçmek için FragmentFactory
kaldı
ActivityResultRegistry
öğesini parçanın oluşturucusuna ekleyin.
Örneğin, TakePicturePreview
sözleşmesini kullanan bir parçanın
küçük resim
aşağıdakine benzer bir resim yazılabilir:
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; } // ... }
Teste özel bir ActivityResultRegistry
oluştururken
"the"
onLaunch()
yöntemidir. startActivityForResult()
yöntemini çağırmak yerine testiniz
uygulama,
dispatchResult()
testinizde kullanmak istediğiniz tam sonuçları sağlayarak:
val testRegistry = object : ActivityResultRegistry() {
override fun <I, O> onLaunch(
requestCode: Int,
contract: ActivityResultContract<I, O>,
input: I,
options: ActivityOptionsCompat?
) {
dispatchResult(requestCode, expectedResult)
}
}
Eksiksiz test beklenen sonucu verir, yeni bir test oluşturur
ActivityResultRegistry
, parçaya iletir, başlatıcıyı tetikler
test API'lerini kullanarak veya Espresso gibi diğer test API'lerini kullanarak
sonuçlar:
@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)
}
}
}
Özel sözleşme oluşturun
ActivityResultContracts
iken
bir dizi önceden oluşturulmuş ActivityResultContract
sınıfı içerirse
İhtiyacınız olan tür açısından güvenli API'yi sağlayan kendi sözleşmelerinizi sağlayın.
Her ActivityResultContract
, tanımlanmış giriş ve çıkış sınıfları gerektirir.
giriş türü olarak Void
kullanma
herhangi bir giriş gerektirmez (Kotlin'de, Void?
veya Unit
'i kullanın).
Her sözleşme,
createIntent()
yöntemini kullanır. Bu yöntem, bir Context
ile girdiyi alır ve şunu oluşturur: Intent
kullanılıyor
startActivityForResult()
ile.
Her sözleşme ayrıca şunları da yapmalıdır:
parseResult()
Bu, verilen resultCode
çıktısını oluşturur; örneğin,
Activity.RESULT_OK
veya Activity.RESULT_CANCELED
ve Intent
.
Sözleşmeler isteğe bağlı olarak
getSynchronousResult()
belirli bir girdinin sonucunun rastgele belirlenmeden
createIntent()
numaralı telefonu arayıp diğer etkinliği başlatmanız ve
parseResult()
tuşuna basın.
Aşağıdaki örnekte ActivityResultContract
öğesinin nasıl oluşturulacağı gösterilmektedir:
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); } }
Özel bir sözleşmeye ihtiyacınız yoksa
StartActivityForResult
sözleşme imzalamaz. Bu, herhangi bir Intent
girdisini alan ve
şunu döndürür:
ActivityResult
,
geri aramanızın bir parçası olarak resultCode
ve Intent
öğelerini çıkarmanıza olanak tanır.
aşağıdaki örnekte gösterildiği gibi:
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)); } }); }