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

android OS & iPadOS の記録。

【kotlin】 非同期処理(RecyclerViewにサムネイル設定が大量の場合)

2024-04-25 15:41:21 | Android studio 日記

RecyclerView.Adapterに画像のフルパスリストを渡し、サムネイル画像を生成する。
その画像を設定すると処理時間が長すぎてサムネイル画像のスクロールがスムーズに動かない。

画像作成と設定、更新を非同期処理で行う。
システムが管理しているサムネイル画像を利用する選択もあるが自前で用意する事にする。

サンプルなどから作成したコードは、随時開始してしまいCPUの能力を削りすぎる。
また、メモリもスレッド数分消費してしまう。
画像数が少なければ問題ないが状況により書き換え更新のストップやユーザーアクションに反応しなくなる。
非同期処理の意味がなくなるのでコルーチンにシングルスレッド処理を設定する。

コンパクトで処理が速いのですが古いデバイスでは低能力、低メモリ量なので大量処理には向かないため。


アダプター修正内容。

class MyFragment : Fragment() {
    /* 省略 * /

    private val parentJob = Job()

    inner class MyAdapter() : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
        /* 省略 * /

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            holder.imageView.setImageBitmap(loadImage(position))
            /* 省略 * /
        }

        private fun loadImage(position: Int): Bitmap? {
            val imagePath: String = pathList.get(position)
            /* 省略 * /

            if (!cf.exists()) { /* キャッシュファイルが無い時 * /

                CoroutineScope(
                    newSingleThreadExecutor().asCoroutineDispatcher()
                ).launch( parentJob ) {
                    asyncTask( imagePath, _recyclerView!!, position)
                }

                return BitmapFactory.decodeResource(
                    requireContext().getResources(),
                    R.drawable.img_file
                )
            }
            return BitmapFactory.decodeFile(cf.absolutePath) /* キャッシュファイルがあれば、Bitmapを返す * /
        }
        /* 省略 * /
    }

 

    suspend fun asyncTask(path:String, rv: RecyclerView, vID: Int) { 

        /* 省略 * /
        
        val ret = MyMakeThumbnail().toThumbnailFile(souFile, cacheFile, _saveSize)

        when ( ret ) {
            0 -> if (vID < _rv.adapter!!.itemCount) {
                _rv.post(Runnable {
                    _rv.adapter!!.notifyItemChanged(vID)
                })
            }

             /* 省略 * /
        }
    }
}


非同期を開始する場所に書く。

CoroutineScope(  newSingleThreadExecutor().asCoroutineDispatcher() ).launch(parentJob) {
    asyncTask(path, _recyclerView!!, position)
}

シングルスレッド処理を開始させる。
前の処理が続いている場合は待機され順番に1つずつ処理が行われる。


コルーチンがよく分からず取り合えず動く内容という形でした。

とりわけ、runBlockingが未理解で付けたら動く。くらいに使ってました(笑)
恐ろしい。


下記サイトを参考に何となくコルーチン組みました。

【Kotlin/JVM】CoroutineDispatcher を作る
       https#//qiita.com/sdkei/items/a056a1275b05b11ddcd4


CoroutinesのlaunchとasyncとChannelとFlowの使い分け
       https#//qiita.com/naoi/items/9892db4cec2e9c0f6114

 


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

【kotlin】 Toastをカスタマイズする

2024-04-03 13:26:40 | Android studio 日記

Toast の文字の大きさを大きくしたい。
という思いから調べたところ、純正からはそのような記事は見つからなかった。

説明されている複数のサイトでカスタマイズする方法が分かりました。
ですが、自分のプログラムに組み込むには問題があり例外が発生してしまう。

複数の方法を組み合わせて自分のものに使えるように調整した。

【参考】
 ※【Android Studio】Toast に画像・テキストを追加するカスタマイズ方法
  https#//codeforfun.jp/android-studio-how-to-customize-toast/

 ※ [Android] Toast をカスタマイズする
  https#//akira-watson.com/android/toast-custom.html

 

【注意】
ViewModel でViewの参照の値を保存することはメモリリークの原因になります。
メソッド内で参照を作成した場合はメソッドが終了すると参照をシステムが切ってくれます。多分^^;

 

アプリケーションの Context が求められれば、ViewModelのメソッド内でViewが作成できる。
そのViewをToastに設定して表示する。

Viewの構成は、custom_toast.xmlに記載しておく。

※ toast.setView(view) は、非推奨になりました。最新のOSでは、いずれ使用できなくなります。

 

【MainViewModel.kt】

class MainViewModel(app:Application): AndroidViewModel(app) {

    fun toastMake(text:String) {
        val view: View = LayoutInflater.from(getContext())
            .inflate(
                R.layout.custom_toast,
                null
            )

        view.findViewById(R.id.toast_message).text = text

        val toast: Toast =
            Toast.makeText(
                view.context,
                "",
                Toast.LENGTH_LONG
            )
        toast.setGravity(
            Gravity.CENTER,
            0,
            200
        )
        toast.setView(view)  // 非推奨
        toast.show()
    }
}

 

【custom_toast.xml】 res/layout に作成。


< RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relative_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    < TextView
        android:id="@+id/toast_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:background="@drawable/message_frame"
        android:textColor="@color/background_color"
        android:textStyle="bold"
        android:textSize="24sp"
        />
< /RelativeLayout>


android:background="@drawable/message_frame"
枠の設計を別にしています。
色や形状をカスタマイズ。説明は省略。

 


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