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

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

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

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

Android Studio

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

Kotlin

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

解決済

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

lonelyRider
lonelyRider

総合スコア24

Android

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

Android Studio

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

Kotlin

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

2回答

0グッド

0クリップ

221閲覧

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

以下のような質問にはグッドを送りましょう

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

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

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

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

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

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

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

適切な質問に修正を依頼しましょう。

jimbe

2022/11/01 09:13 編集

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

2022/11/01 09:14

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

2022/11/01 09:25

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

回答2

1

自己解決

なるほど、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

lonelyRider

総合スコア24

jimbe😄を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

回答へのコメント

jimbe

2022/11/01 12:28

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

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

総合スコア10748

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

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

Android

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

Android Studio

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

Kotlin

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