先看服务端的代码(对象封装类和servlet类)
ShopInfo.java(get、set、构造器、toString方法省略)
- private String name;
- private String img;
- package com.atguigu.dianpin_server.servlet;
- import java.io.File;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.google.gson.Gson;
- /**
- * 获取分页ShopList的json字符串
- */
- public class ShopListServlet extends HttpServlet {
- private List<ShopInfo> infos;
- protected void doGet(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
- init();
- // 得到start和count的请求参数
- int start = Integer.parseInt(request.getParameter("start"));
- int count = Integer.parseInt(request.getParameter("count"));
- // 如果start太大, 就返回一个空串
- // 15 start=15
- if (start >= infos.size()) {
- response.getWriter().write("");
- return;
- }
- // 从集合中取当前请求页的数据集合
- List<ShopInfo> data = new ArrayList<ShopInfo>();
- // 11 start=10&count=5
- if (start + count > infos.size()) {
- count = infos.size() - start;
- }
- for (int i = 0; i < count; i++) {
- data.add(infos.get(start + i));
- }
- // 转换为json字符串
- String json = new Gson().toJson(data);
- // 写到客户端
- response.setContentType("text/json;charset=utf-8");
- response.getWriter().write(json);
- // [{"name":"商铺名称1", "img":"f1.jpg"},{"name":"商铺名称2", "img":"f12.jpg"}]
- }
- public void init() {
- if (infos == null) {
- infos = new ArrayList<ShopInfo>();
- // 得到/image的真实路径
- String imagesPath = getServletContext().getRealPath("/image");
- // 得到路径对象
- File dirFile = new File(imagesPath);
- // 得到所有图片file对象
- File[] files = dirFile.listFiles();
- // 遍历
- for (int i = 0; i < files.length; i++) {
- // 将图片信息封装为一个shopinfo对象, 并保存到集合中
- String imageName = files[i].getName();
- String name = "商铺名称 " + (i + 1);
- infos.add(new ShopInfo(name, imageName));
- }
- }
- }
- }
看android代码
先贴出布局来
activity_main.xml
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
- <com.handmark.pulltorefresh.library.PullToRefreshListView
- android:id="@+id/lv_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <ProgressBar
- android:id="@+id/pb_main"
- style="?android:attr/progressBarStyleLarge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"/>
- </FrameLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="100dp"
- android:orientation="horizontal"
- android:gravity="center_vertical">
- <com.android.volley.toolbox.NetworkImageView
- android:id="@+id/iv_img"
- android:layout_width="90dp"
- android:layout_height="90dp"/>
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="描述文本"
- android:layout_marginLeft="20dp"
- android:textSize="20sp"/>
- </LinearLayout>
- <?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="wrap_content"
- android:orientation="horizontal"
- android:gravity="center"
- android:clickable="false"
- android:focusable="false">
- <ProgressBar
- android:id="@+id/pb_foot"
- style="?android:attr/progressBarStyle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/tv_foot"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="正在加载中..." />
- </LinearLayout>
- <!--
- 1. 如果还有更多数据, 它就会显示
- 2. 如果没有更多数据: 隐藏ProgressBar, 更新TextView的文本
- -->
ShopInfo.java(get、set、构造器、toString方法省略)
- private String name;
- private String img;
VolleyTool.java(框架的工具类)
- package com.atguigu.day03_test;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.support.v4.util.LruCache;
- import com.android.volley.RequestQueue;
- import com.android.volley.toolbox.ImageLoader;
- import com.android.volley.toolbox.ImageLoader.ImageCache;
- import com.android.volley.toolbox.Volley;
- public class VolleyTool {
- //初始化请求队列、图片加载器
- private RequestQueue queue;
- private ImageLoader imageLoader;
- //私有静态实例
- private static VolleyTool instance;
- //私有构造方法
- private VolleyTool(Context context) {
- //创建请求队列
- queue = Volley.newRequestQueue(context);
- //创建图片加载器
- imageLoader = new ImageLoader(queue, new LruImageCache());
- }
- //公共、静态的方法
- public static VolleyTool getInstance(Context context) {
- if (instance == null) {
- instance = new VolleyTool(context);
- }
- return instance;
- }
- //得到请求队列
- public RequestQueue getQueue() {
- return queue;
- }
- //得到图片加载器
- public ImageLoader getImageLoader() {
- return imageLoader;
- }
- /**
- * 使用LRU回收算法的缓存类
- */
- class LruImageCache implements ImageCache {
- // 缓存容器
- private LruCache<String, Bitmap> cache;
- public LruImageCache() {
- // 计算缓存的最值
- int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);
- //创建缓存对象实例
- cache = new LruCache<String, Bitmap>(maxSize) {
- @Override
- protected int sizeOf(String key, Bitmap value) {
- // 返回bitmap占用的内存大小
- return value.getRowBytes() * value.getHeight();
- }
- };
- }
- // 从缓存中取图片对象
- @Override
- public Bitmap getBitmap(String url) {
- return cache.get(url);
- }
- // 将图片对象保存到缓存容器中
- @Override
- public void putBitmap(String url, Bitmap bitmap) {
- cache.put(url, bitmap);
- }
- }
- }
- package com.atguigu.day03_test;
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ListView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.android.volley.Request;
- import com.android.volley.RequestQueue;
- import com.android.volley.Response;
- import com.android.volley.Response.Listener;
- import com.android.volley.VolleyError;
- import com.android.volley.toolbox.NetworkImageView;
- import com.android.volley.toolbox.StringRequest;
- import com.google.gson.Gson;
- import com.google.gson.reflect.TypeToken;
- import com.handmark.pulltorefresh.library.PullToRefreshBase;
- import com.handmark.pulltorefresh.library.PullToRefreshListView;
- public class MainActivity extends Activity {
- // 进度条
- private ProgressBar pb_main;
- // 请求队列
- RequestQueue requestQueue;
- // 显示存放服务端数据的listView
- private PullToRefreshListView lv_main;
- // 数据对象集合
- private List<ShopInfo> data = new ArrayList<ShopInfo>();
- // 适配器
- private MainAdapter adapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 定义的PullToRefreshListView需要转型
- lv_main = (PullToRefreshListView) findViewById(R.id.lv_main);
- // 下拉刷新的监听
- lv_main.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>() {
- @Override
- public void onRefresh(PullToRefreshBase<ListView> refreshView) {
- //定义一个标示,如果为true,代表下拉
- loadData(true);
- }
- });
- // 上拉加载的刷新
- lv_main.setOnLastItemVisibleListener(new PullToRefreshBase.OnLastItemVisibleListener() {
- @Override
- public void onLastItemVisible() {
- // pb_foot.isShown()说明数据没有加载完毕
- if (pb_foot.isShown()) {
- //定义一个标示,如果为false,代表上拉
- loadData(false);
- }
- }
- });
- // 创建进度条对象
- pb_main = (ProgressBar) findViewById(R.id.pb_main);
- // 得到请求队列
- requestQueue = VolleyTool.getInstance(getApplicationContext())
- .getQueue();
- // 添加一个footView(上拉松开加载)
- addFootView();
- // 初始化加载数据显示(false或者true均可)
- loadData(false);
- }
- /**
- * 添加一个footView 1. 如果还有更多数据, 它就会显示 2. 如果没有更多数据: 隐藏ProgressBar, 更新TextView的文本
- */
- private ProgressBar pb_foot;
- private TextView tv_foot;
- private void addFootView() {
- View footView = View.inflate(this, R.layout.listview_foot, null);
- pb_foot = (ProgressBar) footView.findViewById(R.id.pb_foot);
- tv_foot = (TextView) footView.findViewById(R.id.tv_foot);
- lv_main.getRefreshableView().addFooterView(footView);
- }
- /*
- * 页面上下滑动,如果还没有加载完毕,就快速滑动过去
- * 这样消耗内存 定义一个标记,标记的意思是--某次请求是否正在加载图片(默认没有加载,表明已经加载过)
- */
- private boolean loading = false;
- private void loadData(final boolean reset) {
- /*
- * 如果正在加载,直接结束,从新滑到的图片无需继续加载了
- */
- if (loading)
- return;
- // 一旦方法执行,就将标记改成true,说明正在加载
- loading = true;
- // 计算start-如果加载第一页就是0,如果不是第一页就是data.size
- int start = reset ? 0 : data.size();
- // data.size()==10 -->start=10
- String url = "http://192.168.30.41:8090/dianpin_03/ShopListServlet?start="
- + start + "&count=5";
- // 创建一个请求
- Request request = new StringRequest(url, new Listener<String>() {
- @Override
- public void onResponse(String response) {
- /*
- * 从服务器得到数据,一旦该方法触发,说明某次请求已经加载完毕图片了 要将标记改为false,说明已经加载完毕,无需加载了
- */
- loading = false;
- /*
- * 即使加载完毕,如果继续往下拉的话,还会发送请求 这里需要判断服务器端返回null值的情况(查看服务端代码)
- */
- if ("".equals(response)) {
- // 隐藏ProgressBar, 更新TextView的文本
- pb_foot.setVisibility(View.GONE);
- tv_foot.setText("已加载完部数据");
- // 将该方法直接返回,无需继续往下执行了
- return;
- }
- // 将服务器端的json数组解析为ShopInfo对象集合
- List<ShopInfo> newData = new Gson().fromJson(response,
- new TypeToken<List<ShopInfo>>() {
- }.getType());
- // 因为每次请求5个json对象,如果返回小于5说明已经加载完所有的数据了
- if (newData.size() < 5) {
- // 隐藏ProgressBar, 更新TextView的文本
- pb_foot.setVisibility(View.GONE);
- tv_foot.setText("已加载完部数据");
- }
- /*
- * 第一次加载 lv_main.setAdapter(adapter);
- * 说明只显示第一页的数据
- */
- if (adapter == null) {
- data = newData;
- adapter = new MainAdapter();
- lv_main.setAdapter(adapter);
- pb_main.setVisibility(View.GONE);
- } else {
- if (reset) {
- // 如果适配器不为null,并且下拉刷新,需要清空数据,只加载第一页
- data.clear();
- // 显示加载更多
- pb_foot.setVisibility(View.VISIBLE);
- tv_foot.setText("下拉加载更多");
- lv_main.onRefreshComplete();
- }
- // 不是第一次加载,就需要将每次获取的数据放到data集合中
- data.addAll(newData);
- adapter.notifyDataSetChanged();
- }
- }
- }, new Response.ErrorListener() {
- @Override
- public void onErrorResponse(VolleyError error) {
- Toast.makeText(getApplicationContext(), "请求服务器异常", 0).show();
- }
- });
- // 将请求添加到队列中, 自动处理
- requestQueue.add(request);
- }
- /**
- * 适配器代码
- */
- class MainAdapter extends BaseAdapter {
- @Override
- public int getCount() {
- return data.size();
- }
- @Override
- public Object getItem(int position) {
- return data.get(position);
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ViewHolder holder = null;
- if (convertView == null) {
- holder = new ViewHolder();
- convertView = View.inflate(getApplicationContext(),
- R.layout.list_item, null);
- holder.imageView = (NetworkImageView) convertView
- .findViewById(R.id.iv_img);
- holder.textView = (TextView) convertView
- .findViewById(R.id.tv_name);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
- ShopInfo shopInfo = data.get(position);
- holder.textView.setText(shopInfo.getName());
- // 设置未加载默认图片
- holder.imageView.setDefaultImageResId(R.drawable.default_icon);
- // 设置加载异常的图片
- holder.imageView.setErrorImageResId(R.drawable.error);
- // 动态加载图片
- String url = "http://192.168.30.41:8090/dianpin_03/image/"
- + shopInfo.getImg();
- holder.imageView.setImageUrl(url,
- VolleyTool.getInstance(getApplicationContext())
- .getImageLoader());
- return convertView;
- }
- class ViewHolder {
- NetworkImageView imageView;
- TextView textView;
- }
- }
- }