答案 0 :(得分:24)
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):
// 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();
}
}
});
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
someActivityResultLauncher.launch(intent);
}
新方法(科特琳):
var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode === Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
doSomeOperations()
}
}
fun openSomeActivityForResult() {
val intent = Intent(this, SomeActivity::class.java)
resultLauncher.launch(intent)
}
答案 1 :(得分:12)
新方法是:registerForActivityResult
优势:
在 Kotlin 中:
var launchSomeActivity = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
// your operation...
}
}
fun openYourActivity() {
val intent = Intent(this, SomeActivity::class.java)
launchSomeActivity.launch(intent)
}
在 Java 中:
// Create lanucher variable inside onAttach or onCreate or global
ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
// your operation....
}
}
});
public void openYourActivity() {
Intent intent = new Intent(this, SomeActivity.class);
launchSomeActivity.launch(intent);
}
答案 2 :(得分:9)
从现在开始,permission_role
已过时,请改用新方法。
Kotlin示例
startActivityForResult()
答案 3 :(得分:4)
onActivityResult
,startActivityForResult
,requestPermissions
和onRequestPermissionsResult
是androidx.fragment
上1.3.0-alpha04
上的deprecated,而不是{{ 1}}。
相反,您可以将Activity Result APIs
与registerForActivityResult
结合使用。
答案 4 :(得分:4)
在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 -> {
...
}
FOR
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
答案 5 :(得分:3)
我的目标是以最少的代码更改重用 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()
}
}
我在我的项目中使用了 Dagger,并在需要的地方注入了包装器
@Inject
lateinit var activityResultLauncher: ActivityResultLauncherWrapper
但是包装器也可以直接实例化:
val activityResultLauncher = ActivityResultLauncherWrapper()
那么您必须使用 startActivityForResult
更改 launchIntentForResult
方法。这是从片段调用它的示例:
activityResultLauncher.launchIntentForResult(
requireActivity(),
intent,
REQUEST_CODE_CONSTANT,
object: ActivityResultLauncherWrapper.OnActivityResultListener {
override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {
/*do something*/
}
}
)
您将在匿名对象中收到结果。
如果您实现接口并像这样重构当前实现,则可以在 Fragment 或 FragmentActivity 中使用 OnActivityResultListener
:
class MyFragment : Fragment(), OnActivityResultListener {
...
override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {/*do somthing*/}
...
}
我们知道,Kotlin 类 ActivityResultLauncherWrapper 也可以在 Java 代码中使用。我的项目中也有 java 类。有一个在 Fragment 中实现回调接口的例子:
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*/}
...
}
我希望这有助于为您的案例构建解决方案。
答案 6 :(得分:3)
参考:Kotlin - Choose Image from gallery
迄今为止我发现的最简单的替代方案
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/*")
}
}
答案 7 :(得分:2)
在 Java 中可以这样写:
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);
答案 8 :(得分:2)
这是我的解决方案:
在我们的项目中,我们有 20 多次 startActivityForResult(和 onActivityResult)。
我们希望尽可能少地更改代码(并继续使用请求代码),同时引入一个优雅的解决方案以供将来使用。
既然我们很多开发人员都使用 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!
}
}
}
希望对大家有所帮助
答案 9 :(得分:1)
在替换已弃用的方法 startActivityForResult(...) 时,需要遵循 4 个简单的步骤。
代替覆盖的方法 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(intent, 123),使用
Intent intent = new Intent(this, SampleActivity.class);
activityResultLaunch.launch(intent);
在 SampleActivity.java 类中,返回源活动时,代码将保持不变,如 -
Intent intent = new Intent();
setResult(123, intent);
finish();
快乐编码! :)
答案 10 :(得分:1)
您可以使用 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
}
}
答案 11 :(得分:1)
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
}
}
});
答案 12 :(得分:0)
如果您使用的是 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)
}
}
答案 13 :(得分:0)
在超类中似乎不推荐使用onActivityResult
,但是您在问题中没有提及超类名称和compileSdkVersion
。
在Java和Kotlin中,只需向其添加@Deprecated
,就可以将每个类或方法标记为已弃用,因此检查您的超类可能会扩展错误的类。
不赞成使用一个类的所有方法。
要查看快速解决方案,请单击不推荐使用的方法,然后在Android Studio中按Ctrl+Q
以查看方法文档,其中应有解决方案。
在我的使用androidx
和API 29作为compileSdkVersion
的项目中,活动和片段中不建议使用此方法
答案 14 :(得分:0)
registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
//...
}
}
向 Activity 请求权限?
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) {
//it: Map<String, Boolean>
}
使用相同的方法,但确保将这些实现放在 initialization, onAttach(), or onCreate()
答案 15 :(得分:0)
另一种方法是分 3 个步骤。 (考虑到你有一个 startActivityForResult(0 和 onActivityResult())
var resultLauncher:ActivityResultLauncher<Intent>
形式创建一个变量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)
答案 16 :(得分:0)
startActivityForResult 和 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)
但是你应该在调用launch之前注册并在任何你想要的地方启动。 否则,你会得到这个异常
attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
答案 17 :(得分:0)
Kotlin 版本的 @Muntashir Akon 解决方案
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())
}
}
}