Xamarin Android: использование StartActivityForResult ();resultCode в OnActivityResult всегда "отменен" - PullRequest
0 голосов
/ 26 декабря 2018

У меня есть два отдельных приложения, написанные с использованием Xamarin.Android;для обсуждения давайте назовем их «Тристан» и «Изольда».У Тристана есть информация о состоянии, которую иногда нужно знать Изольде.Осложнение: Тристан может работать или не работать в тот момент, когда у Изольды возникает потребность узнать его состояние.

У меня сейчас работает Клудж, когда Изольда отправляет Тристану специальное намерение при запуске, которое затем использует намерение вещания.отправить информацию обратно Изольде.(Подробности см. В моем предыдущем вопросе .)

"Но подождите!"Я слышу, как ты плачешь: "Разве это не идеальный вариант использования StartActivityForResult()?"Это действительно так!Код намного проще, и все, что я прочитал, подразумевает, что именно таким образом Android хочет, чтобы вы делали подобные вещи.

К сожалению, я не могу заставить его работать (несмотря на то, что пробовал много вариантов ичитая дюжину или около того связанных вопросов на этом самом сайте).Моя конкретная проблема заключается в том, что в обратном вызове 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, где Изольде нужно запросить состояние Тристана:

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

Диагностика - илискорее, их специфический недостаток - заставляет меня верить, что Тристана IsoldeQueryActivity.OnStart() никогда не вызывают.

Идеи, запросы на дополнительную информацию и / или полезные эксперименты, которые можно попробовать, приветствуются.(Если ваша идея «Поместить в манифест», помните, что это Xamarin. Android, и я должен сделать это, поместив в атрибут, украшающий Activity.)

Отредактировано вдобавить: в коде Изольды, DoStuffWith(data) был сбой, потому что data было null.Когда я изменил этот метод, чтобы избежать этого, я обнаружил, что получил (чуть позже) исключение, брошенное в StartActivityForResult():

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

Это заставляет меня поверить, что я не создаю Intent должным образомв Изольде.Нужно ли использовать один из других Intent конструкторов?Если да, то как конкретно?

1 Ответ

0 голосов
/ 27 декабря 2018

Ладно, думаю, я понял это.Код в моем исходном вопросе имел три основные проблемы:

  1. Я неправильно строил Intent в Изольде.
  2. Я не экспортировал IsoldeQueryActivity в Тристане.
  3. Обращение к 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();
        }
    }
}

А вотфиксированный код от Изольды:

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