タブレット用プログラムの書き止め

android OS & iPadOS の記録。

RecyclerView【と】AsyncTask

2022-11-16 17:02:43 | Android studio 日記

ViewModel に recyclerView_id を管理させ、RecyclerView アダプタがアタッチ、デタッチされたとき recyclerView_id を変化させる。
アダプターが変化しなければ、recyclerView_id も変化しない。
ワーカースレッドで recyclerView_id を比較して更新の可否を決める。

意外とシンプルに判断できる。


public class MainViewModel extends ViewModel {

    private MutableLiveData< RecyclerView> recyclerView = null;
    public MutableLiveData< RecyclerView> getRecyclerView() {
        if ( recyclerView == null ) {
            recyclerView = new MutableLiveData< RecyclerView>(null);
            recyclerView_id = 0;
        }
        return recyclerView;
    }
    public RecyclerView getValueRecyclerView() {
        return getRecyclerView().getValue();
    }
    private long recyclerView_id;
    public void setRecyclerView(RecyclerView rv) {
        getRecyclerView().setValue(rv);
        recyclerView_id++;
    }
    public void clearRecyclerView() {

        if ( getRecyclerView() != null && getRecyclerView().getValue() != null ) {
            getRecyclerView().getValue().setAdapter(null);

            getRecyclerView().setValue(null);
            recyclerView_id++;
        }
    }
    public long getValueRecyclerViewID() {
        return recyclerView_id;
    }

    //省略
}

 


public class MyAdapter extends RecyclerView.Adapter {

    private final MainViewModel mViewModel;
    private RecyclerView myRecyclerView = null;
    private View.OnClickListener myListener;

    //省略

    public MyAdapter(MainViewModel viewModel, View.OnClickListener listener) {
        mViewModel = viewModel;
        myListener = listener;
        //省略
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        myRecyclerView = recyclerView;
        mViewModel.setRecyclerView(myRecyclerView);//****
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
        myRecyclerView = null;
        mViewModel.setRecyclerView(null);//****
        super.onDetachedFromRecyclerView(recyclerView);
    }

    //省略

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        if (getItemCount() <= 0) return;

        Bitmap bitmap = loadImage(myImageAbsPaths.get(position));
        if (bitmap != null)
            holder.imageView.setImageBitmap(bitmap);
        else {
            holder.imageView.setImageBitmap(
                      BitmapFactory.decodeResource(mMainModel.getContext().getResources(), R.drawable.img_file));
            MyAsyncTask2 mAsyncTask = new MyAsyncTask2(mViewModel, myRecyclerView, position);
            mAsyncTask.execute(myImageAbsPaths.get(position));
        }

        holder.textView.setText(String.valueOf(position + 1));
        initStartPositionOffset(holder.linearLayout, position);
        holder.linearLayout.setId(holder.getAdapterPosition());
        holder.linearLayout.setOnClickListener(myListener);
    }

    //省略
}

 


public class MyAsyncTask2 {

    private MainViewModel mViewModel;
    private RecyclerView mRecyclerView;
    private final int vID;

    private long mRecyclerView_id = 0;


    //省略

    public MyAsyncTask2(MainViewModel data, RecyclerView rv, int id ) {
        super();

        mViewModel = data;
        mRecyclerView = rv ;
        vID = id;
        mRecyclerView_id = data.getValueRecyclerViewID();

        //省略
    }

    private class TaskRunnable implements Runnable {

        private String targetPath = "";
        public TaskRunnable(String param) { targetPath = param; }

        @Override
        public void run() {
            
            //省略

            new Handler(Looper.getMainLooper())
                    .post(() -> onPostExecute(result));
        }
    }

    public void execute(String param) {
        mViewModel.getValueExecutorService().submit(new TaskRunnable(param));// ワーカースレッド実行
    }

    void onPostExecute(int result) {

        if ( mRecyclerView == null || mRecyclerView_id != mViewModel.getValueRecyclerViewID() ) {
            finish();
            return;
        }

        switch ( result ) {
            case 0:
                if ( vID < mRecyclerView.getAdapter().getItemCount() ) {
                        mRecyclerView.getAdapter().notifyItemChanged(vID);
                }
                break;
            
            //省略
        }
        finish();
    }
    void finish() {
        mRecyclerView = null;
        mViewModel = null;
    }

    //省略
}

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

RecyclerView【基礎】ImageView の列挙。まとめ。

2022-11-16 15:29:37 | Android studio 日記

【1】リソース画像を列挙。(一般サンプル通りでOK)
【2】画像ファイルを縮小(サムネイル化)して列挙。


【2】のポイント。
 [1]処理速度。
 [2]容量。


 [1-1]サムネイル画像ファイルを作成し、2回目以降はそれを読み込む。
 [1-2]サムネイル画像ファイルの作成はワーカースレッドで実行する。
 [1-3]サムネイル画像ファイルが未作成の時はリソース画像を設定。作成後入れ替える(更新)。

 [2-1]サムネイル画像ファイルの保存場所。
 [2-2]サムネイルのサイズと保存容量。
 [2-3]サムネイル画像ファイルの総数。

 

 [1-1-1]サムネイル画像ファイルの保存場所のファイル有無で処理を分岐する。
 [1-2-1]ExecutorService().submit(new Runnable())
 [1-3-1]RecyclerView.getAdapter().notifyItemChanged(viewID)

 [2-1-1]getCacheDir() + absoluteFilePath 
 [2-2-1]160x160ドット、10Kbyte程度。JPG
 [2-3-1]CacheDirならシステムで一括消去が有る。


【注意点】
・RecyclerViewは任意の時点で更新される。(可能性がある)
・RecyclerView.setAdaptr()でアイテムが更新される。(可能性がある)
・RecyclerViewが更新されてもワーカースレッドは独立進行する。

なので、現在のRecyclerViewの内容がワーカースレッドへ処理発注した時点のRecyclerViewの内容と同じならばImageViewを更新させる。
RecyclerViewの内容が変更されているのに発注した時点の条件で更新すると例外で停止する。

・現在のRecyclerView.getAdapter()オブジェクトとワーカースレッド引数のRecyclerView.getAdapter()オブジェクトを調べる。
・ワーカースレッドへ処理発注時にMyRecyclerViewでRecyclerView_idを渡す。そのIDが現在のRecyclerView_idと同じかを調べる。
 IDはViewModelで管理してRecyclerViewの変更、更新があったらIDを進める。

 

今、RecyclerViewアダプターのオブジェクト比較で同じならnotifyItemChanged(viewID)で更新している。
ViewModelで一元管理するのであれば、RecyclerViewに関する更新が行われた時にnotifyItemChanged(viewID)が実行されない工夫が必要。

・継承MyRecyclerViewにRecyclerView_idを設置。
・ViewModelのLiveDataにRecyclerViewを使う。そして、RecyclerView_idを設置。


継承クラスかViewModelか、試して使い勝手の良い方を選択する。
やっぱり、一元管理かな。

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする