Как отобразить диалоговое окно в Android без контекста активности? - PullRequest
33 голосов
/ 17 марта 2012

Кажется, это должно быть просто, но я нигде не нахожу ответа. У меня есть приложение для Android, которое выполняет сетевые задачи в фоновом режиме. Если ошибка возвращается, я хочу отобразить диалог ошибки. Когда задание возвращается, я не знаю, какое действие находится на переднем плане. Исходя из этого поста , похоже, что мы не можем использовать контекст приложения для отображения диалогового окна (и действительно я получаю сбой, если пытаюсь).

Так, как я могу получить контекст текущей деятельности? Опять же, получатель сетевой задачи работает в контексте приложения, а не в конкретной операции. Есть другие идеи?

Редактировать: я должен уточнить. Я не хочу отображать диалоговое окно с ошибкой, если я не являюсь основным приложением. Меня интересует только тот случай, когда наше приложение сейчас на переднем плане.

Ответы [ 9 ]

26 голосов
/ 17 марта 2012

Если ошибка возвращается, я хочу отобразить диалог ошибки.

Пожалуйста, делайте это, только если вы знаете, что пользователь активно использует ваше приложение. Пользователь будет очень и очень раздражен, если вы прервете его посреди чего-то другого (игра в игру, просмотр фильма, чтение книги).

Так, как я могу получить контекст текущей деятельности?

Вы не. Самое большее, вы позволяете текущей деятельности знать, что она должна что-то делать.

Есть еще идеи?

Одной из возможностей является использование упорядоченной трансляции, поэтому , если у вас есть активность на переднем плане, она получает контроль, в противном случае вы поднимаете Notification, чтобы сообщить пользователю о проблеме, не открывая диалоговое окно. Деятельность, которая получает заказанную рассылку, может отображать AlertDialog или иным образом сообщать пользователю о проблеме. Я написал подробности о том, как это сделать , в сообщении в блоге глава книги , в этом отношении), и вот пример приложения , демонстрирующий техника.

Или обратитесь в службу поддержки startActivity(), чтобы запустить диалоговую тему .

6 голосов
/ 19 марта 2012

Я создал вспомогательный класс, который реализует идею CommonsWare. Для действий, которые хотят отображать оповещения, просто нужно вызвать Alerts.register () и Alerts.unregister (). Тогда любой может вызвать Alerts.displayError ().

Комментарии приветствуются.

public class Alerts {

    private static class AlertReceiver extends BroadcastReceiver {

        private static HashMap<Activity, AlertReceiver> registrations;
        private Context activityContext;

        static {
            registrations = new HashMap<Activity, AlertReceiver>();
        }

        static void register(Activity activity) {
            AlertReceiver receiver = new AlertReceiver(activity);
            activity.registerReceiver(receiver, new IntentFilter(MyApplication.INTENT_DISPLAYERROR));
            registrations.put(activity, receiver);
        }

        static void unregister(Activity activity) {
            AlertReceiver receiver = registrations.get(activity);
            if(receiver != null) {
                activity.unregisterReceiver(receiver);
                registrations.remove(activity);
            }
        }

        private AlertReceiver(Activity activity) {
            activityContext = activity;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            abortBroadcast();
            String msg = intent.getStringExtra(Intent.EXTRA_TEXT);
            displayErrorInternal(activityContext, msg);
        }
    }

    public static void register(Activity activity) {
        AlertReceiver.register(activity);
    }

    public static void unregister(Activity activity) {
        AlertReceiver.unregister(activity);
    }

    public static void displayError(Context context, String msg) {
        Intent intent = new Intent(MyApplication.INTENT_DISPLAYERROR);
        intent.putExtra(Intent.EXTRA_TEXT, msg);
        context.sendOrderedBroadcast(intent, null);
    }

    private static void displayErrorInternal(Context context, String msg) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("Error")
               .setMessage(msg)
               .setCancelable(false)
               .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       dialog.cancel();
                   }
               });
        final AlertDialog alert = builder.create();

        alert.show();
    }

}
4 голосов
/ 05 июля 2018

Я использую пользовательский диалог.Он будет вызываться службой или обработчиком даже в том случае, если текущая активность потеряет фокус.

активность моего пользовательского диалога :

public class AlertDialogue extends AppCompatActivity {

    Button btnOk;
    TextView textDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE); //comment this line if you need to show Title.
        setContentView(R.layout.activity_alert_dialogue);

        textDialog = (TextView)findViewById(R.id.text_dialog) ;
        textDialog.setText("Hello, I'm the dialog text!");

        btnOk = (Button) findViewById(R.id.button_dialog);
        btnOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

Вы можете позвонитьэтот диалог использует:

Intent intent = new Intent(this, AlertDialogue.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

В манифесте :

<activity android:name=".AlertDialogue"
    android:theme="@style/AlertDialogMy">

</activity>

стиль:

<resources>

    <style name="AlertDialogMy" parent="Theme.AppCompat.Light.Dialog">
        <item name="android:windowNoTitle">true</item> //delete this line if you need to show Title.
    </style>

</resources>

Вот полный код этого примера .

1 голос
/ 22 августа 2017

Вот реализация, которая позволяет отображать AlertDialog поверх текущей активной активности (это пример диалога сообщений, но может использоваться и для оповещений).

public class AlertsDialogue
{
    private AlertDialog.Builder alertDialogBuilder;
    private AlertDialog alert;

    public AlertsDialogue(Context context, String title, String message)
    {
        alertDialogBuilder = new AlertDialog.Builder(context);
        alertDialogBuilder.setTitle(title);
        alertDialogBuilder.setIcon(R.drawable.ic_launcher);
        alertDialogBuilder.setMessage(message)
            .setCancelable(false)
            .setPositiveButton(context.getString(R.string.text_ok), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    alert.dismiss();
                }
            });

        alert = alertDialogBuilder.create();
        Window window = alert.getWindow();
        if (window != null)
        {
            // the important stuff..
            window.setType(WindowManager.LayoutParams.TYPE_TOAST);
            alert.show();
        }
        else
            Toast.makeText(context, message, Toast.LENGTH_LONG).show();
    }
}

Диалоговое окно будет отображаться, даже если контекст, в котором он был создан, больше не активен, очень похоже на Toast.

Позвонить с new AlertsDialogue(MyActivity.this, "title", "message");

Никаких дополнительных разрешений в файле AndroidManifest не требуется.

0 голосов
/ 01 июля 2016

вам нужно сбросить тип окна, к которому прикреплен диалог, как показано ниже: dialog.getWindow (). SetType (WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

не забудьте объявить разрешение «android.permission.SYSTEM_ALERT_WINDOW»в вашем манифесте.

0 голосов
/ 10 сентября 2015

Почему бы не использовать шину событий (https://github.com/greenrobot/EventBus)?

  1. Определить события:

    public class ShowErrorMessageEvent {
    
        public String errorMessage;
    
        public ShowErrorMessageEvent(String errorMessage) {
            this.errorMessage = errorMessage;
        }
        public String getErrorMessage() {
            return this.errorMessage;
        }
    }
    
  2. Подготовка подписчиков ко всем нужным вам действиям:

    @Override
    public void onStart() { 
        super.onStart(); 
        EventBus.getDefault().register(this);
    }
    
    @Override
    public void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }
    
  3. Во всех действиях показать диалоговое окно, если получено событие

     public void onEvent(ShowErrorMessageEvent event) {
         /* Show dialog with event.getErrorMessage() from background thread */
     };
    
  4. В фоновой ветке опубликуйте сообщение об ошибке:

    EventBus.getDefault().post(new ShowErrorMessageEvent("This is an error message!"));
    
0 голосов
/ 17 августа 2014

Я тоже сталкиваюсь с проблемой.Я нахожу простое и эффективное решение.Как правило, у нас есть базовое действие, используемое для обработки некоторой общей логики.Итак, имейте это:

public class BaseActionBarActivity extends ActionBarActivity{  //this BaseActionBarActivity is the Base Act

   private static BaseActionBarActivity current;

   @Override
   protected void onStart() {
     super.onStart();
     current=this;
   }


   public static BaseActionBarActivity getCurrentContext() {
     return current;
   }
}

текущее поле является текущим контекстным действиемИ я считаю, что нет вопроса утечки памяти.Это хорошо работает для меня!Надеюсь, полезно

0 голосов
/ 17 марта 2012

Какие сетевые задачи выполняются в фоновом режиме.Я бы предложил переосмыслить дизайн.Возможно, уведомление будет лучше?Или, может быть, экран «Сводка результатов».Как пользователь, я бы предпочел не навязчивый сигнал об ошибке, если я не жду активного завершения задачи.

0 голосов
/ 17 марта 2012

Ну, я думаю, что лучшим для вас будет AsyncTask.Вот пример и документ: http://developer.android.com/reference/android/os/AsyncTask.html

...