Как заставить MapActivity в TabActivity ждать получения данных оверлея с сервера?

#android #maps #wait #mapactivity

#Android #Карты #подождите #mapactivity

Вопрос:

Итак, в моей программе у меня есть TabActivity, который содержит две вкладки, одна вкладка — это ListView, а другая — MapActivity, которая запускается с помощью намерения. Я хочу, чтобы мое приложение отправляло запрос с указанием местоположения телефонов и названия продукта и выводило список ближайших магазинов, в которых есть этот продукт, затем показывало эти магазины на вкладке «Карта» и показывало их список на другой вкладке. Приложение начинает прослушивать местоположение при запуске TabActivity, и связь с сервером (в AsyncTask) начинается, как только местоположение получено.

Проблема в том, что когда TabActivity запускается, он также запускает MapActivity, потому что он находится на его первой вкладке, и MapActivity начинает пытаться добавить наложения на карту, но данных для этих наложений пока нет, потому что AsyncTask в TabActivity еще не закончил получение данных с сервера, что приводит к сбою программы.

Мне нужно, чтобы мое приложение показывало пустую карту Google при первом открытии TabActivity и ожидало получения данных с сервера, а затем добавляло наложения на карту, чтобы отметить магазины на ней. Кто-нибудь может показать мне, как я могу этого добиться? Я думаю, мне следует удалить часть кода, создающую оверлей, из onCreate в MapActivity и поместить ее куда-нибудь еще, но я не знаю куда.

Ответ №1:

Потенциально лучшим подходом было бы получить текущую активность вкладки с помощью ActivityGroup#getCurrentActivity(), проверить и преобразовать в ожидаемую MapActivity, а затем вызвать метод в этой активности:

 protected void onPostExecute(final Bitmap result) {
    final Activity activity = MyTabActivity.this.getCurrentActivity();
    if (activity instanceof MyMapActivity) {
        ((MyMapActivity) activity).onBitmapReceived(result); // or some other method, like onMarkersReceived(), etc..
    }
}
  

Проблема с BroadcastReceiver решением заключается в том, что трансляция выходит за пределы изолированной среды вашего приложения, пытаясь уведомить кого-либо на устройстве, которое прослушивает ваши намерения, хотя на самом деле только один получатель хочет иметь с этим что-либо общее.

Комментарии:

1. Просто попробовал ваше предложение, работает безупречно и действительно является лучшим подходом к тому, чего я пытаюсь достичь. Спасибо.

Ответ №2:

В вашей AsyncTask переопределите метод onPostExecute и создайте там свое наложение. Эта функция будет вызвана после завершения метода doInBackground. Скорее всего, вы захотите отправить результаты из вашего материала doInBackground в onPostExecute.

Пример из здесь:

 private class DownloadImageTask extends AsyncTask {
     protected Bitmap doInBackground(String... urls) {
         return loadImageFromNetwork(urls[0]);
     }

     protected void onPostExecute(Bitmap result) {
         mImageView.setImageBitmap(result);
     }
 }
  

Комментарии:

1. Спасибо, Марк, но моя AsyncTask находится в TabActivity, а карта — в другом activity, поэтому я не могу создавать оверлеи в onPostExecute. Мне нужно каким-то образом передать сообщение из onPostExecute в мой MapActivity о том, что данные получены.

2. Вы можете отправить MapActivity новое намерение, содержащее информацию, необходимую для создания наложения. В MapActivity переопределите метод onNewIntent и обработайте входящие данные из нового намерения там.

3. Я тоже думал об этом, но я не знаю, как это сделать, и я не могу найти никакой полезной информации об этом, все руководства по использованию Intents, которые я нашел, используют их только с методами startActivity () или startActivityForResult (), но мне не нужно снова запускать MapActivity, потому что он уже запускается при запуске TabActivity. Есть ли какой-либо другой способ отправить intent в activity, который уже запущен?

4. Нет, вы отправляете намерение таким же образом. Намерения используются не только для запуска новых действий, они также могут использоваться для передачи информации между действиями. В моем приложении у меня есть режим запуска activity, который получает значение intent, установленное на singleTop. Для этого поместите android:launchMode=»singleTop» в свой узел Activity в AndroidManifest.xml. Затем в этом действии переопределите onNewIntent (намерение Intent) и извлеките данные, которые вы передали, из объекта intent.

5. Приложение сейчас не аварийно завершает работу, но намерение запускает новый экземпляр MapActivity, который затем занимает весь экран, и мне нужно, чтобы MapActivity был на вкладке. Я предполагаю, что это потому, что MapActivity не находится на вершине стека activity, потому что это часть TabActivity, а действия singleTop должны быть поверх стека, иначе будет создан их новый экземпляр на основе полученного намерения, как для стандартных действий :/

Ответ №3:

Я решил эту проблему сам. Это действительно просто, просто нужно использовать широковещательный приемник.

Я создал BroadcastReceiver в моем MapActivity:

 private BroadcastReceiver myReceiver = new BroadcastReceiver() {        
    @Override
    public void onReceive(Context context, Intent intent) {
        addMarkers();
        mapView.invalidate();
    }
};
  

Затем я зарегистрировал это в методе MapActivities onCreate:

 registerReceiver(myReceiver, new IntentFilter("VAISTINES.RECEIVED"));
  

И, наконец, я заставил мой метод AsyncTask в TabActivity onPostExecute отправлять широковещательную рассылку, сообщающую, что необходимые данные были получены с сервера:

 Intent i = new Intent("VAISTINES.RECEIVED");
sendBroadcast(i);