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

android OS & iPadOS の記録。

基礎。作業ディレクトリの考察。分割の前編。

2022-02-16 01:33:44 | Android studio 日記

前回の2つのディレクトリを切り替えも考えつつ説明。


作業ディレクトリが1つの時の動きは。

1、対象ディレクトリのFile情報を取得。
2、作業ディレクトリの作業ファイルを全て削除する。(直前の作業ファイルがある場合)
3、対象ディレクトリの中にあるフォルダアイテムをディレクトリと画像ファイルに分けてList<>化する。

4、画像ファイルからbitmapへデコードする。
5、bitmapをサムネイル画像へ変換する。

6、作業ディレクトリに保存する。


3番のあとにRecyclerViewAdapterで4、5番をしている。
毎回、画像変換すると時間がかかるので、ディレクトリが変更されるまでサムネイル画像を保存して読み出すようにする。

作業場所が1つの場合、作業ファイル削除と画像変換の時間がかかる。
この部分をバックグランドで処理できれば、反応速度が速くなる。

 

作業ディレクトリが2つの時の動きは。
 
1、対象ディレクトリのFile情報を取得。
2、対象の作業ディレクトリを切り替える。
3、前の作業ディレクトリの作業ファイルを全て削除する。(別スレッドでバックグラウンド処理)
4、対象ディレクトリの中にあるフォルダアイテムをディレクトリと画像ファイルに分けてList<>化する。
5、サムネイル画像ファイルがあれば、それを使う。無ければ、リソース画像を表示する。
6、バックグラウンドで画像ファイルからbitmapへデコード、bitmapをサムネイル画像へ変換、作業ディレクトリに保存する。
7、対象ディレクトリの変更の時は、1番からやり直し。

これでFile情報の取得と必要データのリスト化、アダプターへの設定と表の処理時間を減らせた。
画像ファイル数が少なければ、気にならないが数百枚画像があると反応速度にイラつく。


最初のテストでは問題は無かったけど、何か相性が悪い書き込みをしてしまったようで例外が発生するようになった。
色々と対応してみたが原因も突き止められないので、この際だから深く考え直す。

2つの作業ディレクトリで論理的に良いと思うが、低い確率で処理がぶつかって問題になる。
例えば、画像枚数が多くてファイル削除が終わる前にディレクトリ移動が発生した時。
問題回避には看板をかけて処理待ちさせれば良い。低確率だからこれでいいと思うが個人的に納得できない。

となると、作業ディレクトリを必要に合わせて増やせばいい。
そういうクラスを作る。


クラス内で作業ディレクトリを自動で増加させる。
操作可能不可能をできるだけクラス内で自動に設定させる。
別スレッドで作業ファイルを自動で削除させる。

Adapterで使用する作業ディレクトリも内部フラグで自動変更させる。
getTempDirForAdapter() を呼べば、使用中の作業ディレクトリのFile情報が帰る。


次に分割の後編。プログラム草案。

 


基礎。作業ディレクトリの考察。(プログラム草案)

2022-02-16 01:29:31 | Android studio 日記

作業用ディレクトリの管理クラス。

 

    static class MyTempDir {
        private Context mContext = null;
        private ArrayList< File> mTempDir = null;       // 作業ディレクトリ
        private ArrayList< Boolean> usingFlag = null;  // 作業中 true
        private ArrayList< Boolean> usedFlag = null;  // 使用後 true
        private ArrayList< Boolean> clearFlag = null;// 消去中 true

        MyTempDir( Context context ) {
            mContext = context;
            mTempDir = new ArrayList< File>();
            usingFlag =  new ArrayList< Boolean>();
            usedFlag =  new ArrayList< Boolean>();
            clearFlag = new ArrayList< Boolean>();
            init();
        }
        private void init() {
            File dir = new File( mContext.getFilesDir(), "temp" );
            dir = new File( dir, "temp1" );
            boolean b;
            if ( !dir.exists() )  b = dir.mkdirs();
            mTempDir.add(dir);
            usingFlag.add(false);
            usedFlag.add(false);
            clearFlag.add(false);
        }
        private boolean mGetDirFlag = false;
        private File getTempDir() {
            mGetDirFlag = true;
            int usingNo = getUsingTempDir();
            int i = mTempDir.size();
            while ( --i >= 0 ) {
                if ( !usingFlag.get( i ) && !usedFlag.get( i ) && !clearFlag.get( i ) ) break;
            }
            if ( usingNo >= 0 ) {
                usingFlag.set( usingNo, false );
                usedFlag.set( usingNo, true );
            }
            if ( i < 0 ) {
                File dir = new File( mContext.getFilesDir(), "temp" );
                i = mTempDir.size();
                String dirName = "temp" + String.valueOf( (i+1) );
                dir = new File( dir, dirName );
                boolean b;
                if ( !dir.exists() )  b = dir.mkdirs();
                
                mTempDir.add(dir);   // 4つはセットで追加する
                usingFlag.add(true); // 管理できなければ、4つを1つの構造体にして配列使用
                usedFlag.add(false); //
                clearFlag.add(false);//
                
                mGetDirFlag = false;
                allClearTempFile();
                return mTempDir.get(i);
            }
            usingFlag.set( i, true );
            mGetDirFlag = false;
            allClearTempFile();
            return mTempDir.get(i);
        }

        public void setUsingFlag( int no, boolean flag ) { usingFlag.set( no, flag ); }
        public void setUsedFlag( int no, boolean flag ) { usedFlag.set( no, flag ); }
        public void setClearFlag( int no, boolean flag ) { clearFlag.set( no, flag ); }

        public int getUsingTempDir() {
            int i = mTempDir.size();
            while ( --i >= 0 ) {
                if ( usingFlag.get(i) ) break;
            }
            return i;
        }
        private boolean isUsingTempDir( int no ) {
            return ( no >= 0 && no < mTempDir.size() )? usingFlag.get(no): false;
        }
        private boolean isUsedTempDir( int no ) {
            return ( no >= 0 && no < mTempDir.size() )? usedFlag.get(no): false;
        }
        private boolean isClearTempDir( int no ) {
            return ( no >= 0 && no < mTempDir.size() )? clearFlag.get(no): false;
        }

        public void allClearTempFile() {
            int i = mTempDir.size();
            while ( --i >= 0 ) {
                if ( usedFlag.get(i) ) {
                    clearFlag.set( i, true );
                    allClearTempFile( mTempDir.get(i) );
                    clearFlag.set( i, false );
                    usedFlag.set( i, false );
                }
            }

        }
        private void allClearTempFile( File dir ) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while ( true ) {
                        if (!mGetDirFlag) break;
                    }
                    boolean b;
                    File[] files = dir.listFiles();
                    for ( File file: files) {
                        b= file.delete();
                    }
                }
            }).start();
        }

        public File getTempDirForAdapter() {
            int no = getUsingTempDir();
            return ( no < 0 )? null: mTempDir.get( no ); // 使用中の作業ディレクトリを返す
        }
        
        public void finish() {

            mTempDir.clear();
            mTempDir = null;
            usingFlag.clear();
            usingFlag = null;
            clearFlag.clear();
            clearFlag = null;
            mContext = null;
        }
    }


    MyTempDir mTempDir = new MyTempDir( mContext );