Xamarin Android: using StartActivityForResult(); resultCode in OnActivityResult is always “Canceled”

前提是你 提交于 2019-12-23 01:14:28

问题


I have two separate applications written using Xamarin.Android; for the sake of discussion, let's call them "Tristan" and "Isolde". Tristan has some state information that Isolde sometimes needs to know. Complication: Tristan may or may not be running at the moment Isolde develops the need to know his state.

I've got kludge working now where Isolde sends a special launch intent to Tristan, who then uses a broadcast intent to send information back to Isolde. (See my earlier question for details.)

"But wait!" I hear you cry, "Is this not a perfect use case for StartActivityForResult()?" Indeed it is! The code is a whole lot simpler, and everything I've read implies that this is how Android wants you to do stuff like this.

Unfortunately, I can't get it to work (despite trying many variations and reading the dozen-or-so related questions on this very site). My specific problem is that in Isolde's OnActivityResult() callback, the resultCode is always Result.Canceled and the data is always null.

Here is the code for Tristan (where commented-out bits represent variations I've tried):

using Android.App;
using Android.Content;

namespace com.example.Tristan.Android
{
    [Activity(Name ="com.example.Tristan.Android.IsoldeQueryActivity")]
    public class IsoldeQueryActivity : Activity
    {
        protected override void OnStart()
        {
            // base.OnStart();
            var rtn = new Intent();
            rtn.PutExtra("Test", "test");
            //rtn.SetAction("TestAction");
            SetResult(Result.Ok, rtn);
            Finish();
            //FinishActivity(1234);
        }
    }
}

And here is the relevant code from the Activity where Isolde needs to ask for Tristan's state:

    private TaskCompletionSource<bool> TristanStateCompletion;

    public async Task GetTristanState()
    {
        TristanStateCompletion = new TaskCompletionSource<bool>();

        var req = new Intent("com.example.Tristan.Android.IsoldeQueryActivity");
        //req.PutExtra(Intent.ExtraReturnResult, true);
        StartActivityForResult(req, 1234);
        var rtn = await TristanStateCompletion.Task;
        if (!rtn) bomb("can't get state");
        TristanStateCompletion = null;
    }

    protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);
        if(requestCode == 1234) {
           DoStuffWith(data);
           TristanStateCompletion?.TrySetResult(true);
        }
    }

Diagnostics -- or rather, a specific lack of them -- leads me to believe that Tristan's IsoldeQueryActivity.OnStart() is never actually being called.

Ideas, requests for additional information and/or useful experiments to try are all welcome. (If your idea is "Put <thing> in the manifest", remember this is Xamarin.Android and I have to do that by putting <relatedThing> in the attribute decorating the Activity.)

Edited to add: In Isolde's code, DoStuffWith(data) was crashing because data was null. When I changed that method to avoid that, I found that I got a (slightly later) exception thrown in StartActivityForResult():

Android.Content.ActivityNotFoundException No Activity found to handle Intent { act=com.example.Tristan.Android.IsoldeQueryActivity }

This leads me to believe I'm not creating the Intent properly in Isolde. Do I need to be using one of the other Intent constructors? If so, how specifically?


回答1:


Okay, I think I have this figured out. The code in my original question had three major problems:

  1. I was building the Intent incorrectly in Isolde.
  2. I didn't export the IsoldeQueryActivity in Tristan.
  3. The call to base.OnStart() in Tristan's OnStart override is mandatory.

Here is the working version of Tristan:

using Android.App;
using Android.Content;

namespace com.example.Tristan.Android 
{
    [Activity(Name ="com.example.Tristan.Android.IsoldeQueryActivity", Exported=true)]
    public class IsoldeQueryActivity : Activity
    {
        protected override void OnStart()
        {
            base.OnStart();
            var rtn = new Intent();
            rtn.PutExtra("Test", "test");
            SetResult(Result.Ok, rtn);
            Finish();
        }
    }
}

And here is the fixed code from Isolde:

private TaskCompletionSource<bool> TristanStateCompletion;

public async Task GetTristanState()
{
    TristanStateCompletion = new TaskCompletionSource<bool>();

    var req = new Intent();
    req.SetComponent(new ComponentName("com.example.Tristan.Android", "com.example.Tristan.Android.IsoldeQueryActivity"));

    StartActivityForResult(req, 1234);
    var rtn = await TristanStateCompletion.Task;
    if (!rtn) bomb("can't get state");
    TristanStateCompletion = null;
}

protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    if(requestCode == 1234) {
       if(resultCode != Result.Ok) bomb("bad resultCode {0}", resultCode);
       if(data == null) bomb("null data from Tristan");
       DoStuffWith(data);
       TristanStateCompletion?.TrySetResult(true);
    }
}


来源:https://stackoverflow.com/questions/53935398/xamarin-android-using-startactivityforresult-resultcode-in-onactivityresult

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!