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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

2回答

1363閲覧

RecyclerViewの中のEditText、IME_ACTION_NEXTでsetOnEditorActionListener、setOnFocusChangeListener 両方動いてしまう

退会済みユーザー

退会済みユーザー

総合スコア0

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2022/11/01 08:31

前提

Android+kotlinでRecyclerViewの中にEditTextがあるアプリを作っています。
よくある、Excelのような表形式のイメージで、EditTextに値を入力し、DB(Room)を更新するようなアプリです。

DBの更新のきっかけとしてはキーパットのIME_ACTION_NEXTで次の行(EditText)に移る場合、
EditTextからフォカスが外れる場合(タップで他の行に移動する場合)
があります。

どちらも、EditTextに入力した数値をDB(Room)に更新しに行きます。

ここでキーパットのIME_ACTION_NEXTの時に、EditTextのイベントハンドラ、
setOnEditorActionListener
setOnFocusChangeListener
の両方が動いてしまいます。

EditTextからフォカスが外れる場合(タップで他の行に移動する場合)は
setOnFocusChangeListener
しか動きません。

今回はどっちしても、同じ値(EditTextの入力値)でDBを更新しにいくので、キーパットのIME_ACTION_NEXTの時は、同じSQLのUPDATE文を2回実行しているだけなので、まー、多少は無駄ですが、動作には大きな影響はありません。
が、しかし、これが+1カウントアップするような処理だと困ってしまいます。キーパットのIME_ACTION_NEXTの時は2回、カウントアップされてしまいます。

実現したいこと

キーパットのIME_ACTION_NEXTの時に
setOnEditorActionListenerだけ
setOnFocusChangeListeneは呼ばないようにする方法はないのでしょうか。

一般的に、RecyclerViewの中にEditTextがあるExcelの表形式のようなものを実現したいとしたら、どのようにすればよいのでしょうか?
EditTextからフォカスが外れる(タップで他の行に移動できる)というのが、処理をややこしくしているのですが、これをできないようにする方策はなんかあるのでしょうか?

補足情報(FW/ツールのバージョンなど)

AndroidStudio Dolphine 2021.3.1 patch1
Kotlin 1.7.20

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/11/01 09:13 編集

一応分かるのでちょっとした書き方の問題ですが、 >EditTextのイベントハンドラ、 >setOnEditorActionListener >setOnFocusChangeListener set~ はイベントハンドラではありません。イベントハンドラを登録するメソッドです。 イベントハンドラはそのパラメータになっている方ですので、 OnEditorActionListener とか OnFocusChangeListener といった書き方になります。 また、 >キーパットのIME_ACTION_NEXTの時に >setOnEditorActionListenerだけ >setOnFocusChangeListeneは呼ばないようにする イベントは発生した時に呼ばれるのは、イベントハンドラのメソッドですので、そのイベントハンドラのメソッドの方を書かれたほうが良いです。
退会済みユーザー

退会済みユーザー

2022/11/01 09:14

ご指摘の通りですkotlinだと、lambdaで、 XXX.setOnFocusChangeListener { ・・・ } XXX.setOnEditorActionListener{ 。。。 } という書き方をするので、そのまま書いてしまいましたが、意図しているのはご指摘の通りです
jimbe

2022/11/01 09:25

問題を再現できる実際に動作するコード(DBの更新部分はログ表示等で構いません)はご提示頂くことは可能でしょうか。
guest

回答2

0

ベストアンサー

なるほど、View#getTag()、View#setTag(Object)を使って比較しますか・・・

それもそうなんですが、自分で気が付いてしまいました。
ここでキーパットのIME_ACTION_NEXTの時に、EditTextのイベントハンドラ、
OnEditorActionListener
OnFocusChangeListener
の両方が呼ばれる。

EditTextからフォカスが外れる場合(タップで他の行に移動する場合)は
OnFocusChangeListener
が呼ばれる。

両方のハンドラからDB更新しにくからIME_ACTION_NEXTの時に2回更新されるので、どっちの道、OnFocusChangeListenerは必ず呼ばれる。
IME_ACTION_NEXTの時に次の行のEditTextにフォーカスを移すという制御やっているので、その時、OnFocusChangeListenerは呼ばれる。

なのでDB更新はOnFocusChangeListenerだけでやればうまくいくということがわかりました。

投稿2022/11/01 12:18

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/11/01 12:28

私の回答で setTag/getTag を用いているのは、 ViewHolder でリスナを登録しているからです。onBindViewHolder で登録するようにすれば item が使えますので setTag/getTag は必要ありません。
guest

0

EditText の更新を DB に反映するということだけから見れば、更新のトリガが発生したら実際に更新されていようがいまいが更新をかけるのでは無く、 EditText の値が実際に更新されていた場合にのみ DB を更新するようにすれば、そのチェックのトリガは連続して何度あったとしても更新は一回で済むのではないでしょうか。
もし更新回数をカウントアップしているということであれば、これも実際に更新した時だけカウントアップすれば、問題無いように思います。

以下 java ですが、アクション、フォーカスが発生しても、更新されている場合のみ UPDATE が出ると思います。

MainActivity.java

java

1import androidx.annotation.NonNull; 2import androidx.appcompat.app.AppCompatActivity; 3import androidx.recyclerview.widget.RecyclerView; 4 5import android.os.Bundle; 6import android.util.Log; 7import android.view.*; 8import android.widget.EditText; 9 10import java.util.*; 11 12public class MainActivity extends AppCompatActivity { 13 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.activity_main); 18 19 RecyclerView recyclerView = findViewById(R.id.recyclerView); 20 recyclerView.setAdapter(new Adapter()); 21 } 22 23 private static class Item { 24 final long id; 25 final String text; 26 Item(long id, String text) { 27 this.id = id; 28 this.text = text; 29 } 30 @Override 31 public String toString() { 32 return super.toString() + "[id=" + id + ", text='" + text + "']"; 33 } 34 } 35 36 private static class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> { 37 class ViewHolder extends RecyclerView.ViewHolder { 38 final EditText editText; 39 public ViewHolder(@NonNull View itemView) { 40 super(itemView); 41 editText = itemView.findViewById(R.id.editText); 42 editText.setOnEditorActionListener((v, actionId, event) -> { 43 if(actionId != EditorInfo.IME_ACTION_NEXT) return false; 44 Item item = (Item)editText.getTag(); 45 String text = editText.getText().toString(); 46 Log.d("Adapter **", "OnEditorActionListener. orig=" + item + ", new text=" + text); 47 update(item, text); 48 return true; 49 }); 50 editText.setOnFocusChangeListener((v, hasFocus) -> { 51 if(hasFocus) return; 52 Item item = (Item)editText.getTag(); 53 String text = editText.getText().toString(); 54 Log.d("Adapter **", "OnFocusChangeListener. orig=" + item + ", new text=" + text); 55 update(item, text); 56 }); 57 } 58 } 59 60 private List<Item> itemList = new ArrayList<>(); 61 62 Adapter() { 63 //テストデータ 64 itemList.add(new Item(1, "ABC")); 65 itemList.add(new Item(2, "DEF")); 66 itemList.add(new Item(3, "GHI")); 67 itemList.add(new Item(4, "JKL")); 68 } 69 70 private void update(Item item, String text) { 71 if(item.text.equals(text)) return; 72 73 Log.d("Adapter **", "UPDATE table (text) VALUES ('" + text + "') WHERE id=" + item.id); 74 75 int index = itemList.indexOf(item); 76 itemList.set(index, new Item(item.id, text)); 77 notifyItemChanged(index); 78 } 79 80 @NonNull 81 @Override 82 public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 83 return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false)); 84 } 85 86 @Override 87 public void onBindViewHolder(@NonNull ViewHolder holder, int position) { 88 Item item = itemList.get(position); 89 holder.editText.setTag(item); 90 holder.editText.setText(item.text); 91 } 92 93 @Override 94 public int getItemCount() { 95 return itemList.size(); 96 } 97 } 98}

res/layout/activity_main.xml

xml

1<?xml version="1.0" encoding="utf-8"?> 2<androidx.recyclerview.widget.RecyclerView 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:tools="http://schemas.android.com/tools" 5 xmlns:app="http://schemas.android.com/apk/res-auto" 6 tools:context=".MainActivity" 7 android:id="@+id/recyclerView" 8 android:layout_width="match_parent" 9 android:layout_height="match_parent" 10 app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

res/layout/item.xml

xml

1<?xml version="1.0" encoding="utf-8"?> 2<EditText 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:id="@+id/editText" 5 android:layout_width="match_parent" 6 android:layout_height="wrap_content" />

投稿2022/11/01 09:31

編集2022/11/06 04:58
jimbe

総合スコア12632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問