RecyclerView上のボタンを押した時の処理をリストごとに変化させる

#はじめに
Androidアプリ開発でリスト表示を作るためにRecyclerViewを利用しますよね。
RecyclerView上にボタンを設置して、リストから他の画面に遷移する時、**何番目のリストのボタンが押されたか**を知りたい時ありますよね。
RecyclerView.Adapter上で「何番目のボタンが押されたか」は割とすぐ取得できるのですが、それをMainActivityで使う時に少しハマったのでメモ。

#RecyclerViewについて
概要についてはこちらの記事が分かりやすかったのでこちらを参照ください。
[RecyclerViewの基本](https://qiita.com/naoi/items/f8a19d6278147e98bbc2)

#やりたいこと
- RecyclerView上にボタンを配置し、ボタンを押した時に画面遷移させたい。
- ボタンを押したリストの行数によって遷移先での挙動を変化させたい。

画面遷移する時のボタンを押した時の処理のイメージはこんな感じ。
遷移先の画面に対して、何番目のリストのボタンが押されたかを教えてあげたい

ちなみにRecyclerView.AdapterはActivtyクラスを継承していないので画面遷移ができません。
そのため、MainActivity上で何番目のリストが押されたかを知り、画面遷移することが必要になります。

```java:MainActivity
@Override                                                                             
public void onClick(View view) {                                                      
    int line = getLine(); //どうにかして押したリストの行数を取得したい                             
    Intent hoge = new Intent(MainActivity.this, HogeActivity.class);
    hoge.putExtra("line", line);                   
    startActivity(hoge);                                                              
}    
```

#まずその前に
RecyclerViewに含まれるボタンを押した時に、MainActivity上での処理を行いたいので
RecyclerView.AdapterのリスナーにMainActivityのOnClickListenerを登録しておきます。 
これでリスト上でボタンを押した時に、MainActivty上のOnClick()が呼び出されるようリスナーの設定ができます。

```java:RecyclerAdapter.java
public void setOnItemClickListener(View.OnClickListener listener){
        m_listener = listener;
}

public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    final int pos = position;
    // リスト上のボタンが押された時に上で登録したクリックリスナーを呼び出してあげる
    holder.m_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            m_listener.onClick(view);
        }
    });
}
``` 

```java:MainActivity.java   
RecyclerView.Adapter rAdapter = new RecycleAdapter(data);
rAdapter.setOnItemClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        int line = getLine(); //どうにかして押したリストの行数を取得したい                             
        Intent hoge = new Intent(MainActivity.this, HogeActivity.class);
        hoge.putExtra("line", line);                   
        startActivity(hoge);  
    }
});    
```


# 本題
今の状態のままだと、どのリストのボタンを押しても同じ処理が行われてしまいます。

RecyclerView.Adapterに`onBindViewHolder`というメソッドがあります。
これはリストの項目が作られるたびに呼び出されるメソッドです。
そして引数である`position`がまさに何番目のリストが作成されたか、という値を表しています。

**このpositionの値を、リスト上のボタンのクリックリスナー内でRecyclerViewのメンバ変数に登録するよう実装します。**
**こうすることでボタンが押された時にその行数の値がRecycleViewAdapterのメンバ変数(m_line)に登録されます。**

そしてその`m_line`を外部から参照できるようなメソッドを作成し、それをMainActivityのOnClick()内で呼び出すよう実装します。
あとは遷移先の`HogeActivity`で値を取得して、それによって処理を変えてあげればOKですね。

```java:RecyclerAdapter.java
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    final int pos = position;
    holder.m_btn.setOnClickListener(new View.OnClickListener() {　
        @Override
        public void onClick(View view) {
            m_line = pos; //行数を登録
            m_listener.onClick(view); //登録した直後にMainのOnClickを呼び出す
        }
    });
}

public int getLine(){
    return m_line; //行数を取得
}
```               

```java:MainActivity.java   
final RecyclerView.Adapter rAdapter = new RecycleAdapter(list);
recyclerView.setAdapter(rAdapter);
((RecycleAdapter) rAdapter).setOnItemClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        int line = ((RecycleAdapter) rAdapter).getLine(); //ここでm_lineの値を取得
        Intent edit = new Intent(MainActivity.this, HogeActivity.class);
        edit.putExtra("line", line);
        startActivity(edit);
    }
});
``` 

# 最後に
なんだかものすごく回りくどい実装になってしまいましたが
押した行数をMainActivityに伝える方法が自力ではこれしか見つからなかったのでこんな実装になってしまいました。
「いやいや、そんなことしなくてもhogehogeすれば一発やん...」というのがあればぜひご教授ください。


# 最後の最後に
自分が作ったアプリからコード抜粋して少し修正しているので、文章とソースコードの変数名が一致していなかったりする場合もあります。
そこは脳内変換お願いします。