前面的博客中介绍了在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>
Xml中的字段解释:
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();
}
}
}
5、在配置文件中添加一条访问网络的权限
<uses-permission android:name="android.permission.INTERNET"/>