一、摘要继上一篇博客《模仿网易新闻客户端(上)》之后,笔者继续开发我们自己的“网易新闻客户端”,由于找不到现成的url新闻链接地址,所以这里就用RSS订阅所提供的url,这里所用到的链接仍然是网易新闻中心的RSS地址http://www.163.com/rss/,然后通过解析xml内容,以ListView的方式呈现在手机界面上。还有一个问题,因为RSS所提供的xml资源里面,没有对应item的图片,所以,ListView里面每一个Item都没有图片,这点有点遗憾,但也没事,实现其功能就行了。废话不多说,老惯例,先看效果图
[img]http://www.eoeandroid.com/data/attachment/forum/201212/25/135448umt5valrithrcvm9.png[/img][img]http://www.eoeandroid.com/data/attachment/forum/201212/27/152058mjwj3jf3hw73awl7.png[/img][img]http://www.eoeandroid.com/data/attachment/forum/201212/27/152202q11y16c2cyvmn1sx.png[/img][img]http://www.eoeandroid.com/data/attachment/forum/201212/27/152315oc19xdsn5w3ha5ha.png[/img]

三、解析RSS

首先,先大概地看一下RSS所提供XML的数据结构,下面是一个RSS文件结构示例

<?xml version="1.0" encoding="GBK"?>  <?xml-stylesheet type="text/css" ?>  <rss version="2.0">  <channel>  <title>网易头条新闻</title>  <link><a href="\"http://news.163.com/</link\"" target="\"_blank\"">http://news.163.com/</link></a>  <description>网易头条新闻</description>  <pubDate>Mon, 2 Apr 2012 01:07:10 GMT</pubDate>  <lastBuildDate>Mon, 2 Apr 2012 01:07:10 GMT</lastBuildDate>  <item id="1">  <title>...</title>  <link><a href="\"http://news.163.com/12/0402/08/7U2TBKQF0001124J.html</link\"" target="\"_blank\"">http://news.163.com/12/0402/08/7U2TBKQF0001124J.html</link></a>  <description>......</description>  <pubDate>2012-04-02 09:07:10</pubDate>  </item>  </channel>  </rss>

了解了有哪些节点,下面来编写元数据类RSSItem.java

package com.and.netease.rss;

public class RSSItem {

    private String title;    private String link;    private String description;    private String pubDate;

    public RSSItem() {        super();    }

    public String getTitle() {        return title;    }

    public void setTitle(String title) {        this.title = title;    }

    public String getLink() {        return link;    }

    public void setLink(String link) {        this.link = link;    }

    public String getDescription() {        return description;    }

    public void setDescription(String description) {        this.description = description;    }

    public String getPubDate() {        return pubDate;    }

    public void setPubDate(String pubDate) {        this.pubDate = pubDate;    }

    @Override    public String toString() {        return "RSSItem [title=" + title + ", link=" + link + ", description="                + description + ", pubDate=" + pubDate + "]";    }

}

紧接着编写解析XML的Handler类:RSSHandler.java

package com.and.netease.rss;

import java.util.ArrayList;import java.util.List;

import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;

import android.text.Html;

public class RSSHandler extends DefaultHandler {

    private List<RSSItem> list;    private RSSItem item;    private String tag = "";

    private StringBuffer buffer;    @Override    public void characters(char[] ch, int start, int length)            throws SAXException {        super.characters(ch, start, length);        if(item!=null){            String data = new String(ch,start,length);            if(tag.equals("title")){                item.setTitle(data);            }else if(tag.equals("link")){                item.setLink(data);            }else if(tag.equals("description")){//                item.setDescription(data);                buffer.append(Html.fromHtml(data));            }else if(tag.equals("pubDate")){                item.setPubDate(data);            }        }    }

    @Override    public void endDocument() throws SAXException {        super.endDocument();    }

    @Override    public void endElement(String uri, String localName, String qName)            throws SAXException {        super.endElement(uri, localName, qName);        if(localName.equals("item")){            item.setDescription(buffer.toString());            list.add(item);            item = null;            buffer = null;        }        tag = "";    }

    @Override    public void startDocument() throws SAXException {        super.startDocument();        list = new ArrayList<RSSItem>();    }

    @Override    public void startElement(String uri, String localName, String qName,            Attributes attributes) throws SAXException {        super.startElement(uri, localName, qName, attributes);        if(localName.equals("item")){            item = new RSSItem();            buffer = new StringBuffer();        }        tag = localName;    }

    public List<RSSItem> getData(){        return list;    }

}

注意:在存description的值的时候,可能会出问题,有可能读取出来的全是省略号,因为第一次读取到数据,存入了相应的RSSItem实例变量中,第二次又读取到省略号,再存入当前的RSSItem实例中,造成最后只有第二次存入的值,因为它前面的文字和后面的省略号不是一次读取完的,所以我这里用了一个StringBuffer来存它,之后一次性地存入到当拉RSSItem中。当然有些提供的RSS源代码中不是这样的。具体需要自己测试一下才好。

当然,这里所解析的所有URL地址放在一个常量类里面的,开始本想放String.xml文件中,但是地址里面有特殊字符,为了简便,就专门定义了一个常量类用来存放URL地址,如下CONST.java

View Code 

package com.and.netease;

public class CONST {

    public static final String URL_NEWS_TOP = "http://news.163.com/special/00011K6L/rss_newstop.xml";    public static final String URL_NEWS_SPORT = "http://sports.163.com/special/00051K7F/rss_sportslq.xml";    public static final String URL_NEWS_PLAY = "http://ent.163.com/special/00031K7Q/rss_toutiao.xml";    public static final String URL_NEWS_FINANCE = "http://money.163.com/special/00252EQ2/yaowenrss.xml";    public static final String URL_NEWS_SCIENCE = "http://tech.163.com/special/000944OI/headlines.xml";

    //国内    public static final String URL_NEWS_DOMESTIC = "http://news.163.com/special/00011K6L/rss_gn.xml";    //军事    public static final String URL_NEWS_MILITARY = "http://news.163.com/special/00011K6L/rss_war.xml";    //国际    public static final String URL_NEWS_INTERNATIONAL = "http://news.163.com/special/00011K6L/rss_gj.xml";    //社会    public static final String URL_NEWS_COMMUNITY = "http://news.163.com/special/00011K6L/rss_sh.xml";    //深度    public static final String URL_NEWS_DEPTH = "http://news.163.com/special/00011K6L/rss_hotnews.xml";    //彩票    public static final String URL_NEWS_TICKET = "http://sports.163.com/special/00051K7F/rss_sportscp.xml";    //电影    public static final String URL_NEWS_FILM = "http://ent.163.com/special/00031K7Q/rss_entmovie.xml";    //音乐    public static final String URL_NEWS_MUSIC = "http://ent.163.com/special/00031K7Q/rss_entmusic.xml";    //IT    public static final String URL_NEWS_IT = "http://tech.163.com/special/000944OI/kejiyejie.xml";    //汽车    public static final String URL_NEWS_CAR = "http://auto.163.com/special/00081K7D/rsstoutiao.xml";    //数码    public static final String URL_NEWS_DIGITAL = "http://tech.163.com/digi/special/00161K7K/rss_digixj.xml";

    //网易话题    public static final String URL_TOPIC = "http://news.163.com/special/00011K6L/rss_newsspecial.xml";    //网易图片    public static final String URL_PICTURE = "http://news.163.com/special/00011K6L/rss_photo.xml";    //网易跟帖    public static final String URL_FOLLOW = "";    //网易投票    public static final String URL_VOTE = "";

}

后面的网易跟帖和投票,我实在找不到合适的URL地址了,所以就都用的网易图片的URL,因为里面我没有涉及到跟帖和投票的操作。如上最后一张图片所示。

四、关于Tab(新闻)页面的讲解

由于RSS格式的限制,所以里面的各个页面大体框架类似,下面只大概讲解一下“新闻”页面。它是TabHost里面的其中一个页面,在这个页面中涉及到另外几个页面,如“头条”、“体育”、“娱乐”、“财经”等一些,所以这个页面让它继承自ActivityGroup类,在这个ActivityGroup类里面可以管理很多的Activity。那要怎样把一个Activity添加到ActivityGroup中来呢?

intent = new Intent(TabNewsActivity.this, TabNewsTopActivity.class);        page = getLocalActivityManager().startActivity("activity1", intent).getDecorView();        LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);        layout_news_main.addView(page, params);

这样,就可以把一个Activity转化成View,然后添加到当前的ActivityGroup中。

另外,这里涉及到一个Progress的处理,当请求数据的时候,让它显示一个旋转的进度提示。这里面用到了ViewSwitcher这个类,在它里面添加两个视图View,然后在不同的时候控件它具体显示哪一个View而达到目的,我这里在ViewSwitcher里面分别添加了一个ListView和一个ProgressBar,当请求网络的时候,让它显示ProgressBar界面,请求完成,让它显示ListView。

viewSwitcher = (ViewSwitcher) findViewById(R.id.viewswitcher_news_top);        listView = new MyListView(this);        ...        viewSwitcher.addView(listView);        viewSwitcher.addView(getLayoutInflater().inflate(R.layout.layout_progress_page, null));        viewSwitcher.showNext();

完整代码TabNewsTopActivity.java

package com.and.netease;

import java.io.InputStream;import java.io.InputStreamReader;import java.io.Reader;import java.net.URL;import java.net.URLConnection;import java.nio.charset.Charset;import java.util.List;

import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;import org.xml.sax.XMLReader;

import com.and.netease.MyListView.OnRefreshListener;import com.and.netease.rss.RSSHandler;import com.and.netease.rss.RSSItem;

import android.app.Activity;import android.content.Intent;import android.graphics.Color;import android.os.AsyncTask;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import android.widget.ViewSwitcher;

public class TabNewsTopActivity extends Activity {

    MyListView listView;

    List<RSSItem> list;    RSSHandler rssHandler;

    MyAdapter adapter;

    ViewSwitcher viewSwitcher;

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.layout_news_top);        setTheme(android.R.style.Theme_Translucent_NoTitleBar);

        initViews();

        rssHandler = new RSSHandler();        requestRSSFeed();

    }

    private void initViews() {        viewSwitcher = (ViewSwitcher) findViewById(R.id.viewswitcher_news_top);        listView = new MyListView(this);        listView.setCacheColorHint(Color.argb(0, 0, 0, 0));        ImageView testView = new ImageView(this);        testView.setImageResource(R.drawable.temp);        listView.addHeaderView(testView);        listView.setonRefreshListener(refreshListener);

        viewSwitcher.addView(listView);        viewSwitcher.addView(getLayoutInflater().inflate(R.layout.layout_progress_page, null));        viewSwitcher.showNext();        listView.setOnItemClickListener(listener);

    }

    private OnRefreshListener refreshListener = new OnRefreshListener() {

        @Override        public void onRefresh() {            // TODO Auto-generated method stub            new AsyncTask<Void, Void, Void>() {                protected Void doInBackground(Void... params) {                    try {                        Thread.sleep(1000);                    } catch (Exception e) {                        e.printStackTrace();                    }

                    return null;                }

                @Override                protected void onPostExecute(Void result) {                    adapter.notifyDataSetChanged();                    listView.onRefreshComplete();                }

            }.execute(null);        }    };

    private void requestRSSFeed() {        Thread t = new Thread() {            @Override            public void run() {                super.run();                try {                    URL url = new URL(CONST.URL_NEWS_TOP);                    URLConnection con = url.openConnection();                    con.connect();

                    InputStream input = con.getInputStream();

                    SAXParserFactory fac = SAXParserFactory.newInstance();                    SAXParser parser = fac.newSAXParser();                    XMLReader reader = parser.getXMLReader();                    reader.setContentHandler(rssHandler);                    Reader r = new InputStreamReader(input, Charset.forName("GBK"));                    reader.parse(new InputSource(r));                    list = rssHandler.getData();//                    for (RSSItem rss : list) {//                        System.out.println(rss);//                    }                    if (list.size() == 0) {                        handler.sendEmptyMessage(-1);                    } else {                        handler.sendEmptyMessage(1);                    }                } catch (Exception e) {                    e.printStackTrace();                }            }        };        t.start();    }

    Handler handler = new Handler() {        public void handleMessage(android.os.Message msg) {            if (msg.what == 1) {                adapter = new MyAdapter();                listView.setOnItemClickListener(listener);                listView.setAdapter(adapter);                viewSwitcher.showPrevious();

                listView.onRefreshComplete();            }        };    };

    private OnItemClickListener listener = new OnItemClickListener() {

        @Override        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {            if(position==1){                return;            }            Intent intent = new Intent(TabNewsTopActivity.this, NewsContentActivity.class);            intent.putExtra("content_url", list.get(position-2).getLink());            TabNewsTopActivity.this.startActivityForResult(intent, position);        }    };

    private class MyAdapter extends BaseAdapter {

        @Override        public int getCount() {            return list.size();        }

        @Override        public Object getItem(int position) {            return null;        }

        @Override        public long getItemId(int position) {            return 0;        }

        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder holder;            if (convertView == null) {                holder = new ViewHolder();                convertView = getLayoutInflater().inflate(R.layout.layout_news_top_item, null);                holder.tv_date = (TextView) convertView.findViewById(R.id.tv_date_news_top_item);                holder.tv_title = (TextView) convertView.findViewById(R.id.tv_title_news_top_item);                holder.tv_Description = (TextView) convertView.findViewById(R.id.tv_description_news_top_item);                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }

            holder.tv_date.setText(list.get(position).getPubDate());            holder.tv_title.setText(list.get(position).getTitle());            holder.tv_Description.setText(list.get(position).getDescription());

            return convertView;        }

    }

    public static class ViewHolder {        TextView tv_date;        TextView tv_title;        TextView tv_Description;    }

    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        System.out.println("返回");        super.onActivityResult(requestCode, resultCode, data);

    }}

几点说明:

1、细心的你有可能会发现,里面我用的是MyListView,它是自定义的一个ListView,为了实现下拉刷新而写的。如果不需要下拉刷新,直接换成ListView即可。但是,要注意,这里自定义MyListView之后,设置它的OnItemClickListener点击事件,Item里面的position从1开始,而非从0开始,下拉列表是从网上复制一的段,还没怎么研究,我猜的话,估计那个下拉出现的东西,有可能position就是0。这个之后再研究。关于下拉刷新,我会在另外一个博客中说明。现在我也还没弄明白。

2、这个类里面的ListView添加的Header,是一张静态图片,因为RSS代码里面没有提供图片链接,为了达到效果,暂且用一张图片代替。

五、具体新闻内容

具体的新闻内容,暂且用一个WebView来加载它,碍于RSS的限制,具体某一条新闻的Link链接地址,是一个完整的网页。当然请求的时候,照样显示旋转的进度条,跟之前的一个ViewSwitcher一样处理。新闻内容NewsContentActivity.java

package com.and.netease;

import android.app.Activity;import android.graphics.Bitmap;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.webkit.WebSettings;import android.webkit.WebView;import android.webkit.WebViewClient;import android.widget.ImageButton;import android.widget.ViewSwitcher;

public class NewsContentActivity extends Activity {

    ImageButton btn_back;    WebView webView;    String content_url;

    ViewSwitcher viewSwitcher;

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.layout_newscontent);        initViews();    }

    private void initViews() {        btn_back = (ImageButton) findViewById(R.id.btn_newscontent_back);        btn_back.setOnClickListener(listener);

        viewSwitcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);

        content_url = getIntent().getStringExtra("content_url");        webView = new WebView(this);

        // 向ViewSwitcher中添加两个View,用来切换        viewSwitcher.addView(webView);        viewSwitcher.addView(getLayoutInflater().inflate(                R.layout.layout_progress_page, null));        WebSettings settings = webView.getSettings();        settings.setJavaScriptEnabled(true);

        webView.setWebViewClient(client);        webView.loadUrl(content_url);    }

    private WebViewClient client = new WebViewClient() {

        @Override        public void onPageFinished(WebView view, String url) {            super.onPageFinished(view, url);            viewSwitcher.showPrevious();        }

        @Override        public void onPageStarted(WebView view, String url, Bitmap favicon) {            super.onPageStarted(view, url, favicon);            viewSwitcher.showNext();        }

        @Override        public boolean shouldOverrideUrlLoading(WebView view, String url) {            return super.shouldOverrideUrlLoading(view, url);        }

    };

    private OnClickListener listener = new OnClickListener() {

        @Override        public void onClick(View v) {            NewsContentActivity.this.setResult(RESULT_OK);            NewsContentActivity.this.finish();        }    };

    public void onBackPressed() {        if (webView.canGoBack()) {            webView.goBack();        } else {            NewsContentActivity.this.setResult(RESULT_OK);            NewsContentActivity.this.finish();        }    };}

至此,这个版本算是基本上完成了。除了第一个Tab(新闻)页面稍微复杂点之外,其它页面基本一样,因为目前我所发现的RSS所能提供的仅是这些。

模仿网易新闻客户端的开发就告一段落了,如果找到合适的URL再继续吧,目前还有很多功能没有实现,比如天气、分享、跟帖等等很多东西。

六、总结

小小地总结一下,模仿网易新闻客户端,虽然没碰到很大的难点,但是还是有不少 的收获的,比如在自定义TabHost控件的时候,以前也遇到过点击不能切换背景的问题,当时在代码里面控制的。通过做这个东西,现在解决了,还有一个就是ProgressBar的问题,自定义旋转图片的时候,以前总是不知道怎样让它匀速循环转动,现在好像也解决了,反正收获不少吧。此“项目”权当闲来练手,没什么实际用处,希望各位大牛多多指点。

Android新闻客户端(仿网易)--下相关推荐

  1. Android新闻客户端实训-Day1类Day2接口基操

    结束了一些事情,本以为可以好好玩一段时间,结果紧接着又来了Android实训,因为这个实训已经开了一段时间了,我中途加入已经不赶趟了,但出于兴趣,准备今天开始跟着老师的笔记的源码从头开始自己摸索着学一 ...

  2. android新闻客户端报告,简易的Android新闻客户端

    学完Android基础之后不知道该怎么办?现在开始实战吧! 现在来看看一款简易的Android新闻客户端是怎么做的,当然,获取网络数据的这一部分我是使用别人做好的本地客户端,然后通过组建本地数据库来使 ...

  3. android 新闻频道,GitHub - xiyy/TopNews: 一款Android新闻客户端,并提供电视台直播功能...

    TopNews 一款Android新闻客户端,独立开发完成,主要功能包括: 1 新闻频道分类,头条.社会.国内.娱乐.体育.军事.科技.财经.时尚 使用ViewPager+FragmentPagerA ...

  4. android新闻客户端的实现

    制作一个基于聚合新闻数据简单的新闻APP 制作简易新闻App 导航篇 [1.使用Fragment+ViewPager +TabLayout自制简易新闻 app主要框架(一)](https://blog ...

  5. android新闻客户端(有源码)

    有些功能还没实现 源码今天起不再免费提供,评论区有联系方式 目录 一. 题目及要求 2 二. 功能设计 3 三. 详细设计 3 1. 启动页面 3 1)页面显示完跳转 3 2) 启动页面图片全屏化 3 ...

  6. android新闻客户端发展趋势,基于Android平台的新闻客户端设计与实现

    杨苏雯 摘 要 在Android开发平台上,并在JavaWeb开发的PC端新闻网站的基础上结合现在的需求开发了移动版的新闻客户端App,这个系统设计主要分为用户登录验证模块.新闻列表的显示功能模块以及 ...

  7. android新闻客户端实验报告,基于Android平台的新闻客户端设计与实现

    摘 要 在Android开发平台上,并在JavaWeb开发的PC端新闻网站的基础上结合现在的需求开发了移动版的新闻客户端App,这个系统设计主要分为用户登录验证模块.新闻列表的显示功能模块以及新闻内容 ...

  8. android新闻客户端实验报告,Android 新闻客户端学习笔记

    学习了新闻客户端开发后,有很多是通用的,就把客户端用到的一些做个笔记,已备以后使用,主要用到的知识点有: 1.  Android网络编程 2.  Android中BaseAdapter的使用 3.   ...

  9. Android 新闻客户端案例

    实现新闻客户端案例首先需要注意XML文件的在线解析,适配器问题和ListView控件的使用. 根据自己的需要和要求,准备好素材. 1.NewsInfo.xml文件如下: <?xml versio ...

最新文章

  1. 使用yum快速搭建LAMP和配置phpMyAdmin
  2. 乐视云监控数据存放到influxdb中
  3. 从源码角度深入分析log4j配置文件使用
  4. cpu不支持虚拟装linux,linux 查看cpu是不是支持虚拟化
  5. linux c多进程多线程,linux下的C\C++多进程多线程编程实例详解
  6. Symbian编程VC开发环境设置
  7. android ascii 比较大小写,为什么可以通过ASCII中的字母排序规则来进行字母的大小写转换?...
  8. wdos相关问题解答
  9. JsonHelper(Json帮助类)
  10. Linux常用基本命令总结
  11. 《UNIX系统编程》
  12. 计算机开机后黑屏 只有鼠标,电脑开机后一直黑屏只有一个鼠标,重启也是.怎么处理...
  13. Pytorch TextCNN实现中文文本分类(附完整训练代码)
  14. java-常量和变量
  15. (六)高德地图之驾车路线规划
  16. crh寄存器_STM32的GPIO的寄存器介绍和设置
  17. 没人谈论的 3 种从 ChatGPT 赚钱的方法,我测试过的建立被动收入流的行之有效的方法
  18. 申请TC交易证书以下4点请注意
  19. 【Sanic】Sanic应用 2
  20. JavaScript实现春节倒计时

热门文章

  1. 微信域名拦截检测API源码 检测域名是否能在微信正常打开
  2. 如何使用Photoshop在PSD文件上切图
  3. 如何设置计算机自动连接宽带,Win10怎么设置开机自动连接宽带?设置宽带自动联网方法...
  4. 使用html和css进行红米案例、学成在线开发
  5. (linux自学笔记)linux系统初体验与编程基础
  6. 如何判断一个数是不是素数?
  7. Virtuoso仿真错误 ---- input.scs
  8. 【过关斩将】运维老鸟带教你如何精通运维
  9. day 5 文字溢出处理 背景图片处理 开发经验
  10. Objective-C向面向对象编程中添加了一个新概念:类别(categor)。