我有两个使用Xamarin.Android编写的独立应用程序;为了便于讨论,我们将它们称为“ Tristan”和“ Isolde”。特里斯坦(Tristan)有一些伊索尔德有时需要知道的状态信息。并发症:在Isolde发展了解自己状态的需求的那一刻,Tristan可能正在跑步,也可能未跑步。

我现在正在忙着工作,在这里Isolde向Tristan发送了一个特殊的启动意图,然后Tristan使用广播意图将信息发送回Isolde。 (有关详细信息,请参见我的earlier question。)

“可是等等!”我听到你在哭,“这不是StartActivityForResult()的完美用例吗?”它的确是!该代码非常简单,我读过的所有内容都暗示这就是Android希望您做这样的事情的方式。

不幸的是,我无法使其正常运行(尽管尝试了许多变体并阅读了该站点上的十几个相关问题)。我的特定问题是在Isolde的OnActivityResult()回调中,resultCode始终为Result.Canceled,而data始终为null

这是Tristan的代码(其中注释掉的位代表我尝试过的变体):

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);
        }
    }
}


以下是Activity中的相关代码,Isolde需要询问Tristan的状态:

    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);
        }
    }


诊断程序-或更确切地说,缺少诊断程序-使我相信Tristan的IsoldeQueryActivity.OnStart()从未真正被调用过。

欢迎提出想法,要求提供其他信息和/或尝试进行有用的实验。 (如果您的想法是“在清单中放入”,请记住这是Xamarin.Android,我必须通过在装饰Activity的属性中放入来做到这一点。)

编辑添加:在Isolde的代码中,由于DoStuffWith(data)datanull崩溃了。当我更改该方法以避免这种情况时,我发现(稍晚些时候)在StartActivityForResult()中引发了一个异常:

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


这使我相信我没有在Isolde中正确创建Intent。我是否需要使用其他Intent构造函数之一?如果是这样,具体如何?

最佳答案

好吧,我想我已经知道了。我最初的问题中的代码存在三个主要问题:


我在Isolde中错误地构建了Intent
我没有在Tristan中导出IsoldeQueryActivity
必须在Tristan的base.OnStart()替代中调用OnStart


这是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();
        }
    }
}


这是来自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);
    }
}

07-27 21:50