web-dev-qa-db-ja.com

Androidアクティビティコンテキストなしでダイアログを表示するにはどうすればよいですか?

これは簡単なはずですが、どこにも答えが見つかりません。 Androidバックグラウンドでネットワークタスクを実行するアプリケーションがあります。エラーが戻ってきたら、エラーダイアログを表示します。タスクが戻ったとき、どのアクティビティが入っているのかわかりません this post に基づいて、ダイアログを表示するためにアプリケーションコンテキストを使用できないように見えます(実際に試してみるとクラッシュします)。

では、現在のアクティビティのコンテキストを取得するにはどうすればよいですか?繰り返しますが、ネットワークタスクのレシーバーは、特定のアクティビティではなく、アプリケーションコンテキストで実行されています。他のアイデアはありますか?

編集:明確にする必要があります。フォアグラウンドアプリケーションではない場合、エラーダイアログを表示したくありません。今のところ、アプリがフォアグラウンドにある場合にのみ興味があります。

34
ManicBlowfish

エラーが戻ってきたら、エラーダイアログを表示したいです。

ユーザーがアプリケーションを積極的に使用していることがわかっている場合にのみ、これを行ってください。他の何か(ゲームをしている、映画を見ている、本を読んでいる)の途中でユーザーを中断すると、ユーザーは非常にイライラします。

では、現在のアクティビティのコンテキストを取得するにはどうすればよいですか?

あなたはしません。せいぜい、あなたは現在のアクティビティに何かをする必要があることを知らせます。

他のアイデアはありますか?

可能性の1つは、順序付けられたブロードキャストを使用することです。したがって、ifフォアグラウンドアクティビティがあり、制御を取得します。そうでない場合は、Notificationをダイアログを表示せずに、ユーザーに問題を知らせます。順序付けられたブロードキャストを受信するアクティビティは、AlertDialogを表示するか、ユーザーに問題を知らせることができます。私はこれを行う方法の詳細について書きました ブログ投稿で (そして 本の章 、そのことについて)、そして ここにサンプルアプリケーションがあります テクニックのデモ。

または、サービスがstartActivity()を呼び出して起動するようにします ダイアログをテーマにしたアクティビティ

26
CommonsWare

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

}
6
ManicBlowfish

カスタム作成のダイアログを使用しています。現在のアクティビティがフォーカスを失う場合でも、サービスまたはハンドラーによって呼び出されます。

カスタムダイアログのアクティビティ

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>

style:

<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>

以下に、この完全なコードを示します

4
V.March

現在のアクティブなアクティビティの上に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ファイルに追加の権限は必要ありません。

1
Derorrist

バックグラウンドで実行されているネットワークタスクの種類。おそらくデザインを再考することをお勧めします。おそらく、通知の方が良いでしょうか?または、「結果の概要」画面。ユーザーとして、タスクの完了を積極的に待機していない場合は、邪魔にならないエラーのシグナルを送信します。

0
px3j

次のように、ダイアログがアタッチされたウィンドウのタイプをリセットする必要があります:dialog.getWindow()。setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

マニフェストで「Android.permission.SYSTEM_ALERT_WINDOW」権限を宣言することを忘れないでください。

0
hopetribe

私も問題に直面しています。シンプルで効果的なソリューションを見つけました。通常、一般的なロジックの処理に使用される基本アクティビティがあります。これがあります:

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
Victor Choy

イベントバスを使用しないのはなぜですか( 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
Allen Chan