前面的博客中介绍了在Android中实现网络通信,这篇博客将是对前面介绍的技术的一个综合运用,制作一个简单的新闻客户端,在这个新闻客户端中用到了ListView、ListView的优化、使用开源框架访问网络图片、使用pull解析xml文件等技术,这些技术都是前面的博客中介绍的
首先看一下新闻客户端的演示效果
实现方式:
第一步:将新闻中用到的图片部署到Tomcat服务器上,部署方法可以参考我的博客:在Windows下安装Tomcat服务器
第二步:新建一个xml文件用于保存新闻中的标题、新闻的内容、评论数、新闻中图片所在的地址、xml文件如下
<?xml version="1.0" encoding="UTF-8" ?> <newslist> <news> <title>黑马52期就业快报</title> <detail>热烈祝贺黑马52期平均薪水突破13k</detail> <comment>15687</comment> <image>http://192.168.1.101:8080/app/images/6.jpg</image> </news> <news> <title>程序员因写代码太乱被杀害</title> <detail>凶手是死者同事,维护死者代码时完全看不懂而痛下杀手</detail> <comment>16359</comment> <image>http://192.168.1.101:8080/app/images/7.jpg</image> </news> <news> <title>产品经理因频繁改需求被杀害</title> <detail>凶手是一名程序员,因死者对项目需求频繁改动而痛下杀手</detail> <comment>14112</comment> <image>http://192.168.1.101:8080/app/images/7.jpg</image> </news> <news> <title>3Q大战宣判: 腾讯获赔500万</title> <detail>最高法驳回360上诉, 维持一审宣判.</detail> <comment>6427</comment> <image>http://192.168.1.101:8080/app/images/1.jpg</image> </news> <news> <title>今日之声:北大雕塑被戴口罩</title> <detail>市民: 因雾霾起诉环保局; 公务员谈"紧日子": 坚决不出去.</detail> <comment>681</comment> <image>http://192.168.1.101:8080/app/images/2.jpg</image> </news> <news> <title>奥巴马见达赖是装蒜</title> <detail>外文局: 国际民众认可中国大国地位;法院: "流量清零"未侵权.</detail> <comment>1359</comment> <image>http://192.168.1.101:8080/app/images/3.jpg</image> </news> <news> <title>轻松一刻: 我要沉迷学习不自拔</title> <detail>放假时我醒了不代表我起床了, 如今我起床了不代表我醒了!</detail> <comment>11616</comment> <image>http://192.168.1.101:8080/app/images/4.jpg</image> </news> <news> <title>男女那些事儿</title> <detail>"妈, 我在东莞被抓, 要2万保释金, 快汇钱到xxx!"</detail> <comment>10339</comment> <image>http://192.168.1.101:8080/app/images/5.jpg</image> </news> <news> <title>赵帅哥语录一</title> <detail>少壮不努力,老大做IT</detail> <comment>14612</comment> <image>http://192.168.1.101:8080/app/images/8.jpg</image> </news> <news> <title>赵帅哥语录二</title> <detail>问君能有几多愁,恰似调完代码改需求</detail> <comment>13230</comment> <image>http://192.168.1.101:8080/app/images/8.jpg</image> </news> <news> <title>赵帅哥语录三</title> <detail>觉得我帅的人工资一般都比较高</detail> <comment>9928</comment> <image>http://192.168.1.101:8080/app/images/8.jpg</image> </news> <news> <title>今日之声:北大雕塑被戴口罩</title> <detail>市民: 因雾霾起诉环保局; 公务员谈"紧日子": 坚决不出去.</detail> <comment>681</comment> <image>http://192.168.1.101:8080/app/images/2.jpg</image> </news> <news> <title>奥巴马见达赖是装蒜</title> <detail>外文局: 国际民众认可中国大国地位;法院: "流量清零"未侵权.</detail> <comment>1359</comment> <image>http://192.168.1.101:8080/app/images/3.jpg</image> </news> </newslist>
title:新闻的标题
detail:新闻的内容
comment:新闻的评论数
image:新闻中图片所在的网址
创建完后将Xml文件部署到Tomcat服务器上
第三步:使用Android Studio创建一个Android工程
1、修改activity_main.xml文件,在activity_main.xml中添加一个ListView控件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.fyt.newsclient.MainActivity"> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </RelativeLayout>
2、新建一个item_listview.xml的布局文件,用于设置ListView中的条目的布局,在这个布局中用到了一个自定义控件
SmartImageView控件,SmartImageView控件的用法可以参考我的博客: 使用开源框架制造网络图片查看器
item_listview.xml中的代码如下
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.loopj.android.image.SmartImageView android:id="@+id/iv" android:layout_width="90dp" android:layout_height="90dp" android:layout_centerVertical="true"/> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toRightOf="@+id/iv" android:textSize="22sp" android:singleLine="true" android:text="尝到了真人秀的甜头后,途牛又砸1.48亿在跑男上"/> <TextView android:id="@+id/tv_detail" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/tv_title" android:layout_toRightOf="@+id/iv" android:textColor="#aaa" android:lines="2" android:text="昨晚第四季《奔跑吧兄弟回归》,途牛是这一季的赞助商之一。"/> <TextView android:id="@+id/tv_comment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_detail" android:layout_alignParentRight="true" android:textColor="#ff0000" android:text="65031条评论"/> </RelativeLayout>
3、新建一个News类,用于处理新闻中的数据
package com.fyt.newsclient; //创建一个News类用于处理新闻 public class News { //新闻的标题 private String title; //新闻的详细介绍 private String detai; //新闻的评论数量 private int comment; //新闻中图片的URL private String imageUrl; //无参构造 public News() { } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDetai() { return detai; } public void setDetai(String detai) { this.detai = detai; } public int getComment() { return comment; } public void setComment(int comment) { this.comment = comment; } public String getImageUrl() { return imageUrl; } public void setImageURL(String imageUrl) { this.imageUrl = imageUrl; } @Override public String toString() { return "News{" + "title='" + title + '\'' + ", detai='" + detai + '\'' + ", comment=" + comment + ", imageUrl='" + imageUrl + '\'' + '}'; } }
4、修改MainActivity.java中的代码
package com.fyt.newsclient; import android.app.Activity; import android.os.Bundle; import android.util.Xml; import android.os.Handler; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import com.loopj.android.image.SmartImageView; import org.xmlpull.v1.XmlPullParser; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; public class MainActivity extends Activity { //用于创建保存新闻的集合 private List<News> newsList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获得新闻信息 getNewsInfo(); } //创建Handler对象,用于在主线程中接收并处理由子线程 //发送过来的消息 Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { //获得布局文件上的ListView控件 ListView listView = (ListView) findViewById(R.id.lv); //为ListView控件设置适配器 listView.setAdapter(new MyAdapter()); } }; //创建一个自定义的适配器类MyAdapter class MyAdapter extends BaseAdapter { //设置ListView中条目的个数,由系统调用 @Override public int getCount() { return newsList.size(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v; ViewHolder mHolder; //如果ListView中的条目没有缓存 if(convertView == null) { //将布局文件填充成一个View对象 v = View.inflate(MainActivity.this, R.layout.item_listview, null); //创建一个ViewHolder对象 mHolder = new ViewHolder(); //把布局文件中所有组件的对象封装至ViewHolder对象中 mHolder.tv_title = (TextView) v.findViewById(R.id.tv_title); mHolder.tv_detail = (TextView) v.findViewById(R.id.tv_detail); mHolder.tv_comment = (TextView) v.findViewById(R.id.tv_comment); mHolder.siv = (SmartImageView) v.findViewById(R.id.iv); //把ViewHolder对象封装至View对象中 v.setTag(mHolder); } //ListView中的条目有缓存 else { v = convertView; //从缓存中获得ViewHolder对象 mHolder = (ViewHolder) v.getTag(); } //设置新闻的标题 mHolder.tv_title.setText(newsList.get(position).getTitle()); //设置新闻的内容 mHolder.tv_detail.setText(newsList.get(position).getDetai()); //设置评论的数量 mHolder.tv_comment.setText(newsList.get(position).getComment()+"条评论"); //下载并显示图片 mHolder.siv.setImageUrl(newsList.get(position).getImageUrl()); return v; } class ViewHolder{ //条目的布局文件中有什么组件,这里就定义什么属性 TextView tv_title; TextView tv_detail; TextView tv_comment; SmartImageView siv; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } } //获得新闻信息 public void getNewsInfo() { //创建一个子线程 Thread t = new Thread() { //执行子线程 @Override public void run() { //设置新闻所在的xml文件的地址 String path = "http://192.168.1.101:8080/app/news.xml"; try { //将地址封装成URL对象 URL url = new URL(path); //获取连接对象,此时未建立连接 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //设置请求方式为Get请求 conn.setRequestMethod("GET"); //设置连接超时 conn.setConnectTimeout(5000); //设置读取超时 conn.setReadTimeout(5000); //如果请求成功 if(conn.getResponseCode() == 200) { //获得文件输入流 InputStream is = conn.getInputStream(); //使用pull解析器解析文件输入流中的xml文件 parseNewsXml(is); } } catch (Exception e) { e.printStackTrace(); } } }; //启动子线程 t.start(); } //使用pull解析器解析文件输入流中的xml文件 public void parseNewsXml(InputStream is) { //创建pull解析器对象 XmlPullParser xp = Xml.newPullParser(); try { //将输入流中的数据以utf-8格式输入到pull解析器 xp.setInput(is, "utf-8"); //判断节点的事件类型 //可以知道当前节点是什么节点 int type = xp.getEventType(); //定义一个News变量,用于创建新闻对象 News news = null; while (type != XmlPullParser.END_DOCUMENT) { switch (type) { case XmlPullParser.START_TAG: if("newslist".equals(xp.getName())) { newsList = new ArrayList<News>(); } else if("news".equals(xp.getName())) { news = new News(); } else if("title".equals(xp.getName())) { String title = xp.nextText(); news.setTitle(title); } else if("detail".equals(xp.getName())) { String detail = xp.nextText(); news.setDetai(detail); } else if("comment".equals(xp.getName())) { int comment = Integer.parseInt(xp.nextText()); news.setComment(comment); } else if("image".equals(xp.getName())) { String image = xp.nextText(); news.setImageURL(image); } break; case XmlPullParser.END_TAG: if("news".equals(xp.getName())){ newsList.add(news); } break; } //解析完当前节点后,把指针移动至下一个节点,并返回它的事件类型 type = xp.next(); } //发送空消息到主线程并且让主线程设置listview的适配器 //如果消息不需要携带数据,可以发送空消息 handler.sendEmptyMessage(1); } catch (Exception e) { e.printStackTrace(); } } }
<uses-permission android:name="android.permission.INTERNET"/>