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

android OS & iPadOS の記録。

基礎。SharedPreferences String 配列の保存。

2021-12-12 12:54:17 | Android studio 日記

アプリの状態を記憶している変数をアプリ固有のPreferences領域に保存する。
いくつか種類があるが手間の少ないものを選択してみる。文字列配列の説明。お気に入りの画像ファイルのフルパスを配列保存しているのでPreferences領域に保存が必要。

 

文字列配列をプリファレンスへ保存するには Set<String> という型でないといけない。変換は簡単。

Set<String> sArray = new HashSet<String>( list );

これだけで変換は終了。ただし、大きな問題もある。Set<>型は同じ文字列の重複を許さない事。逆を言えば、重複を勝手に削除してくれる。自前で重複削除を作らなくていいのでラッキーだった。


            List<String> list = new ArrayList<>();
            list.add("ABC");
            list.add("DEF");
            list.add("ABC");

            // 書き込み
            SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(Context);

            Set<String> sArray = new HashSet<String>( list );
            pref.edit().putStringSet("key_list", sArray ).apply();
            sArray.clear();

実行して読み出すと
"ABC"
"DEF"
この二つしか保存されていない。

書き込むタイミングは、お気に入り登録時、onPause() 時、編集時あたりか。
読み込みは逆にList<>へ変換すれば良い。

 

            // 読み出し
            SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(Context);

            Set<String> sArray = pref.getStringSet("key_list", null );
            if ( sArray != null ) list = new ArrayList<String>( sArray );
            else list = new ArrayList<>();
            sArray.clear();

 

List<String> list = new ArrayList<String>( sArray );

これで List<String> へ、キャスティングしてくれるそう。
重複文字列は削除済み。重複文字列も重要であれば、保存前に処理。

list.add( i, list.get( i ) + "/" + String.valueOf( i ) );

識別文字を付加して重複を回避する。全てに付加。読み出し後に識別部分を取り去る。

 


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

基礎。Thread & Runnable の続き。

2021-12-06 14:59:43 | Android studio 日記

データの受け渡しは問題なさそう。
ただ、戻り値の受け取り処理、別スレッドで再度の処理の開始、タイミングの取り方をしっかり考えること。

画像のファイルパス2つからbitmapを作り、合成して1つのbitmapを用意する。それを戻り値にして、ImageViewに設定。
進み、戻りを繰り返すと例外ストップ。

例外発生になりそうな部分を手直ししても例外発生。
スレッド内プログラムが終了すれば、スレッド消滅らしいが…。


テストでスレッド処理中はフラグを立てて、処理待ちでメインを待機のようなスルーのような。

thread.start();
while ( flag ) ;

スタート後、問題なさそうに実行されるが何かの原因で例外発生。
thread.join();
thread.interrupt();

待機と例外停止?を追加した。while() は取り除き(グルグル回らないから)。


気持ち、長く稼働しているがある条件で例外発生。
スレッドを使わないときの実行では問題ないコード(ほぼ同じ内容)だけど…。

フラグを多用して、タイミングを調整か?

画像表示で1秒止まることもないので円形プログレスバーは取りやめて、ディレクトリのアイテムを読み取って、ソートするところをスレッド処理してみる。

 

グルグルはシステムの方でスレッド処理して欲しいな。

 


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

基礎。円形プログレスバーとThread & Runnable

2021-12-04 20:43:05 | Android studio 日記

画像切り替え、ディレクトリの移動など動作OKなので、重い処理で待機している時の円形プログレスバーを組み込みたい。

プログレス オン()
処理()
プログレス オフ()

やっちまった。
アンドロイドプログラミング初心者あるある。だそう。
OSは、マルチで動いていてもアプリはシングルらしい。
プログレスバーもメインスレッドの一部の時間を上手く使って動いてる。
処理が長時間占有するとプログレスバーは止まるという事。
プログレスバーはUIなのでメインで使うルール。
処理を別スレッドで実行させないとグルグルが回らない。

まず、円形プログレスバー。

【activity_main.xml】

    < ProgressBar
        android:id="@+id/progress_circular"
        style="@style/Widget.AppCompat.ProgressBar"
        android:layout_width="100dp"
        android:layout_height="100dp" />

大きさを変える時は、layout_width="100dp" サイズ指定。大きくしすぎるとボケる。
別デザインあり。ちょっと気に入らない。

 

要望などなど。
別スレッドを作る時に引数を渡して戻り値を受け取りたい。
メモリリークに注意する。
AsyncTask、Handlerは、非推奨になるらしい。
Thread、Runnableを使っての別スレッドを実行。

色々検索して、EventListener インターフェースを新設することで戻り値を受け取れると分かった。
スレッド内のメモリを解放、参照を切ること。

インターフェースは、これ。
テストでビットマップを受け取ってみる。

【MyEventListener.java】

public interface MyEventListener extends EventListener {
    void onMyEvent(Bitmap bitmap);
}

スレッドでの処理。

【MyRunnable.java】

public class MyRunnable implements Runnable {
    private MyMainData mainData;
    private MyEventListener mEventListener = null;
    private Bitmap mBitmap = null;

    MyRunnable(MyMainData mainData ) {
        this.mainData = mainData;
    }
    public void setEventListener( MyEventListener listener ) {
        this.mEventListener = listener;
    }
    public void removeEventListener() {
        this.mEventListener = null;
    }
    @Override
    public void run() {

        try {
            File file = new File(mainData.getTargetFilePath());
            InputStream isf1 = new FileInputStream(file);
            mBitmap = BitmapFactory.decodeStream(isf1);
            isf1.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if ( this.mEventListener != null && mBitmap != null ) {
            this.mEventListener.onMyEvent( mBitmap );
        }
        mainData = null;
        mEventListener = null;
        mBitmap = null;
    }
}

タイミング的に後始末が良いのか不安が残る。

 

イベントリスナー宣言内ではUI操作はエラーとならない。
受け取ったビットマップをコピーしてImageViewに設定している。
スレッド内で確保したビットマップをrecycle()で解放。
一時的に同じビットマップを2面利用するのが気になるが今はスルー。

【MainActivity.java】


    MyRunnable test = new MyRunnable( mainData );
    test.setEventListener( new MyEventListener() {
        @Override
        public void onMyEvent(Bitmap bitmap) {
            MyImageView view = mainData.getTargetImageView();
            view.scrollTo(0, 0);
            view.setImageBitmap( bitmap.copy( Bitmap.Config.ARGB_8888, true ) );
            mainPage.setPaddingImageView(view, bitmap.getWidth(), bitmap.getHeight());
            bitmap.recycle();
        }
    });
    Thread th = new Thread( test );
    th.start();

 

テストは動作問題なし。メモリ状況は確認できず。
どうなんだろう?


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

基礎。配列に用意した画像ファイルパスから2枚を並べて表示、及び、移動。

2021-12-02 23:32:57 | Android studio 日記

プログラムが、ある程度まとまったので、「次へ」「戻る」で移動させよう。
viewSwitcherも使おう。と、テストのメソッドを削除して、並びを整理したら、プログラム途中でディレクトリ用のサムネイルが表示しなくなった。…

関係部分を突いてみたものの解らずじまい。
これは1から見直すしかないとMainActivity を見ていったら、テスト部分の整理したメソッド…、
見栄えで並び順を変えたせいでデータが出てないのに参照していたという落ち。
1週間がorz..

 

めげずに配列の画像パスを使って「次へ進む」「前へ戻る」を組み込む。

まず、1枚表示。
「次へ進む」targetIndex++
「前へ戻る」targetIndex--
と、配列の範囲外処理で問題なし。

では、2枚表示。
「次へ進む」targetIndex+2
「前へ戻る」targetIndex-2
と、配列の範囲外処理で問題なし。

 

人は欲望で動いている。
画像は、縦長、横長があるよね。
ペアになったら横長が小さくなって見づらいから、横長は1枚表示にしよう。
あ~めんど。(30分後)

進むだけなら問題ない。
戻るが加わると単純には操作できない。

で、考え方の基礎部分。イメージのみ。


2枚を表示する画像に対応する箱が2つ。
AとB。Aがベース、Bがサブとする。

                                  A    B
index:  0    1    2    3   (4)  (5)   6    7    8    9
                                             A    B
index:  0    1    2    3    4    5   (6)  (7)   8    9

これは2枚づつの場合。

 

分かりやすく進むだけを考える。範囲外チェックは省略。
横長を判断条件にする。
例えば、5番が横長だったら。

                                 A   (B)            Bには、ー1を入れておく。
index:  0    1    2    3   (4)   5    6    7    8    9

                                       A  (B)       Bには、ー1を入れておく。
index:  0    1    2    3    4   (5)   6    7    8    9

                                             A    B
index:  0    1    2    3    4    5   (6)  (7)   8    9

横長がペアに入ったら1枚表示とする。
そして、ABの箱を渡す。次の処理は、箱の中を見て表示画像と位置を決める。

 

次は戻るだけを考える。同じく5番が横長。

                                             A    B
index:  0    1    2    3    4    5   (6)  (7)   8    9

                                       A  (B)       Bには、ー1を入れておく。
index:  0    1    2    3    4   (5)   6    7    8    9

                            A    B
index:  0    1    2   (3)  (4)     6    7    8    9


実際には、indexを管理する変数を使っている。
ベース、Aの箱の中の番号の1つ前を調べて、横長なら、Aに番号を入れ、Bにー1を入れて次へ渡す。

別パターン。

                                                    A    B
index:  0    1    2    3    4    5    6   (7)  (8)   9

                                              A  (B)       Bには、ー1を入れておく。
index:  0    1    2    3    4    5   (6)   7    8    9

                                        A  (B)             Bには、ー1を入れておく。
index:  0    1    2    3    4   (5)   6    7    8    9

                            A    B
index:  0    1    2   (3)  (4)     6    7    8    9

パターンによる違いも考える。

そして、ABの箱の並びは、進むも戻るも同じ順序。
次の処理では画面の左側、右側を箱の並びで決めているから。
左右の画像を入れ替えたい時は、ABに入れる番号を逆にする。

 

進むで画像を切り替えていて、戻るで番号が減数変化した時の動作も確認する。
状況判断の取りこぼしに注意。


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