2

Android プログラミングについて質問があります。以下のコードを使用して、文字列の一致を検証します。正常に検証されますが、LogCat は TextWatcher メソッドがキーストロークごとに 2 回起動していることを示しており、その理由がわかりません。キーストロークごとに1回だけ発火したいと思います。

なぜこれをしているのか知っていますか?

テキストの色を変更したためだと思いましたが、コメントアウトしても違いはありませんでした。

LogCat 出力

03-31 03:37:25.269: I/BeforeText(676): Hit 
03-31 03:37:25.269: I/OnText(676): Hit
03-31 03:37:25.269: I/AfterText(676): Hit
03-31 03:37:25.274: I/InvalidText(676): Incorrect Text.
03-31 03:37:25.274: I/Text Value(676): a
03-31 03:37:25.404: I/BeforeText(676): Hit
03-31 03:37:25.404: I/OnText(676): Hit
03-31 03:37:25.404: I/AfterText(676): Hit
03-31 03:37:25.404: I/InvalidText(676): Incorrect Text.
03-31 03:37:25.404: I/Text Value(676): a

活動コード

public void onCreate(Bundle savedInstanceState) {

     //...omitted

    //Create Answer Field
    textField = (EditText)this.findViewById(R.id.textField);

    //Add validation to TextField
    textField.addTextChangedListener(new TextWatcher(){
        public void afterTextChanged(Editable s){

            Log.i("AfterText","Hit");

            if(textField.getText().toString().trim().equalsIgnoreCase("hello")){
                Log.i("ValidText", "Text matched.");

                answerField.setTextColor(Color.GREEN);

            }
            else{
                Log.i("InvalidText", "Incorrect text.");
                Log.i("Text Value", textField.getText().toString());

                textField.setTextColor(Color.RED);

            }
        }

        public void beforeTextChanged(CharSequence s, int start, int count, int after){
            //Do nothing
            Log.i("BeforeText", "Hit");
        }

        public void onTextChanged(CharSequence s, int start, int before, int count){
            //Do nothing
            Log.i("OnText","Hit");

        }
    });
}
4

5 に答える 5

3

あなたの質問は、キーストロークごとに TextWatcher メソッドが 2 回起動しているためです。Validate String の EditText の Make watch に TextWather を使用し、 Color を設定しました。

ここの開発者サイトで TextWatcher のドキュメントを参照できます。http://developer.android.com/reference/android/text/TextWatcher.html

キーストアを押すと、EditText テキストが変更され、TextWatcher メソッドがonTextChanged呼び出されます。EditText メソッドの任意のキーを押すと、EditText のbeforeTextChanged編集を開始するときに呼び出されます。

EditText に 1 文字を入力すると、この 3 つのメソッドがすべて呼び出されますTextwather。Call のシーケンスが異なります。また、この SO Question Android TextWatcher.afterTextChanged と TextWatcher.onTextChanged を参照してください。

そのため、EditText で Text Change を 2 回呼び出しても問題はありません。

理解していただければ幸いです。

于 2012-03-31T05:36:17.797 に答える
1

これでお役に立てるかどうかはわかりませんが、私の場合はスワイプ キーボードのようです。

ポイントは、スワイプが提案を行おうとすると、onchange メソッドが 2 回呼び出されるように見えることです (1 つは EditText から、もう 1 つはスワイプ キーボードから)。

これがあなたのコードで実行可能かどうかはわかりませんが、EditText でこれを試して、何が起こるかを確認してください。

android:inputType="textNoSuggestions"

この問題について話している次のサイトを確認できます。

http://support.swiftkey.net/forums/116693-2-bug-reports/suggestions/2994580-span-exclusive-exclusive-spans-cannot-have-a-zero-

解決策が見つかったら、この回答を編集します。


編集


私の結論は、中間イベントを回避することはできず、ユーザーからの実際の変更イベントとスワイプ変更イベントを区別できないということです。

実際の問題に応じて、別の回避策を試す必要があります。回避策の 1 つは、更新された情報を ConcurrentHashMap に保存し、イベントを受信して​​から 100 ミリ秒後にタスクをスケジュールすることです。同時に、「lastModified」日付を設定する必要があります。

スケジュールされたタスクでは、「前回の更新から 100 ミリ秒経過しましたか?」と尋ねて、答えが「いいえ」の場合 --> 何もしません (これは、別のイベントが到着したため、最後の値で別の更新タスクが実行されることを意味します)。

すべてに ReentrantLock を付けて原子性を実現します。

このようなもの:

   private final ReentrantLock lock = new ReentrantLock();
    private final ScheduledExecutorService scheduleExecutor = new ScheduledThreadPoolExecutor(1);
    private Date lastModification = null;
    private static final long UPDATE_WINDOW_IN_MILLISECONDS = 100;

protected class UpdateBusinessLogicTask implements Runnable {
    private final String newVal;

    public UpdateBusinessLogicTask(String newVal) {
        super();
        this.newVal = newVal;
    }

    @Override
    public void run() {

        //check current date
        Date now = new Date();
        //get lock to achieve atomicity 
        lock.lock();

        // calculate elapsed time
        long elapsedTime = lastModification.getTime() - now.getTime();

        // free the lock --> you could free the lock after business logic, depends on your scenario
        lock.unlock();

        //if the time is less than the updating window (100 milliseconds)
        if (elapsedTime < (UPDATE_WINDOW_IN_MILLISECONDS - 1)) {
            // DO NOTHING!!
            Log.d("TEST", "Dismiss update "+newVal);
        } else {
            Log.d("TEST", "Updating business with newVal: "+newVal);
            // TODO implement business logic
        }

    }
};

protected void onCreate(Bundle savedInstanceState) {

    EditText view = findViewById(R.id.nameEditText);

    TextWatcher tw = new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            Log.d("TEST", "New text event received, new val: " + s.toString());

            lock.lock();
            lastModification = new Date();

            scheduleExecutor.schedule(new UpdateBusinessLogicTask(s.toString()), UPDATE_WINDOW_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
            lock.unlock();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    };

}
于 2014-01-27T21:40:57.273 に答える
0

ブール値を使用できます。ユーザーがテキストを変更したときに設定し、カスタムコードが起動したときにリセットします。イベントは引き続き2回発生しますが、コードは1回だけ呼び出されます。よろしくお願いします。

于 2012-03-31T06:46:01.787 に答える