Volley ImageLoader实现图片瀑布流

Volley ImageLoader实现图片瀑布流

在网络上请求图片资源是APP最常见的操作之一,上篇博文已经介绍过ImageRequest,可以实现image的请求显示 重新按照所需尺寸编码decode等等功能。这次我们来介绍ImageLoader。

  • ImageRequest—a canned request for getting an image at a given URL and calling back with a decoded bitmap. It also provides convenience features like specifying a size to resize to. Its main benefit is that Volley’s thread scheduling ensures that expensive image operations (decoding, resizing) automatically happen on a worker thread.
  • ImageLoader—a helper class that handles loading and caching images from remote URLs. ImageLoader is a an orchestrator for large numbers of ImageRequests, for example when putting multiple thumbnails in a ListView. ImageLoader provides an in-memory cache to sit in front of the normal Volley cache, which is important to prevent flickering. This makes it possible to achieve a cache hit without blocking or deferring off the main thread, which is impossible when using disk I/O. ImageLoader also does response coalescing, without which almost every response handler would set a bitmap on a view and cause a layout pass per image. Coalescing makes it possible to deliver multiple responses simultaneously, which improves performance.
  • NetworkImageView—builds on ImageLoader and effectively replaces ImageView for situations where your image is being fetched over the network via URL. NetworkImageView also manages canceling pending requests if the view is detached from the hierarchy.

1.设置list_item.xml

为ListView的每一个项目设置布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:orientation="horizontal" >

    <!-- 使用Volley定义的控件NetworkImageView -->

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/item_image"
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:layout_marginLeft="10dp"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:text="神秘北极圈 阿拉斯加的山巅 谁的脸 出线海角的天边" >
    </TextView>

</LinearLayout>

主布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android1="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ListView
        android1:id="@+id/listView1"
        android1:layout_width="match_parent"
        android1:layout_height="wrap_content"
        android1:layout_alignParentTop="true"
        android1:layout_centerHorizontal="true" >

    </ListView>

</RelativeLayout>

2.初始化ListView和设置Adapter

package com.example.volley_list;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.Volley;

public class MainActivity extends Activity {
    private ListView listView;
    // 定义自己的Adapter
    private ListItemAdapter adapter;

    private static final String TAG = "MainActivity";
    // 请求队列
    static RequestQueue rQueue;

    // 圖片URL数组
    private String[] paths = {
            "http://d.hiphotos.bdimg.com/album/pic/item/34fae6cd7b899e51dca31fbb40a7d933c8950d6b.jpg",
            "http://imgsrc.baidu.com/forum/w%3D580/sign=97543e82b6119313c743ffb855380c10/fc0a12f41bd5ad6e19d394aa85cb39dbb6fd3c5d.jpg",
            "http://thumbnail2.jiaoyoudns.com/mfs.jiaoyoudns.com/test/sld/91/0391/1_tuku_1_9_1395000391.jpg=-=750_750_0_thumbnails.jpg",
            "http://d.hiphotos.bdimg.com/album/pic/item/34fae6cd7b899e51dca31fbb40a7d933c8950d6b.jpg",
            "http://img5.duitang.com/uploads/item/201405/02/20140502190021_Bkau2.jpeg",
            "http://img4.duitang.com/uploads/item/201405/02/20140502191110_vFfLm.png",
            "http://img4.duitang.com/uploads/item/201407/22/20140722133408_BGL2a.png",
            "http://1881.img.pp.sohu.com.cn/images/blog/2012/5/4/10/8/e10850818_137d711c6fcg214.png",
            "http://img4.imgtn.bdimg.com/it/u=3256617509,2551528905&fm=21&gp=0.jpg",
            "http://imgsrc.baidu.com/forum/w%3D580/sign=66743b95d639b6004dce0fbfd9513526/efa669cf3bc79f3d8b66dc46b9a1cd11738b295f.jpg",
            "http://images.chinese.kdramastars.com/data/images/full/15686/f-x-krystal.jpg?w=600" };

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

        // 实例化成员变量
        Log.i(TAG, "onCreate()");
        listView = (ListView) findViewById(R.id.listView1);
        rQueue = Volley.newRequestQueue(getApplicationContext());

        adapter = new ListItemAdapter(this);
        listView.setAdapter(adapter);
        adapter.notifyDataSetChanged();

    }

    /**
     * 编写适配器ListItemAdapter
     * 
     * @author QT
     * 
     */
    public class ListItemAdapter extends BaseAdapter {
        // 上下文对象
        private Context context;

        public ListItemAdapter(Context context) {
            super();
            this.context = context;
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return paths.length;
        }

        @Override
        public Object getItem(int arg0) {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public long getItemId(int arg0) {
            // TODO Auto-generated method stub
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater inflater = LayoutInflater.from(context);
            View v;
            Log.i(TAG, "getView()" + position);
            if (convertView == null) {
                // 若为空,则动态加载一个View
                v = inflater.inflate(R.layout.list_item, null);
                // v.setPadding(8, 8, 8, 8);

            } else {
                v = convertView;
            }
            // 初始化ImageLoader,此处其实也应该为单例的
            // ImageLoader 需要自己实现缓存
            ImageLoader mImageLoader = new ImageLoader(rQueue,
                    new ImageCache() {
                        private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(
                                20);

                        @Override
                        public void putBitmap(String url, Bitmap bitmap) {
                            cache.put(url, bitmap);

                        }

                        @Override
                        public Bitmap getBitmap(String url) {
                            return cache.get(url);
                        }
                    });

            NetworkImageView mNetworkImageView = (NetworkImageView) v
                    .findViewById(R.id.item_image);
            String IMAGE_URL = paths[position];

            // Set the URL of the image that should be loaded into this view,
            // and
            // specify the ImageLoader that will be used to make the request.
            mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);

            TextView mTextView = (TextView) v.findViewById(R.id.item_text);
            mTextView.append("------>" + position);
            return v;
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

3.运行结果

这里写图片描述


RequestQueue和ImageLoader单例模式

每次执行网络请求,实例化一个RequestQueue,很明显是对于资源的浪费,同时在app整个生命周期几乎都有可能发生网络请求,所以设置RequestQueue的上下文对象为ApplicationContext,使用单例模式是最佳实践!

package com.example.volley_list;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.LruCache;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class MySingleton {
    private static MySingleton mInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
    private static Context mCtx;

    private MySingleton(Context context) {
        mCtx = context;
        mRequestQueue = getRequestQueue();

        mImageLoader = new ImageLoader(mRequestQueue,
                new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap>
                    cache = new LruCache<String, Bitmap>(20);

            @Override
            public Bitmap getBitmap(String url) {
                return cache.get(url);
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                cache.put(url, bitmap);
            }
        });
    }

    public static synchronized MySingleton getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new MySingleton(context);
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
        }
        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req) {
        getRequestQueue().add(req);
    }

    public ImageLoader getImageLoader() {
        return mImageLoader;
    }
}


方法调用

// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
    getRequestQueue();
...

// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest);


// Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值