Android网络框架-Volley实践 使用Volley打造自定义ListView

这篇文章翻译自Ravi Tamada博客中的Android Custom ListView with Image and Text using Volley

最终效果

这个ListView呈现了一些影视信息,每一行是一个影片的信息,每一行中有一张电影的图片,电影的名字、评分、类型、年份等信息。

1.json数据

我们通过解析json然后拿到数据,这个json数据包括json数组,每个json数组中是一个json对象,json对象中包括了电影的图片url地址、标题、年份、评分、类型等信息

JSON Url:http://api.androidhive.info/json/movies.json

[
    {
        "title": "Dawn of the Planet of the Apes",
        "image": "http://api.androidhive.info/json/movies/1.jpg",
        "rating": 8.3,
        "releaseYear": 2014,
        "genre": ["Action", "Drama", "Sci-Fi"]
    },
    ....
    ....
]

2.下载Volley库(volley.jar)

如果你第一次使用Volley框架,我建议你去我之前的文章看一下Android网络框架-Volley(一) 工作原理分析 。然后到百度上下载一个volley.jar。添加到项目的lib文件夹里面

3.布局分析

我选择了RelativeLayout来实现这个布局,图片我们使用volley提供的NetworkImageView

现在我们来新建一个Android项目

4.创建一个新的项目

1.打开eclipse,点击File-->New-->Android Application Project。填好基本信息后,我们把包名命名为info.androidhive.customlistviewvolley

2.将volley.jar添加到项目的lib文件夹下

3.我们先把包建好,我们一共分为4个包: adapter, app, model 和 util  。现在我们项目结构如下:

info.androidhive.customlistviewvolley.adater
info.androidhive.customlistviewvolley.app
info.androidhive.customlistviewvolley.model
info.androidhive.customlistviewvolley.util

4.打开res/values/colors.xml。如果没有colors.xml,我们就自己创建一个。然后添加如下代码


   
   

   
   
 
    
    
    
     
     #666666
    
    
    
    
    
     
     #888888
    
    
    
    
    
     
     #d9d9d9
    
    
    
    
    
     
     #ffffff
    
    
    
    
    
     
     #ffffff
    
    
    
    
    
     
     #ebeef0
    
    
    
    
    
     
     #ebeef0
    
    
 

   
   
5.打开res/values/dimens.xml。添加如下代码


    
    
         
    
     
     
      
      17dp
     
     
    
     
     
      
      15dip
     
     
    
     
     
      
      13dip
     
     
    
     
     
      
      12dip
     
     
 

    
    
6.在写jsva代码之前,我们先完成UI部分,在res下新建一个drawable文件夹,在res/drawable中新建3个xml文件: list_row_bg.xml、list_row_bg_hover.xmllist_row_selector.xml

list_row_bg.xml -没有被点击时listview的样式

     
     

     
     
  
      
      

     
     
list_row_bg_hover.xml -被点击后listview的样式

      
      

      
      
 
    
       
       
 

      
      
list_row_selector.xml -切换两种样式的slector文件

       
       

       
       
 
    
        
        
    
        
        
    
        
        
 

       
       
7.打开 activity_main.xml 添加listview


   
   
 
    
    
    
 

   
   

8.创建每个item的布局文件 list_row.xml

     
     

     
     
 
    
      
      
    
      
      
 
    
      
      
    
      
      
 
    
      
      
    
      
      
     
    
      
      
    
      
      
 
    
      
      
    
      
      
 

     
     
UI部分我们已经完成了,接下来是java代码部分
9.在util包下新建 LruBitmapCache.java  这个类是用来缓存图片的,这个类我们在之前文章中已经分析过了。参见 Android网络框架-Volley(二) RequestQueue源码分析以及建立一个RequestQueue
package info.androidhive.customlistviewvolley.util;
 
import com.android.volley.toolbox.ImageLoader.ImageCache;
 
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
 
public class LruBitmapCache extends LruCache
     
     
      
       implements
        ImageCache {
    public static int getDefaultLruCacheSize() {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 2;
 
        return cacheSize;
    }
 
    public LruBitmapCache() {
        this(getDefaultLruCacheSize());
    }
 
    public LruBitmapCache(int sizeInKiloBytes) {
        super(sizeInKiloBytes);
    }
 
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }
 
    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }
 
    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
}

     
     
10.在app包下新建 AppController.java  这个类是用来创建一个单例RequestQueue的,以及初始化一些volley核心对象
package info.androidhive.customlistviewvolley.app;
 
import info.androidhive.customlistviewvolley.util.LruBitmapCache;
import android.app.Application;
import android.text.TextUtils;
 
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
 
public class AppController extends Application {
 
    public static final String TAG = AppController.class.getSimpleName();
 
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;
 
    private static AppController mInstance;
 
    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }
 
    public static synchronized AppController getInstance() {
        return mInstance;
    }
 
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
 
        return mRequestQueue;
    }
 
    public ImageLoader getImageLoader() {
        getRequestQueue();
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader(this.mRequestQueue,
                    new LruBitmapCache());
        }
        return this.mImageLoader;
    }
 
    public 
      
      
       
        void addToRequestQueue(Request
       
       
        
         req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }
 
    public 
        
        
         
          void addToRequestQueue(Request
         
         
          
           req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }
 
    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

         
         
        
        
       
       
      
      
11.现在我们要在 AndroidManifest.xml  中注册这个AppController,并且添加上网络权限

       
       

       
       
 
    
        
        
 
    
        
        
 
    
        
        
        
         
         
            
          
          
                
           
           
 
                
           
           
            
          
          
        
         
         
    
        
        
 

       
       
12.现在在model包下创建一个Movie实体类,解析完的json数据会保存到这个实体类中
package info.androidhive.customlistviewvolley.model;
 
import java.util.ArrayList;
 
public class Movie {
    //title=标题, thumbnailUrl=图片地址
    private String title, thumbnailUrl;
    //年份
    private int year;
    //评分
    private double rating;
    //类别
    private ArrayList
        
        
         
          genre;
 
    public Movie() {
    }
 
    public Movie(String name, String thumbnailUrl, int year, double rating,
            ArrayList
         
         
          
           genre) {
        this.title = name;
        this.thumbnailUrl = thumbnailUrl;
        this.year = year;
        this.rating = rating;
        this.genre = genre;
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String name) {
        this.title = name;
    }
 
    public String getThumbnailUrl() {
        return thumbnailUrl;
    }
 
    public void setThumbnailUrl(String thumbnailUrl) {
        this.thumbnailUrl = thumbnailUrl;
    }
 
    public int getYear() {
        return year;
    }
 
    public void setYear(int year) {
        this.year = year;
    }
 
    public double getRating() {
        return rating;
    }
 
    public void setRating(double rating) {
        this.rating = rating;
    }
 
    public ArrayList
          
          
           
            getGenre() {
        return genre;
    }
 
    public void setGenre(ArrayList
           
           
            
             genre) {
        this.genre = genre;
    }
 
}

           
           
          
          
         
         
        
        
13.在adapter包下新建一个 CustomListAdapter.java  adapter会将item布局加载出来,并且将数据显示到listview上面
package info.androidhive.customlistviewvolley.adater;
 
import info.androidhive.customlistviewvolley.R;
import info.androidhive.customlistviewvolley.app.AppController;
import info.androidhive.customlistviewvolley.model.Movie;
 
import java.util.List;
 
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
 
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;
 
public class CustomListAdapter extends BaseAdapter {
    private Activity activity;
    private LayoutInflater inflater;
    private List
         
         
          
           movieItems;
    ImageLoader imageLoader = AppController.getInstance().getImageLoader();
 
    public CustomListAdapter(Activity activity, List
          
          
           
            movieItems) {
        this.activity = activity;
        this.movieItems = movieItems;
    }
 
    @Override
    public int getCount() {
        return movieItems.size();
    }
 
    @Override
    public Object getItem(int location) {
        return movieItems.get(location);
    }
 
    @Override
    public long getItemId(int position) {
        return position;
    }
 
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
 
        if (inflater == null)
            inflater = (LayoutInflater) activity
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (convertView == null)
            convertView = inflater.inflate(R.layout.list_row, null);
 
        if (imageLoader == null)
            imageLoader = AppController.getInstance().getImageLoader();
        NetworkImageView thumbNail = (NetworkImageView) convertView
                .findViewById(R.id.thumbnail);
        TextView title = (TextView) convertView.findViewById(R.id.title);
        TextView rating = (TextView) convertView.findViewById(R.id.rating);
        TextView genre = (TextView) convertView.findViewById(R.id.genre);
        TextView year = (TextView) convertView.findViewById(R.id.releaseYear);
 
        // getting movie data for the row
        Movie m = movieItems.get(position);
 
        // thumbnail image
        thumbNail.setImageUrl(m.getThumbnailUrl(), imageLoader);
         
        // title
        title.setText(m.getTitle());
         
        // rating
        rating.setText("Rating: " + String.valueOf(m.getRating()));
         
        // genre
        String genreStr = "";
        for (String str : m.getGenre()) {
            genreStr += str + ", ";
        }
        genreStr = genreStr.length() > 0 ? genreStr.substring(0,
                genreStr.length() - 2) : genreStr;
        genre.setText(genreStr);
         
        // release year
        year.setText(String.valueOf(m.getYear()));
 
        return convertView;
    }
 
}

          
          
         
         
14.打开我们的MainActivity.java。添加如下代码,我们使用JsonArrayRequest来发送请求,发送json请求我们在 Android网络框架-Volley(四) 使用get和post方法发送json请求 已经讲过了。我们将解析来的Movie对象存储在一个ArrayList中,调用notifyDataSetChanged()方法通知listview去更新我们的数据。
package info.androidhive.customlistviewvolley;
 
import info.androidhive.customlistviewvolley.adater.CustomListAdapter;
import info.androidhive.customlistviewvolley.app.AppController;
import info.androidhive.customlistviewvolley.model.Movie;
 
import java.util.ArrayList;
import java.util.List;
 
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.ListView;
 
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.JsonArrayRequest;
 
public class MainActivity extends Activity {
    // 用来打Log日志的TAG
    private static final String TAG = MainActivity.class.getSimpleName();
 
    // JSON地址
    private static final String url = "http://api.androidhive.info/json/movies.json";
    private ProgressDialog pDialog;
    //用来存储Movie对象的list
    private List
          
          
           
            movieList = new ArrayList
           
           
            
            ();
    private ListView listView;
    private CustomListAdapter adapter;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        listView = (ListView) findViewById(R.id.list);
        adapter = new CustomListAdapter(this, movieList);
        listView.setAdapter(adapter);
 
        pDialog = new ProgressDialog(this);
        // 加载框
        pDialog.setMessage("Loading...");
        pDialog.show();
 
        // 发送一个Json请求
        JsonArrayRequest movieReq = new JsonArrayRequest(url,
                new Response.Listener
            
            
             
             () {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d(TAG, response.toString());
                        hidePDialog();
 
                        // 解析json数据
                        for (int i = 0; i < response.length(); i++) {
                            try {
 
                                JSONObject obj = response.getJSONObject(i);
                                Movie movie = new Movie();
                                movie.setTitle(obj.getString("title"));
                                movie.setThumbnailUrl(obj.getString("image"));
                                movie.setRating(((Number) obj.get("rating"))
                                        .doubleValue());
                                movie.setYear(obj.getInt("releaseYear"));
 
                                // Genre是一个json数组
                                JSONArray genreArry = obj.getJSONArray("genre");
                                ArrayList
             
             
              
               genre = new ArrayList
              
              
                (); for (int j = 0; j < genreArry.length(); j++) { genre.add((String) genreArry.get(j)); } movie.setGenre(genre); // 将解析好的一个movie对象添加到list中 movieList.add(movie); } catch (JSONException e) { e.printStackTrace(); } } // 通知listview我们的数据已经改变,现在更新 adapter.notifyDataSetChanged(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.d(TAG, "Error: " + error.getMessage()); hidePDialog(); } }); // 将request添加到requestQueue中 AppController.getInstance().addToRequestQueue(movieReq); } @Override public void onDestroy() { super.onDestroy(); hidePDialog(); } private void hidePDialog() { if (pDialog != null) { pDialog.dismiss(); pDialog = null; } } @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; } } 
              
             
             
            
            
           
           
          
          



  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值