当前位置:首页 > 行业动态 > 正文

如何在Android上实现照片墙功能?

Android实现照片墙,可以通过GridView或RecyclerView展示图片,使用ImageLoader加载网络图片。

Android实现照片墙

如何在Android上实现照片墙功能?  第1张

一、背景描述

照片墙是一种在移动应用中常见的展示形式,用于以网格的形式整齐排列图片,这种布局不仅美观,而且能够高效利用屏幕空间,使用户能够一目了然地看到更多的图片,实现照片墙功能需要考虑图片的加载、缓存和内存管理等多方面的问题,本文将详细介绍如何在Android平台上实现一个高效的照片墙,并重点讲述如何通过LruCache来防止由于图片过多导致的程序崩溃。

二、需求分析

功能需求

GridView控件:作为照片墙的容器,按网格形式排列图片。

图片加载:支持从网络下载图片和本地存储的图片。

图片缓存:使用LruCache缓存已下载的图片,避免重复下载和内存溢出。

滚动加载:在用户滚动GridView时动态加载更多图片。

非功能需求

性能要求:图片滑动流畅,无明显卡顿。

内存管理:合理释放不再使用的图片资源,防止OOM(Out of Memory)。

用户体验:界面简洁美观,操作顺畅。

三、方案设计

技术选型

GridView:作为主要的图片容器。

ImageView:用于显示单张图片。

LruCache:用于缓存图片,减少内存消耗。

AsyncTask或Glide/Picasso等图片加载库:用于异步加载图片。

系统架构

UI层:包含GridView和自定义的适配器。

数据层:包含图片URL或本地路径。

缓存层:使用LruCache进行图片缓存。

网络层:负责从网络下载图片。

四、实现步骤

创建项目和布局文件

1.1 新建Android项目PhotoWallDemo

创建一个名为PhotoWallDemo的Android项目,并在res/layout目录下创建两个XML布局文件:activity_main.xml和photo_layout.xml。

1.2 activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <GridView
        android:id="@+id/photo_wall"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:columnWidth="90dip"
        android:stretchMode="columnWidth"
        android:numColumns="auto_fit"
        android:verticalSpacing="10dip"
        android:horizontalSpacing="10dip"
        android:gravity="center" />
</LinearLayout>

1.3 photo_layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/photo"
        android:layout_width="90dip"
        android:layout_height="90dip"
        android:src="@drawable/logo"
        android:layout_centerInParent="true"/>
</RelativeLayout>

2.编写适配器类PhotoWallAdapter

创建一个名为PhotoWallAdapter的类,继承自BaseAdapter,用于绑定数据到GridView。

public class PhotoWallAdapter extends BaseAdapter {
    private Context mContext;
    private String[] imageUrls;
    private LruCache<String, Bitmap> mMemoryCache;
    private final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    private final int cacheSize = maxMemory / 8; // Use 1/8th of available memory for cache
    private Set<BitmapWorkerTask> taskCollection;
    private GridView mPhotoWall;
    private int mFirstVisibleItem;
    private int mVisibleItemCount;
    private boolean isFirstEnter = true;
    public PhotoWallAdapter(Context context, String[] imageUrls, GridView photoWall) {
        mContext = context;
        this.imageUrls = imageUrls;
        mPhotoWall = photoWall;
        taskCollection = new HashSet<>();
        final int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
        // Use 1/8th of the available memory for this memory cache.
        int cacheSize = 1024 * memClass / 8;
        mMemoryCache = new LruCache<>(cacheSize);
        mPhotoWall.setOnScrollListener(new AbsListView.OnScrollListener() {
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                mFirstVisibleItem = firstVisibleItem;
                mVisibleItemCount = visibleItemCount;
            }
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (scrollState == SCROLL_STATE_IDLE) {
                    isFirstEnter = false;
                    loadMoreImages();
                }
            }
        });
    }
    @Override
    public int getCount() {
        return imageUrls.length;
    }
    @Override
    public Object getItem(int position) {
        return imageUrls[position];
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.photo_layout, null);
        }
        ImageView photo = (ImageView) convertView.findViewById(R.id.photo);
        String url = getItem(position).toString();
        Bitmap bitmap = mMemoryCache.get(url);
        if (bitmap != null) {
            photo.setImageBitmap(bitmap);
        } else {
            photo.setImageResource(R.drawable.logo); // Default placeholder.
            taskCollection.add(new BitmapWorkerTask(url, photo));
        }
        return convertView;
    }
    private void loadMoreImages() {
        int toIndex = Math.min(mFirstVisibleItem + mVisibleItemCount, 2 * mVisibleItemCount);
        for (int i = mFirstVisibleItem; i < toIndex; i++) {
            loadBitmap(i, imageUrls[i]);
        }
    }
    private void loadBitmap(final int position, final String url) {
        if (cancelPotentialWork(url, position)) {
            BitmapWorkerTask task = new BitmapWorkerTask(url, imageUrls[position]);
            taskCollection.add(task);
            task.execute(url);
        }
    }
    private static boolean cancelPotentialWork(String url, int position) {
        final BitmapWorkerTask task = getBitmapWorkerTask(url);
        if (task != null) {
            final int currentPosition = task.position;
            if (currentPosition == position) {
                return false;
            }
            task.cancel(true);
        }
        return true;
    }
    private static BitmapWorkerTask getBitmapWorkerTask(String url) {
        // Return the existing task if it's still being executed or has been cancelled but not yet removed.
        for (BitmapWorkerTask task : taskCollection) {
            if (task.url.equals(url)) {
                return task;
            }
        }
        return null;
    }
    class BitmapWorkerTask extends AsyncTask<String, String> {
        private String url;
        private final ImageView imageView;
        private int position;
        public BitmapWorkerTask(String u, ImageView i) {
            url = u;
            imageView = i;
        }
        @Override
        protected String doInBackground(String... params) {
            return downloadUrl(params[0]);
        }
        @Override
        protected void onPostExecute(String result) {
            if (isCancelled) {
                taskCollection.remove(this);
                return;
            }
            if (!isCancelled()) {
                Bitmap bitmap = decodeSampledBitmapFromResource(result, 90, 90);
                if (bitmap != null) {
                    mMemoryCache.put(url, bitmap);
                    imageView.setImageBitmap(bitmap);
                }
            }
        }
        private String downloadUrl(String u) {
            InputStream inputStream = null;
            HttpURLConnection connection = null;
            try {
                URL url = new URL(u);
                connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.connect();
                inputStream = connection.getInputStream();
                return BitmapFactory.decodeStream(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    if (inputStream != null) inputStream.close();
                    if (connection != null) connection.disconnect();
                } catch (IOException ignored) {}
            }
        }
    }
}

小伙伴们,上文介绍了“android实现照片墙”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。

你可能想看:
0