web-dev-qa-db-ja.com

Android:ダイアログからのユーザー入力を待機しますか?

ダイアログを表示し、ダイアログが閉じられるまで待機し、ダイアログの内容に応じて結果を返すメソッドを実装したいと思います。これは可能ですか?

_public String getUserInput()
{
    //do something to show dialog
    String input = //get input from dialog
    return input;
}
_

私は実際に、メソッド「public String getUserInput()」を持つインターフェイスを実装しようとしています。このメソッドでは、返された文字列をダイアログ経由で取得する必要があります。これはJavaで簡単にできますが、Androidでは不可能ですか?

編集:コメントで要求されたいくつかのサンプルコードの投稿

getInput()は、バックグラウンドスレッドから呼び出す必要があります(AsynchTaskから呼び出します)。 getInput()はダイアログを表示し、waitを呼び出します。ダイアログで[ok]ボタンを押すと、ダイアログはメンバー変数にユーザー入力を設定し、通知を呼び出します。 notifyが呼び出されると、getInput()は続行し、メンバー変数を返します。

_String m_Input;

public synchronized String getInput()
{
    runOnUiThread(new Runnable() 
    {
        @Override
        public void run() 
        {
            AlertDialog.Builder alert = new AlertDialog.Builder(context);
            //customize alert dialog to allow desired input
            alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton)
            {
                          m_Input = alert.getCustomInput();
                          notify();
            }
        });
        alert.show();   
        }
    });

    try 
    {
         wait();
    } 
    catch (InterruptedException e) 
    {
    }

    return m_Input;
}
_
37
ab11

すべてのフィードバックのおかげで、wait()とnotify()とともにバックグラウンドスレッドを使用してこれを解決できました。私はこれが与えられたパラダイムの最大のアイデアではないことを認識していますが、私が作業しているライブラリに準拠する必要がありました。

11
ab11

これは可能ですか?

いいえ。AndroidにはブロッキングUIモデルはありません。すべてが非同期です。

[〜#〜] update [〜#〜]

質問自体に対するいくつかのコメントに対して、バックグラウンドスレッドからUIを表示することはできません。この回答で書いたように、AndroidにはブロッキングUIモデルはありません。 このサンプルプロジェクト のように、ダイアログが受け入れられたときに実行するダイアログのボタンハンドラーにコードを配置するだけです。

31
CommonsWare

これを行う正しい方法は、イベント駆動型のプログラムモデル、つまり「電話しないで、電話します」です。

単純なコンソールモードプログラミングでは、コードはブロッキング入力関数を呼び出す傾向があり、値を取得するまで戻りません。

多くのGUIプログラミング環境の動作は異なります-コードは通常実行されていませんが、代わりに、潜在的な関心が発生したときにオペレーティングシステム/ウィンドウマネージャーによって呼び出されます。あなたはこれに応じて何かをして、すぐに戻ります-そうしないと、戻るまでOSがあなたに連絡する方法がないので、他に何も通知されません。 (win32と比較すると、メッセージループがAndroidによって実装されているように見え、メッセージループがイベントで呼び出すコードの残りの部分のみを記述できます-すぐに戻らないと、メッセージループがハングします)

その結果、プログラムフローの概念を再考する必要があります。 To Doリストを単純な一連のステートメントとして書き出すのではなく、相互に依存し入力に依存する一連のアクションと考えてください。状態変数で現在実行しているアクションを覚えておいてください。ユーザー入力などのイベントで呼び出された場合、そのイベントが次のステップに進むことができることを意味するかどうかを確認し、もしそうであれば、次を受け取ることができるようにOSにすぐに戻る前に状態変数を更新しますイベント。イベントが必要なものではなかった場合は、状態を更新せずに戻ります。

このモデルが機能しない場合は、ブロック入力を使用してコンソールモードアプリケーションのように実行されるプログラムロジックのバックグラウンドスレッドを作成します。しかし、入力関数は実際には、フラグまたは何かが入力されることを通知されるのを待つだけです。次に、UIスレッドでAndroidイベントを配信すると、フラグを更新してすぐに戻ります。バックグラウンドスレッドは、データが提供されたことを示すフラグが変更されたことを確認し、実行を継続します。 an Androidターミナルエミュレーターはこれを極端に処理します。バックグラウンドコンポーネントは実際には別のプロセス(コンソールモードLinuxプロセス)であり、パイプからのI/Oをブロックする可能性を使用して入力を取得します。 JavaコンポーネントはAndroid UIイベントを受け入れ、文字をstdinパイプに詰め込み、stdoutパイプから引き出して画面に表示します。)

12
Chris Stratton

これまでに提供されたすべてのソリューションを理解するのに苦労したので、自分のソリューションを見つけました。

次のように、ユーザー入力が実行可能ファイルでOKになった後に実行されるはずのコードをラップします。

    Runnable rOpenFile = new Runnable() {
        @Override
        public void run() {
            .... code to perform
        }
    }

次に、そのすぐ下で、実行可能な関数の名前をユーザーダイアログメソッドに渡します。

    userInput("Open File", rOpenFile);

UserInputメソッドは、上記のようにalertDialogビルダーに基づいています。ユーザー入力が承認されると、目的の実行可能ファイルが開始されます。

private void userInput(String sTitle, final Runnable func) {
    AlertDialog.Builder aBuilder = new AlertDialog.Builder(this);

    aBuilder.setTitle(sTitle);
    final EditText input = new EditText(this);
    input.setInputType(InputType.TYPE_CLASS_TEXT);
    aBuilder.setView(input);

    bDialogDone = false;

    aBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            final String sText = input.getText().toString();
            sEingabe = sText;
            func.run();
        }
    });
    aBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
            sEingabe = "";
        }
    });

    aBuilder.show();
}
5
Skandalos

このような何かがするだろう

/**
 *
 */

import Android.app.Activity;
import Android.content.Intent;
import Android.os.Bundle;
import Android.view.View;
import Android.view.WindowManager;
import Android.view.View.OnClickListener;
import Android.widget.Button;
import Android.widget.EditText;

/**
 * @author 
 */
public class TextEntryActivity extends Activity {
    private EditText et;

    /*
     * (non-Javadoc)
     * @see Android.app.Activity#onCreate(Android.os.Bundle)
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_text_entry);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        // title
        try {
            String s = getIntent().getExtras().getString("title");
            if (s.length() > 0) {
                this.setTitle(s);
            }
        } catch (Exception e) {
        }
        // value

        try {
            et = ((EditText) findViewById(R.id.txtValue));
            et.setText(getIntent().getExtras().getString("value"));
        } catch (Exception e) {
        }
        // button
        ((Button) findViewById(R.id.btnDone)).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                executeDone();
            }
        });
    }

    /* (non-Javadoc)
     * @see Android.app.Activity#onBackPressed()
     */
    @Override
    public void onBackPressed() {
        executeDone();
        super.onBackPressed();
    }

    /**
     *
     */
    private void executeDone() {
        Intent resultIntent = new Intent();
        resultIntent.putExtra("value", TextEntryActivity.this.et.getText().toString());
        setResult(Activity.RESULT_OK, resultIntent);
        finish();
    }


}

打ち上げは次のとおりです。

public void launchPreferedNameEdit() {
    Intent foo = new Intent(this, TextEntryActivity.class);
    foo.putExtra("value", objItem.getPreferedNickname());
    this.startActivityForResult(foo, EDIT_PREFERED_NAME);
}

を使用して結果を取得します

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case EDIT_PREFERED_NAME:
            try {
                String value = data.getStringExtra("value");
                if (value != null && value.length() > 0) {

                }
            } catch (Exception e) {
            }
            break;
        default:
            break;
    }
}
1
Pentium10

ステートマシンの観点から考えると、最初のユーザー入力が最初に必要な場合は、「ユーザー入力が必要」などを示すフラグを設定できます。次に、イベントの処理時にそのフラグをチェックし、設定されている場合は、イベントに対する唯一のアクションとしてダイアログを起動し、フラグを設定解除します。次に、ユーザー入力を処理した後のダイアログイベントハンドラーから、ダイアログが不要な場合に通常意図されているコードを呼び出すことができます。

ケース:設定変更リスナーイベントの後、データをプロセスする準備ができており、ユーザーから照会された文字列を追加する必要がありました。オプションメニューが開いているときにアラートダイアログを表示することはできないようです。そのため、待つ必要がありました。ワークフロー内の次のアクティビティに完全な半分のオブジェクトを投げ、そのonResume()を設定してプレースホルダーがnullであるかどうかを確認します。その場合、ダイアログをポップしてオブジェクトを完成させました* "ダイアログのハンドラー"*

これは私の最初の投稿であるため、上記の正しい答えに投票することはできませんが、これにぶつかる他の人を救いたいと思っています。ダイアログは場所です。

0
user816728