ListView中不同类型view的实现
首先创建请求队列,一个活动中只需要一个,因此放在Application中:
public class MyApplication extends Application{ private static RequestQueue requestQueue; @Override public void onCreate() { super.onCreate(); requestQueue = Volley.newRequestQueue(getApplicationContext()); } public static RequestQueue getRequestQueue(){ return requestQueue; } }
注意:需要在清单文件中注册o~
<application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
然后我们需要下载并解析json数据,这时候就需要自定义request继承request了,这里需要一个泛型参数,一般需要解析什么就设置什么,但是推荐使用泛型T,这样可以更方便为我们所使用了
NewsBeanRequest:
/** * Created by Administrator on 2016/9/27. */ public class NewsBeanRequest extends Request<NewsBean> { private Response.Listener<NewsBean> listener; public NewsBeanRequest(int method, String url, Response.ErrorListener listener, Response.Listener<NewsBean> listener1) { super(method, url, listener); this.listener = listener1; } @Override protected Response<NewsBean> parseNetworkResponse(NetworkResponse response) { NewsBean newsBean = new NewsBean(); Gson gson = new Gson(); try { newsBean = gson.fromJson(new String(response.data, HttpHeaderParser.parseCharset(response.headers)),NewsBean.class); } catch (UnsupportedEncodingException e) { newsBean = gson.fromJson(new String(response.data),NewsBean.class); } return Response.success(newsBean, HttpHeaderParser.parseCacheHeaders(response)); } @Override protected void deliverResponse(NewsBean response) { listener.onResponse(response); } }
上面代码分为三部分:
0.定义构造方法,传入请求网络需要的参数,通过父类去请求网络
1.解析网络请求的响应结果,将 字节数组类型的数据转换成自己想要的 T (通常是java bean数据模型)
2.deliverResponse(T response) 分发响应结果(处理监听)调用请求成功的监听器
接下来就是主程序了,
main:
public class MainActivity extends AppCompatActivity { private ListView listview; private RequestQueue requestQueue; private static final String URL = "http://ikft.house.qq.com/index.php?guid=866500021200250&devua=appkft_1080_1920_XiaomiMI4LTE_1.8.3_Android19&devid=866500021200250&appname=QQHouse&mod=appkft&reqnum=&pageflag=&act=newslist&channel=71&buttonmore=&cityid=1"; private List<NewsBean.DataBean> dataList = new ArrayList<>(); private NewsListAdapter newsListAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listview = (ListView) findViewById(R.id.listview); //创建适配器 newsListAdapter = new NewsListAdapter(this,dataList); //设置适配器 listview.setAdapter(newsListAdapter); //1,创建RequestQueue requestQueue = MyApplication.getRequestQueue(); //2.自定义对象请求 NewsBeanRequest newsBeanRequest = new NewsBeanRequest(Request.Method.GET, URL, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.i("tag", "下载数据失败"); } }, new Response.Listener<NewsBean>() { @Override public void onResponse(NewsBean response) { //返回的数据为下载并解析后的newsBean对象 newsListAdapter.addData(response.getData()); } }); //设置标记 newsBeanRequest.setTag(URL); //3.添加到请求队列中 requestQueue.add(newsBeanRequest); } @Override protected void onDestroy() { super.onDestroy(); //4.取消该标记对应的请求 requestQueue.cancelAll(URL); } }
一般的从网上获取数据就是上面这四步了,
给请求设置一个tag是为了请求队列取消请求的时候,可以通过tag来取消tag对应的请求
还有一种方式可以取消:newsBeanrequest.canel();//取消自己
一般在活动销毁的时候将请求也取消
接下来就是适配器中对数据进行设置了:
class NewsListAdapter extends BaseAdapter { private Context context; private List<NewsBean.DataBean>dataList; public NewsListAdapter(Context context, List<NewsBean.DataBean> dataList) { this.context = context; this.dataList = dataList; } /** *添加数据 * @param dataList */ public void addData(List<NewsBean.DataBean> dataList){ this.dataList.addAll(dataList); notifyDataSetChanged(); } @Override public int getCount() { return dataList.size(); } @Override public Object getItem(int position) { return dataList.get(position); } @Override public long getItemId(int position) { return position; } /* 获得当前adapter中view的种类的数量*/ @Override public int getViewTypeCount() { return 2; } /*根据position来获得当前的要显示的item的view类型*/ @Override public int getItemViewType(int position) { return new Integer(dataList.get(position).getType()); } @Override public View getView(int position, View convertView, ViewGroup parent) { //得到当前复用的view的类型 // int type = Integer.parseInt(dataList.get(position).getType()); //得打NewsBean.DataBean中的参数int type int type = getItemViewType(position); NewsBean.DataBean dataBean = dataList.get(position); //1.创建ImageLoader对象 ImageLoader imageLoader = new ImageLoader(MyApplication.getRequestQueue(),new MyImageCache()); ViewHolder1 viewHolder1 = null; ViewHolder2 viewHolder2 = null; switch (type){ case 0: if(convertView == null){ convertView = LayoutInflater.from(context).inflate(R.layout.listview_item_news_1,parent,false); viewHolder1 = new ViewHolder1(convertView); convertView.setTag(viewHolder1); }else{ viewHolder1 = (ViewHolder1)convertView.getTag(); } viewHolder1.tvSummary.setText(dataBean.getSummary()); viewHolder1.tvTitle.setText(dataBean.getTitle()); //2.声明监听 ImageLoader.ImageListener listener = ImageLoader.getImageListener(viewHolder1.imgGroupthumbnail, R.mipmap.ic_launcher, R.mipmap.ic_launcher); //3.加载图片 imageLoader.get(dataBean.getGroupthumbnail(),listener); break; case 1: if(convertView ==null){ convertView = View.inflate(context,R.layout.listview_item_news_2,null); viewHolder2 = new ViewHolder2(convertView); convertView.setTag(viewHolder2); }else{ viewHolder2 = (ViewHolder2)convertView.getTag(); } ImageLoader.ImageListener listener1 = ImageLoader.getImageListener(viewHolder2.imgGroupthumbnail, R.mipmap.ic_launcher, R.mipmap.ic_launcher); imageLoader.get(dataBean.getGroupthumbnail(),listener1); break; } return convertView; } class ViewHolder1 { public ImageView imgGroupthumbnail; public TextView tvTitle; public TextView tvSummary; public ViewHolder1(View view) { this.imgGroupthumbnail = (ImageView) view.findViewById(R.id.img_groupthumbnail); this.tvTitle = (TextView) view.findViewById(R.id.tv_title); this.tvSummary = (TextView) view.findViewById(R.id.tv_summary); } } class ViewHolder2 { public ImageView imgGroupthumbnail; public ViewHolder2(View view) { this.imgGroupthumbnail = (ImageView) view.findViewById(R.id.img_groupthumbnail); } } class MyImageCache implements ImageLoader.ImageCache{ private LruCache<String,Bitmap> lruCache; public MyImageCache() { lruCache = new LruCache<String,Bitmap>((int) (Runtime.getRuntime().maxMemory()/8)){ @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; } @Override public Bitmap getBitmap(String url) { return lruCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { lruCache.put(url,bitmap); } } }
方法解析:
addData:自定义的对外暴露的添加数据的方法,当数据发生改变的时候调用,添加数据
重写适配器中的两个方法,
getViewTypeCount()//得到类型的个数
getItemViewType()//得到当前复用view的类型
在adapter的getView方法中,得到当前显示view的type并判断,然后根据判断的type类型对该类型对应的view布局来进行操作
,如果可复用的布局为空,首先得到当前需要显示的布局,布局通过布局加载器来加载布局,并传入自定义类ViewHolder中,而viewholder的作用是装载控件的,我们可以通过id找到布局中对应的控件,最后,该viewHolder设置为convertview的一个标记,然后我们就可以通过dataList.get(position)得到当前item的数据,并设置到控件上了,当然,如果当前可复用的view不为空,直接通过getTag()方法就可以得到viewHolderl ,操作同上
我们下载图片是通过imageLoader来实现的
ImageLoader是一个图片加载器,可以设置缓存,
首先创建一个ImageLoader对象,里面传递两个参数,
第一个参数是请求队列,一般通过Volley.newRequestQueue来获取,但是一般一个activity中有一个就足够,因此我设置到了MyApplication中.
第二个参数是图片缓存的实现类对象,里面实现了两个方法,分别是对图片的取和存,不过得先创建一个内存缓存,我将他的实现放在了构造方法里面,这样在创建该对象的时候就直接创建了,创建对象需要传入一个参数,该参数指定缓存的大小,这里我设置的是总空间大小的1/8,然后重写sizeOf方法返回每张图片的大小,当构造方法中设置的是一个固定的数值的时候,返回参数设置为1
然后为图片设置监听器:监听回调的数据
参数1: 需要展示图片的imageview , 2.默认图片 3.错误图片
最后ImageLoader加载图片
放入请求队列
参数1:path 网络地址 参数2: 请求成功的监听,请求成功会回调listener
imageLoader.get(path,imagelistener);
现在图片也下载完成了,我们可以看到效果: