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

android OS & iPadOS の記録。

基礎。サムネイル表示、メモリ消費を考える。RecyclerView

2021-10-16 15:49:43 | Android studio 日記

ファイル整理が滞るとディレクトリに画像千枚を超えてしまうことも。それをサムネイル表示処理をしてしまうとメモリ不足でダウンする。

画面上に配置する個数を2画面分用意して、ViewSwitcherで切り替えて分割処理をすれば、メモリ節約になる。ただ、デザイン的に気持ちがすっきりしない。メモリ効率で検索して調べると LinearLayoutやGridLayout などをメモリ効率的にまとめたものが RecyclerView のようだ。viewに割り当てられたものを上手に使い回すらしい。

なのでRecyclerViewのLinearLayoutManagerを試してみる。

手順は、
① activity_main.xmlにRecycleViewを設置。
② recyclerview.xmlへ最小単位のレイアウトを構築。
③ MyAdapter.java アダプターを作る。
④ MainActivity.java に実体を作る。

【activity_main.xml】

        < androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:scrollbars="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

【recyclerview.xml】

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:id="@+id/Linear_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:baselineAligned="false" >

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textview"
        android:layout_gravity="center_horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

 

【MyAdapter.java】

public class MyAdapter extends RecyclerView.Adapter< MyAdapter.ViewHolder >
       implements View.OnClickListener  {

    private Context mContext;
    private LayoutInflater mInflater;
    private RecyclerView mRecyclerView;

    private final List iImagePaths;
    private final List iNames;

    public MyAdapter( Context context ) {
        mContext = context;
        mInflater = LayoutInflater.from( context );
        iImagePaths = new ArrayList<>();
        iNames = new ArrayList<>();
    }

    public MyAdapter( Context context, List< String > itemImagePaths, List< String > itemNames ) {
        mContext = context;
        mInflater = LayoutInflater.from( context );
        iImagePaths = itemImagePaths;
        iNames = itemNames;
    }

    @Override
    public void onAttachedToRecyclerView( @NonNull RecyclerView recyclerView ) {
        super.onAttachedToRecyclerView( recyclerView );
        mRecyclerView = recyclerView;
    }
    @Override
    public void onDetachedFromRecyclerView( @NonNull RecyclerView recyclerView ) {
        mRecyclerView = null;
        super.onDetachedFromRecyclerView( recyclerView );
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate( R.layout.recyclerview, parent, false );
        view.setOnClickListener( (View.OnClickListener) this );

        return new ViewHolder( view );
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        if ( iImagePaths != null ) {
            Bitmap bitmap = loadImage(iImagePaths.get(position));
            if (bitmap != null) holder.imageView.setImageBitmap(bitmap);
        }
        if ( iNames != null ) holder.textView.setText(iNames.get(position));
    }
    public Bitmap loadImage( String fName ) {
        File file = new File( fName );
        if ( !file.exists() || !file.isFile() ) return null;
        Bitmap scaleBitmap = null;
        try {
            InputStream istream = new FileInputStream( file );
            Bitmap bitmap = BitmapFactory.decodeStream(istream);

            float mag = 160f / (float) bitmap.getHeight(); // サムネイル縦160ピクセル

            int width = (int) ((float) bitmap.getWidth() * mag );
            int height = (int) ((float) bitmap.getHeight() * mag );
            scaleBitmap = Bitmap.createScaledBitmap( bitmap, width, height, true);
            bitmap.recycle();
            istream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return scaleBitmap;
    }

    @Override
    public int getItemCount() {
        return iNames.size();
    }

    @Override
    public void onClick(View v) {

    }

    public String getAbsolutePath( int position ) {

        return iImagePaths.get( position );
    }

    public void addAll( List< String > itemImagePaths, List< String > itemNames ) {
        this.iImagePaths.addAll( itemImagePaths );
        this.iNames.addAll( itemNames );
        notifyDataSetChanged();
    }
    public void clear() {
        iImagePaths.clear();
        iNames.clear();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView imageView;
        TextView textView;
        ViewHolder(View v) {
            super(v);
            imageView = v.findViewById( R.id.imageview );
            textView = v.findViewById( R.id.textview );
        }
    }
}

【MainActivity.java】

    private MyDirectory mFolderItemList = null;
    private RecyclerView mRecyclerView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
省略

        File dir = new File( getFilesDir(),"image1" );
        mFolderItemList = new MyDirectory( dir );

        mRecyclerView = findViewById( R.id.recyclerview );
        mRecyclerView.setHasFixedSize( true );

        RecyclerView.LayoutManager rLayoutManager =new LinearLayoutManager(this, RecyclerView.HORIZONTAL, true );
        mRecyclerView.setLayoutManager( rLayoutManager );

        List aPaths = mFolderItemList.getAbsolutePathList();
        List fNames = mFolderItemList.getNameList();

        MyAdapter adapter = new MyAdapter( this, paths, fNames );
        mRecyclerView.setAdapter( adapter );

    }

サムネイル表示はOK。ここまでは簡単。
クリックで本画像を開くのは少し面倒。クリック処理は次回へ続く。