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

android OS & iPadOS の記録。

基礎。サムネイル画像キャッシュ(テスト) 残りのメソッド

2022-01-27 02:11:07 | Android studio 日記

文字数制限のため分割。

実際に組み込んで recyclerView で30枚くらいのサムネイル画像表示テストは、エミュレーター上では満足いく速さだった。
実機テストでどの程度になるか楽しみ。
 

【元画像をサムネイルサイズ付近に縮小処理】
    public Bitmap thumbnaileImage(String fName ) {
        File file = new File( mTargetDir, fName );
        if ( !file.exists() || !file.isFile() ) return null;
        Bitmap scaleBitmap = null;
        try {
            BitmapFactory.Options op = new BitmapFactory.Options();
            op.inJustDecodeBounds = true;

            InputStream istream = new FileInputStream( file );
            BitmapFactory.decodeStream( istream, null, op );

            op.inSampleSize = calculateInSampleSize( op, 96, 96 );
            op.inJustDecodeBounds = false;
            istream.close();
            istream = new FileInputStream( file );
            scaleBitmap = BitmapFactory.decodeStream( istream, null, op );
            istream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return scaleBitmap;
    }

    public int calculateInSampleSize(BitmapFactory.Options op, int reqWidth, int reqHeight ) {
        int height = op.outHeight;
        int width = op.outWidth;
        int inSamplSize = 1;

        if ( height > reqHeight || width > reqWidth ) {
            int halfHeight = height / 2;
            int halfWidth = width / 2;

            while ( ( halfHeight / inSamplSize ) >= reqHeight &&
                    ( halfWidth / inSamplSize ) >= reqWidth
            ) {
                inSamplSize *= 2;
            }
        }
        return inSamplSize;
    }


【後始末】
    public void finish() {
        mFileNameList.clear();
        mFileNameList = null;
        mTargetDir = null;
        mMainData = null;
    }
}

MyThumbnailRunnable クラス 終わり

ディレクトリ移動のサムネイル画像表示とブックマーク機能のサムネイル画像表示をキャッシュ利用に変更したら実機テスト。

 


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

基礎。サムネイル画像キャッシュ(テスト)

2022-01-27 02:00:09 | Android studio 日記

キャッシュフォルダに元画像ファイルのディレクトリ階層を構築して、サムネイル画像を保存する。

recyclerView のアダプタの imageView セットでファイル読み出しかサムネイル作成か。その部分。

    File file = new File( fName ); // フルパス画像ファイル名
    if ( !file.exists() || !file.isFile() ) return null; // 存在を確認
    File cDir = mContext.getCacheDir(); // getCacheDir() が使えないときは、Contextを引っ張る
    String text = cDir.getAbsolutePath() + file.getAbsolutePath(); // スレッドで構築されているはずのフルパス
    File cf = new File( text );
    Bitmap scaleBitmap = null;

    if ( cf.exists() ) { // キャッシュにサムネイルが存在するか確認
        scaleBitmap = BitmapFactory.decodeFile(cf.getAbsolutePath());
    } else {
        // サムネイル作成プログラム
    }


File cf = new File( text );が上手く機能しない場合は、 new File( dir, child  ); で試す。
理由は分からないが、File情報が取得できない事があった。画像ファイルはそこにあるのに。

スレッド実行のタイミングは試行を繰り返して良い場所を探す?
ディレクトリ内のファイルリスト作成場所に組み込んでみた。

    MyThumbnailRunnable mtr = new MyThumbnailRunnable( mMainData, dir );
    Thread thread = new Thread( mtr );
    thread.start();

 

【MyThumbnailRunnable クラス】

public class MyThumbnailRunnable implements Runnable {
    private MyMainData mMainData;
    private File mTargetDir = null;
    private ArrayList< String> mFileNameList = new ArrayList< >();

    public MyThumbnailRunnable( MyMainData mainData, File dir ) {
        mMainData = mainData; // Context 他を受け渡す
        mTargetDir = dir; // 対象ディレクトリ
    }

    @Override
    public void run() {
        if ( mMainData.getMakingThumbnailesDirPath().equals( mTargetDir.getAbsolutePath() ) )
            return;

        mMainData.setMakingThumbnailesDirPath( mTargetDir.getAbsolutePath() ); // フラグ
        fileNameList( mTargetDir );
        createThumbnail();
        mMainData.setMakingThumbnailesDirPath( "" ); // フラグ初期化
        finish(); // run() が終了で消滅するらしいが、念のため明確に参照は切っておく
    }

///// 
MyMainData クラスは、Context とフラグを受け渡すため。スレッド終了時には参照を切る。
引数の dir は、対象ディレクトリ。この中の画像ファイルをサムネイルにしてキャッシュに保存する。
処理が長時間になる場合は、アクティビティー上の参照はしない事。最悪、値をコピーして参照は切る。
スレッドは注意が必要らしい。
/////

【画像ファイル名をリストアップ】
    private void fileNameList( File f ) {
        String fName;
        String[] mList = f.list();
        if ( mList != null ) {
            mFileNameList.clear();
            for (String s : mList) {
                fName = s.toLowerCase(); //小文字に変換;
                if (fName.endsWith(".jpg") || fName.endsWith(".png")) { //画像ファイル選択
                    mFileNameList.add(s);
                }
            }
        }
    }

    public void createThumbnail() {
        if ( mFileNameList == null || mFileNameList.size() == 0 ) return;
        List< String> dirList = disassemblyPath( mTargetDir );
        File mCacheDir = assemblyCachePath( dirList );
        if ( mCacheDir == null ) return;
        makeCacheDirectory( dirList );
        for ( int i = mFileNameList.size()-1; i >= 0 ; i-- ) {
            bitmapToThumbnaile( new File( mCacheDir, mFileNameList.get(i) ) );
        }
    }

【サムネイル画像を保存】
    private void bitmapToThumbnaile( File cfile ) {
        Bitmap bitmap;
        if ( !cfile.exists() ) {
            bitmap = thumbnaileImage( cfile.getName() );
            if ( bitmap != null ) {
                try {
                    FileOutputStream fos = new FileOutputStream( cfile );
                    Bitmap.CompressFormat bcf = getCompressFormat( cfile.getName() );
                    if ( bcf != null ) bitmap.compress( bcf, 100, fos );
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if ( !bitmap.isRecycled() ) bitmap.recycle();
            }
            bitmap = null;
        }
    }

【拡張子から形式を割り出す】
    public Bitmap.CompressFormat getCompressFormat(String name ) {
        String t = name.toLowerCase();
        if ( t.endsWith( ".jpg" ) ) return Bitmap.CompressFormat.JPEG;
        if ( t.endsWith( ".png" ) ) return Bitmap.CompressFormat.PNG;
        return null;
    }


【キャッシュフォルダにディレクトリ階層を構築】
    public void makeCacheDirectory( List< String> list ) {
        int len;
        if ( list == null || ( len = list.size() ) == 0 ) return;
        File cacheDir = mMainData.getContext().getCacheDir();
        for ( int i = list.size()-1; i >= 0; i-- ) {
            cacheDir = new File( cacheDir, list.get(i) );
            if ( !cacheDir.exists() ) {
                boolean b = cacheDir.mkdir();
            }
        }
    }

【フルパスを分解、文字配列作成】
    public List< String> disassemblyPath(File f ) {
        List list = new ArrayList< String>();
        File path = f;
        do {
            list.add(path.getName());
            path = path.getParentFile();
        } while ( path != null && !path.getName().equals(""));

        return list;
    }

【文字配列をキャッシュフォルダ上に組み立て階層を作る】
    public File assemblyCachePath(List< String> list ) {
        int len;
        if ( list == null || ( len = list.size() ) == 0 ) return null;
        File cacheDir = mMainData.getContext().getCacheDir();
        String t;
        for ( len-=1; len >= 0; len-- ) {
            t = list.get(len);
            cacheDir = new File( cacheDir, t );
        }
        return cacheDir;
    }

残りのメソッドは次へ続く。


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