制作一个简单的新闻客户端

前面的博客中介绍了在Android中实现网络通信,这篇博客将是对前面介绍的技术的一个综合运用,制作一个简单的新闻客户端,在这个新闻客户端中用到了ListView、ListView的优化、使用开源框架访问网络图片、使用pull解析xml文件等技术,这些技术都是前面的博客中介绍的

首先看一下新闻客户端的演示效果

制作一个简单的新闻客户端_第1张图片


实现方式:

第一步:将新闻中用到的图片部署到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"/>

你可能感兴趣的:(制作一个简单的新闻客户端)