仿CSDN安卓客户端(二)-----从网络上获取并解析html文件

首先先上一下安卓客户端的效果,之前是静态的图片,不够形象,上一个动态图提升一下逼格。嘿嘿
这里写图片描述

因为我们使用jsoup解析html文件,所以记得在lib里面添加一下jsoup-1.7.2.jar
下载地址:http://download.csdn.net/detail/start_baby/5132499

今天我们的任务就是从CSDN网站上获取每一个条目相应的目录列表,先贴一下代码,然后我们通过代码来理清思路

我们首先要定义一个新闻目录类,用来存储获取到的每一个新闻
NewsItem.java

public class NewsItem {

        private int id;  

        /** 
         * 标题 
         */  
        private String title;  
        /** 
         * 链接 
         */  
        private String link;  
        /** 
         * 发布日期 
         */  
        private String date;  
        /** 
         * 图片的链接 
         */  
        private String imgLink;  
        /** 
         * 内容 
         */  
        private String content;  

        /** 
         * 类型   
         *  
         */  
        private int newsType;  

        public int getNewsType()  
        {  
            return newsType;  
        }  

        public void setNewsType(int newsType)  
        {  
            this.newsType = newsType;  
        }  

        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 int getId()  
        {  
            return id;  
        }  

        public void setId(int id)  
        {  
            this.id = id;  
        }  

        public String getDate()  
        {  
            return date;  
        }  

        public void setDate(String date)  
        {  
            this.date = date;  
        }  

        public String getImgLink()  
        {  
            return imgLink;  
        }  

        public void setImgLink(String imgLink)  
        {  
            this.imgLink = imgLink;  
        }  

        public String getContent()  
        {  
            return content;  
        }  

        public void setContent(String content)  
        {  
            this.content = content;  
        }  

        @Override  
        public String toString()  
        {  
            return "NewsItem [id=" + id + ", title=" + title + ", link=" + link + ", date=" + date + ", imgLink=" + imgLink  
                    + ", content=" + content + ", newsType=" + newsType + "]";  
        }  

    }  

定义好了数据类型,我们现在就可以放心的获取网上的数据,这样就不要担心这些数据无家可归了。下面你可以通过注释理解代码,我尽量为你解释每一行代码。

NewsItemBiz.java
package com.example.httputil;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;


import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.example.myapplication.myApplication;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.provider.DocumentsContract.Document;
import android.util.Log;

public class NewsItemBiz {
    //定义一个NewsItem类型的数组
    List<NewsItem> newsItems = new ArrayList<NewsItem>();
    private int newsType;

    public NewsItemBiz() {
        // TODO Auto-generated constructor stub

/*
     * 这里我通过handler机制来控制进程的先后顺序,这是一个很必要的工作,也是我之前碰到的问题得出来的经验,问题大概是这样的:
     * 因为网络请求数据必须创建一个线程,否则会导致主UI卡死。所以我们创建了一个线程,并且将
     * 返回来的数据变成字符串的形式进行处理,然后我们在主线程中需要解析这个字符串
     * ,这时候问题就出现了,当子线程请求网络数据还没有结束的时候,主线程就已经开始解析了
     * ,这时候这个字符串肯定为空,就会产生错误,所以一定要使用这个异步消息机制
     */
    public Handler handler=new Handler()
    {
        public void handleMessage(android.os.Message msg) {

            NewsItem newsItem = null;       
            org.jsoup.nodes.Document doc = Jsoup.parse(msg.obj.toString());
            Elements units = doc.getElementsByClass("unit");
            for (int i = 0; i < units.size(); i++)
            {
                newsItem = new NewsItem();
                newsItem.setNewsType(newsType);

                Element unit_ele = units.get(i);

                Element h1_ele = unit_ele.getElementsByTag("h1").get(0);
                Element h1_a_ele = h1_ele.child(0);
                String title = h1_a_ele.text();
                String href = h1_a_ele.attr("href");
                Log.i("hello",title);
                newsItem.setLink(href);
                newsItem.setTitle(title);

                Element h4_ele = unit_ele.getElementsByTag("h4").get(0);
                Element ago_ele = h4_ele.getElementsByClass("ago").get(0);
                String date = ago_ele.text();

                newsItem.setDate(date);

                Element dl_ele = unit_ele.getElementsByTag("dl").get(0);// dl
                Element dt_ele = dl_ele.child(0);// dt
                try
                {// 可能没有图片
                    Element img_ele = dt_ele.child(0);
                    String imgLink = img_ele.child(0).attr("src");
                    newsItem.setImgLink(imgLink);
                } catch (IndexOutOfBoundsException e)
                {

                }
                Element content_ele = dl_ele.child(1);// dd
                String content = content_ele.text();
                newsItem.setContent(content);
                newsItems.add(newsItem);
            }

        };
    };
      //此函数才是真正被调用的函数,第一个参数是当前页面的类型,第二个参数是页数
    public List<NewsItem> getNewsItems( int newsType , int currentPage) throws CommonException, IOException
    {
       //通过当前页面类型和页数构造出真正的网址
        String urlStr = URLUtil.generateUrl(newsType, currentPage); 
        //将之前的数组清空
        newsItems.clear();
        doGet(urlStr);
            /*
     * 下面的while循环很有必要,因为当子线程还有没有返回字符串时,那么handler就没有办法解析html的时候,
     * 有可能你的主线程已经走到了下面的一句return
     * newsItems,那么毫无意外,你就只能得到一个空的newsItems,这就是心急吃不了热豆腐啊
     * ,所以我们就要判断newsitems是不是为空,如果是空的话,我们就用一个线程等待
     */
        while((newsItems.size()==0))
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return newsItems;
    }

    //此函数用来获取一个网页的html数据,并将其变成字符串格式
    public void doGet(final String urlStr) throws CommonException{
        final StringBuffer sb = new StringBuffer();
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    URL url = new URL(urlStr);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(5000);
                    conn.setDoInput(true);
                    conn.setDoOutput(true);
                    if(conn.getResponseCode() == 200){
                        InputStream is = conn.getInputStream();
                        int len = 0;
                        byte[] buf = new byte[1024];
                        while((len = is.read(buf)) != -1){
                             sb.append(new String(buf, 0, len, "UTF-8"));
                        }
                        Message message =new Message();
                        message.obj=sb;
                        handler.sendMessage(message);
                        is.close();
                    }else{
                        throw new CommonException("访问网络失败00");
                    }

                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    try {
                        throw new CommonException("访问网络失败11");
                    } catch (CommonException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        }).start();
    }     
}

下面开始测试一下上面的NewsItemBiz类,特别注意使用上面类,要使用异步任务,因为在主线程中获取List耗了很长的时间,如果不使用,会导致UI线程卡死,不信的话,你可以试一试哦,我把我之前没有用异步任务的代码也列在了下面,方便你比较这两者的差别吧!

public class secondFragment extends android.support.v4.app.Fragment{
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        View v=inflater.inflate(R.layout.secondfragment, container,false);
        Button button=(Button)v.findViewById(R.id.send);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {               
                new LoadDatasTask().execute();
//下面就是我之前在主线程中使用的代码,你只需将下面带//的去除,将上面一行加上//
//              NewsItemBiz newitembiz=new NewsItemBiz();
//              List<NewsItem> item=new ArrayList<NewsItem>();
//              try {
//                  try {
//                      item=newitembiz.getNewsItems(3, 2); 
//                      for (NewsItem newsItem : item) {
//                          Log.i("msg", newsItem.getContent()); 
//                  }
//                  } catch (CommonException e) {
//                      // TODO Auto-generated catch block
//                      e.printStackTrace();
//                  }
//              }  catch (IOException e) {
//                  // TODO Auto-generated catch block
//                  e.printStackTrace();
//              }   
            }
        });
        return v;
}

    class LoadDatasTask extends AsyncTask<Void, Void, Void> {
        public NewsItemBiz newitembiz=new NewsItemBiz();
        public List<NewsItem> item=new ArrayList<NewsItem>();
        protected void onPostExecute(Void result) {         
            for (NewsItem newsItem : item) {
                Log.i("msg", newsItem.getContent()); 
        }
        }

        @Override
        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub
            try {
                try {
                    item=newitembiz.getNewsItems(3, 2);         
                } catch (CommonException e) {
                    e.printStackTrace();
                }
            }  catch (IOException e) {          
                e.printStackTrace();
            }       
            return null;
        }
    }
}

效果图还是要上一下的,不然说我骗人就不好了
这里写图片描述
点击上面的send,然后观察logcat中的结果
这里写图片描述

这一节关于从网络上获取并解析html文件我们就先讲到这里,看别人做一万遍,也不如自己做一遍,自己试着做一遍吧!相信自己,你可以的,加油!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值