質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

androidのdialogの表示方法について

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 6,285

RNagamatsu

score 13

着信が入った時にダイアログを表示するアプリを作っていまして、素人ながらもいろいろなサイトを参考にしながらそれなりに形にはなっているのですが、ダイアログの表示でもう1か月以上滞っていて、ヒントだけでも頂けると助かります。

着信の状態を捕捉するクラス(PhoneReceiver.class)を下の様に作っていまして、着信が入ると

                    AlertDialog.Builder builder = new AlertDialog.Builder(context);
                    builder.setMessage(R.string.dialog_message)
                            .setTitle(R.string.dialog_title)
                            .setPositiveButton(R.string.dialog_button, null)
                            .setView(layout);
                    builder.show();


という形でAlertDialogを表示させようとしましたが、アプリが強制終了します。
PhoneReceiverクラスがActivityクラスじゃないということが理由なのだろうと思いつつも、具体的な解決策を出せないでいます。
androidの公式サイトを見れば、DialogFragmentを推奨されていたので、同様にPhoneReceiverクラスがActivityでもFragmentクラスでもないために表示されないものと思います。

仕方がないので、他のサイトを参考にして下のようにToastをカスタマイズして、表示時間の延長、ボタンの追加等をしたのですが、納得ができないでいます。
popupWindowも試してみたのですが、これもうまくいきませんでした。

ですので、元のとおり、AlertDialogを表示する方法、ヒント等ありましたら、教えていただきたく質問いたします。
PhoneReceiverのコードは下に記載しています。
それとも根本的にやり方を変えた方がよいのでしょうか。

※捕捉1
あるサイトでこのような解決方法を見つけたのですが、

    public void showWarningAlert(Context context) { //Added argument
        AlertDialog alertDialog = new AlertDialog.Builder(context).create(); //Use context
        alertDialog.setTitle("Warning");
        alertDialog.setMessage("You are currently in a battle");
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        alertDialog.show();
    }


結局アプリは強制終了する状態です。alertDialog.show()のところでエラーが出ています。

※捕捉2
Logcatの内容です。PhoneReceiverに青文字がついています。

05-11 09:13:42.101 26582-26582/com.example.ma2ri.newstage E/AndroidRuntime: FATAL EXCEPTION: main
                                                                            Process: com.example.ma2ri.newstage, PID: 26582
                                                                            java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
                                                                                at android.support.v7.app.AppCompatDelegateImplV7.createSubDecor(AppCompatDelegateImplV7.java:343)
                                                                                at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:312)
                                                                                at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:277)
                                                                                at android.support.v7.app.AppCompatDialog.setContentView(AppCompatDialog.java:80)
                                                                                at android.support.v7.app.AlertController.installContent(AlertController.java:214)
                                                                                at android.support.v7.app.AlertDialog.onCreate(AlertDialog.java:256)
                                                                                at android.app.Dialog.dispatchOnCreate(Dialog.java:578)
                                                                                at android.app.Dialog.show(Dialog.java:314)
                                                                                at com.example.ma2ri.newstage.PhoneReceiver.showWarningAlert(PhoneReceiver.java:173)
                                                                                at com.example.ma2ri.newstage.PhoneReceiver.onCallStateChanged(PhoneReceiver.java:60)
                                                                                at android.telephony.PhoneStateListener$1.handleMessage(PhoneStateListener.java:323)
                                                                                at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                at android.os.Looper.loop(Looper.java:158)
                                                                                at android.app.ActivityThread.main(ActivityThread.java:7237)
                                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
  class PhoneReceiver extends PhoneStateListener {
    private int totalCount = 0;
    private Context context;
    Intent intent;
    TextView textView;
    ToastCustom toastCustom;
    View view;
    PhoneReceiver(Context context) {
        this.context = context;
    }

    public void onCallStateChanged(int state, String incomingNumber) {
        super.onCallStateChanged(state, incomingNumber);

        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:

                Cursor addressTable = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
                if (addressTable != null) {
                    while (addressTable.moveToNext()) {
                        String phoneNumber = addressTable.getString(addressTable.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        for (int i = 0; i < addressTable.getCount(); i++) {
                            int count = BooleanSum(PhoneNumberUtils.compare(phoneNumber, incomingNumber));
                            totalCount += count;
                        }
                    }
                    addressTable.close();
                }
                if (totalCount >= 1) {

                    /*
                    final LayoutInflater inflater = (LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
                    final View layout = inflater.inflate(R.layout.toast_layout, null);
                    final TextView textView = (TextView) layout.findViewById(R.id.text);
                    textView.setText(R.string.alert);

                    final  Toast toast = new Toast(context.getApplicationContext());
                    toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
                    toast.setDuration(Toast.LENGTH_LONG);
                    toast.setView(layout);
                    toast.show();
                    */

                    CustomToast.makeText(context).show();

                }
                break;

            case TelephonyManager.CALL_STATE_OFFHOOK:
                Toast.makeText(context, R.string.off_hook + incomingNumber, Toast.LENGTH_LONG).show();
                break;
        }
    }

    private int BooleanSum(Boolean exchanger) {
        if (exchanger) return 1;
        else {
            return 0;
        }
    }


_

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • swordone

    2017/05/10 23:58

    まず、コードをマークダウンしてください。質問編集画面でコード部分を反転選択して<code>を押すとコードが読みやすくなります。第2に、強制終了時のログを掲載してください。

    キャンセル

  • RNagamatsu

    2017/05/11 09:52

    返信が遅くなり、申し訳ありません。コードを編集し、ログも掲載しました。

    キャンセル

回答 3

checkベストアンサー

+1

DialogFragmentやAlertDialogはActivity上で表示させる必要があります。
そのため、PhoneReceiverがService内や単体のBroadcastReceiverであれば、Activityを表示させてそこからDialogを表示させる流れになるかと思います。

Activity側ですが、
半透明なActivityを用意しそこからDialogを表示させる。
Activity自体の表示をDialogにして表示する。
といった方法があります。

いずれの方法もStyle(Theme)で設定する事ができます(下部に記載)。
半透明なActivity方法であれば、Theme.Translucentといった半透明用のThemeが用意されていますので簡単です。ただAppCompatのThemeで透明にしたい場合はThemeが用意されていないためStyleを自作する必要があります。
*確認してないのでわかりませんが、最近のライブラリバージョンでは用意されてるやもしれません。

なお、この半透明なActivityでの方法の場合は回転時の対応に注意してください。
onCreateやonStart等のタイミングで単純にDialogFragmentをshowしていると回転の度にDialogが重複されていくかと思います。FragmentManager等で確認してすでに表示されているのであれば表示しないようにする必要があります。あとはDialogを閉じるタイミングでfinishしActivityも閉じるだけです。

最後にいくつかThemeも記載しておきます。
参考になれば幸いです。

AppCompatな半透明用Theme。

<!-- parentを利用するTheme.AppCompatに変更する事でDark等に変更可-->
<style name="Theme.AppCompat.Translucent" parent="Base.Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorAccent">@color/colorAccent</item>

    <!-- 完全に半透明にする場合は通知バー部分の色も透明にする-->
    <item name="colorPrimaryDark">@android:color/transparent</item>
</style>

ActivityをAppCompatなDialog表示にする。

<!-- Lightにする場合はparentをTheme.AppCompat.Light.Dialog.Alertにする-->
<style name="Theme.AppCompat.DialogActivity" parent="Theme.AppCompat.Dialog.Alert">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/13 00:19

    丁寧な説明ありがとうございます。

    すぐにチャレンジしたいのですが、まだ職場ですので明日頑張ってみます。

    キャンセル

  • 2017/05/13 14:57

    まだ、エラーが出てアクティビティを立ち上げることはできないのですが、やり方は教えていただきましたので、頑張ってみます。ありがとうございました。

    キャンセル

  • 2017/05/13 15:32

    エラーの内容が分からないのでなんとも言えませんが、別の回答にコメントされているような、
    You need to use a Theme.AppCompat theme (or descendant) with this activity.
    といったエラーであれば該当ActivityがThemeがTheme.AppCompat を継承したものでないと言われているようです。AppCompatActivityであればTheme.AppCompatを継承したものを適応する必要があります。
    参考まで。

    キャンセル

+1

Reciverクラスから適当なActivityを起動し、Activityの中でAlertDialogを表示するとできそうですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/11 12:43

     ありがとうございます。そのような考え方は思いつきませんでした。

     MyDialogというクラスを新たにつくって、その中でAlertDialogを表示するようにして、ReceiverクラスからMyDialogを起動させるようにしたのですが・・・
           パターン①
    Intent i = new Intent(context.getApplicationContext(), MyDialog.class);
    context.startActivity(i);

           パターン②
    Intent i = new Intent();
    i.setClassName("com.example.ma2ri.newstage", "com.example.ma2ri.newstage.MyDialog");
    context.startActivity(i);

           パターン③
    Intent i = new Intent(context, MyDialog.class);
    context.startActivity(i);

           パターン④
    Intent i = new Intent(activityContext, MyDialog.class);
    activityContext.startActivity(i);
    と試したのですが、いずれも最後の行で
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
    at com.example.ma2ri.newstage.PhoneReceiver.onCallStateChanged(PhoneReceiver.java:77)
    このようなエラーが出てしまいます。
     よろしかったら、もう少しだけヒントを頂けると幸いです。

    キャンセル

  • 2017/05/11 12:55

    その部分だけでは判断できません。
    前後数行を記載してください。

    キャンセル

  • 2017/05/11 13:11

    失礼しました。Receiverクラスのswitch文の中に、
    Intent i = new Intent(context.getApplicationContext(), MyDialog.class);
    context.startActivity(i);
    と、下のように記述しました。読みづらいかと思いますが、体裁を整えられないようなのですみません。
    class PhoneReceiver extends PhoneStateListener {
    private Context context;
    Intent intent;
    PhoneReceiver(Context context) {
    this.context = context;
    }

    public void onCallStateChanged(int state, String incomingNumber) {
    super.onCallStateChanged(state, incomingNumber);

    switch (state) {
    case TelephonyManager.CALL_STATE_RINGING:
    if (totalCount >= 1) {

    Intent i = new Intent(context.getApplicationContext(), MyDialog.class);
    context.startActivity(i);

    }
    break;

    case TelephonyManager.CALL_STATE_OFFHOOK:
    //省略
    break;
    }
    }

    private int BooleanSum(Boolean exchanger) {
    //省略
    }

    エラーはこのようになっています。
    android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
    at android.app.ContextImpl.startActivity(ContextImpl.java:734)
    at android.app.ContextImpl.startActivity(ContextImpl.java:721)
    at android.content.ContextWrapper.startActivity(ContextWrapper.java:345)
    at android.content.ContextWrapper.startActivity(ContextWrapper.java:345)
    at com.example.ma2ri.newstage.PhoneReceiver.onCallStateChanged(PhoneReceiver.java:67)
    at android.telephony.PhoneStateListener$1.handleMessage(PhoneStateListener.java:323)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:158)
    at android.app.ActivityThread.main(ActivityThread.java:7237)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

    キャンセル

  • 2017/05/11 13:15 編集

    何度もすみません。

    Intent i = new Intent(context.getApplicationContext(), MyDialog.class);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.getApplicationContext().startActivity(i);

    このようにすると一度だけMyDialogクラスを呼び出せましたが、その後はずっとエラーです。

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ma2ri.newstage/com.example.ma2ri.newstage.MyDialog}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3254)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)
    at android.app.ActivityThread.access$1100(ActivityThread.java:222)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:158)
    at android.app.ActivityThread.main(ActivityThread.java:7237)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
    Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
    at android.support.v7.app.AppCompatDelegateImplV7.createSubDecor(AppCompatDelegateImplV7.java:343)
    at android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(AppCompatDelegateImplV7.java:312)
    at android.support.v7.app.AppCompatDelegateImplV7.onPostCreate(AppCompatDelegateImplV7.java:167)
    at android.support.v7.app.AppCompatActivity.onPostCreate(AppCompatActivity.java:98)
    at android.app.Instrumentation.callActivityOnPostCreate(Instrumentation.java:1216)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3236)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350) 
    at android.app.ActivityThread.access$1100(ActivityThread.java:222) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:158) 
    at android.app.ActivityThread.main(ActivityThread.java:7237) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 

    MyDialogのDialog自体も調子が悪いようです。

    public class MyDialog extends AppCompatActivity {

    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);



    AlertDialog.Builder alert = new AlertDialog.Builder(MyDialog.this);
    alert.setTitle("title")
    .setMessage("message")
    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    MyDialog.this.finish();
    }
    });
    alert.create().show();

    }
    }

    キャンセル

+1

Reciverクラスで例えば以下のようにAcitivtyを取得し、そのActivity内でダイアログ表示処理を行うと上手くいくかもしれません。

MainActivity ma = (MainActivity) this.getContext();
ma.testest();

MainActivityクラスのtestest()

public void testest(){
DialogFragment dialog = new test_Dialog();       
dialog.show(getFragmentManager(), "test_dialog");
}

拙いコードですが参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/11 12:54

    回答ありがとうございます。
    MainActivityクラスでtestest()を記述することはできたのですが、ReceiverクラスでgetContext()の部分だけ赤字になって失敗してしまいます。
    もう少し試してみます。

    キャンセル

  • 2017/05/12 21:24

    お力になれずすみません。
    がんばってください!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る