VNExpress RSS Reader Simple Demo

Project: https://github.com/minhhuy150894/VNExpress-RSS-Reader-simple-for-tutorial

Xem trước video demo nhé:

OK bây giờ xem lại file XML:

xml

 

Nhìn sơ qua có vẻ đơn giản nhưng vấn đề ở chỗ là chúng ta sẽ lấy link ảnh trong phần CDATA (this is a trick) :))

OK bây giờ bắt đầu nhé :) Chú ý những phần comment trong code nhé, do demo khá dài nên mình dùng các comment dể giải thích, Nếu có thắc mắc thì bạn có thể hỏi ở phần bình luận bên dưới topic này

Tổng quan project của chúng ta sẽ có những class như sau:

class.jpg

activity_main.xml chỉ có một ListView :

main

Custom_layout.xml sẽ có bên trong một ImageView và một TextView:

custom

Nội dung của MainActivity.java:

<pre>import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity {
    ListView lv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) this.findViewById(R.id.lv);
        new AsyncProcess(MainActivity.this, lv)
                .execute("http://vnexpress.net/rss/the-thao.rss"); // đường dẫn file xml tôi thực hiện trong demo này.
    }
}</pre>

 

Nội dung của CustomLayout.java:

<pre>import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

import java.util.List;

/**</pre>
<ul>
<ul>
    <li>Created by admin on 12/16/2015.</li>
</ul>
</ul>
*/ public class CustomLayout extends ArrayAdapter { public CustomLayout(Context context, int textViewResourceId) { super(context, textViewResourceId); } public CustomLayout(Context context, int resource, List items) { super(context, resource, items); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi; vi = LayoutInflater.from(getContext()); v = vi.inflate(R.layout.custom_layout, null); } VNExpress p = getItem(position); if (p != null) { ImageView img = (ImageView) v.findViewById(R.id.imageView); Picasso.with(getContext()).load(p.getImageLink()).into(img); // tôi dùng thư viện Picasso để load ảnh cho vào ImageView. TextView tv = (TextView) v.findViewById(R.id.textView); tv.setText(p.getTitle()); } return v; } }

 

Nội dung của VNExpress.java:

 

<pre>public class VNExpress {
    String title;
    String imageLink;

    public VNExpress(String title, String imageLink) {
        this.title = title;
        this.imageLink = imageLink;
    }

    public String getTitle() {
        return title;
    }

    public String getImageLink() {
        return imageLink;
    }
}</pre>

 

Nội dung của XMLParser.java:

 

<pre>import android.util.Log;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

public class XMLParser {
    public Document getDocument(String xml)
    {
        Document document = null;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try{
            DocumentBuilder db = factory.newDocumentBuilder();
            InputSource is = new InputSource();
            is.setCharacterStream(new StringReader(xml));
            is.setEncoding("UTF-8");
            document = db.parse(is);
        }catch(ParserConfigurationException e)
        {
            Log.e("Error: ", e.getMessage(), e);
            return null;
        }
        catch (SAXException e) {
            Log.e("Error: ", e.getMessage(), e);
            return null;
        }
        catch(IOException e){
            Log.e("Error: ", e.getMessage(), e);
            return null;
        }
        return document;
    }
    public String getValue(Element item, String name)
    {
        NodeList nodes = item.getElementsByTagName(name);
        return this.getTextFromNodeValue(nodes.item(0));
    }
    public final String getTextFromNodeValue(Node elem) {
        Node child;
        if( elem != null){
            if (elem.hasChildNodes()){
                for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){
                    if( child.getNodeType() == Node.TEXT_NODE ){
                        //return child.getNodeValue();
                        return child.getTextContent();
                    }
                }
            }
        }
        return "";
    }
}</pre>

Class cuối cùng, quan trọng là AsyncProcess.java như sau:

 

<pre>import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.widget.ListView;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

public class AsyncProcess extends AsyncTask<String, Integer, String> {
    Context context;
    ListView lv;
    ArrayList arrayList; // ArrayList chứa các đối tượng chứa thông tin, mỗi đối tượng gồm tiêu đề + link ảnh.
    CustomLayout adapter; // khai báo adapter cho listView
    int nodeListCounter = 0; // tổng số bài viết mới đọc từ rss.
    ProgressDialog progressDialog; // khởi tạo Progressdialog

    public AsyncProcess(Context context, ListView lv) {
        this.context = context;
        this.lv = lv;
    }

    @Override
    protected void onPreExecute() {
        progressDialog = new ProgressDialog(context); // bạn nên viết ra thành hàm riêng để sử dụng lại nhiều lần chứ không nên viết như tôi :)
        progressDialog.setMessage("Loading...");
        progressDialog.setIndeterminate(false);
        progressDialog.setMax(nodeListCounter);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.show();
        arrayList = new ArrayList(); // khởi tạo Arraylist
        adapter = new CustomLayout(context, R.layout.custom_layout, arrayList); // khởi tạo adapter.
    }
    @Override
    protected String doInBackground(String... params) {
        if (params[0] != null){
            String xml =  readFromURL(params[0]); // xml là nội dung ta đọc được từ hàm readFromURL.
            XMLParser parser = new XMLParser();
            Document doc = parser.getDocument(xml);
            NodeList nodeList = doc.getElementsByTagName("item");
            NodeList nodeListDescription = doc.getElementsByTagName("description"); // This is a trick :)) Nếu dùng bình thường bạn sẽ không lấy ra được phần CDATA.

            String title="";
            String description="";
            nodeListCounter = nodeList.getLength(); // lấy tổng số các article mới trong xml.

            for(int i=0; i<nodeListCounter; i++) {
                Element e = (Element) nodeList.item(i);
                title = parser.getValue(e, "title");

                description = nodeListDescription.item(i + 1).getTextContent() + "
";
                VNExpress vne = new VNExpress(title, getImageLinkFromCDATA(description)); // chú ý hàm getImageLinkFromCDATA, this is a trick :))

                arrayList.add(vne);
                publishProgress((i*100) / nodeListCounter); // truyền  qua cho hàm onProgressUpdate.
                SystemClock.sleep(100);
            }
            return null;
        }
        else{
            return null;
        }
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        progressDialog.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(String xml) {
        progressDialog.dismiss(); // đóng progressDialog khi hoàn tất
        lv.setAdapter(adapter); // set Adapter cho listView
    }

    private String getImageLinkFromCDATA(String link){ // Chỉ là thủ thuật lấy ra đoạn link mong muốn, còn một cách khác hay hơn.
        int begin = link.indexOf("http://img");
        int end = link.indexOf(".jpg");
        return link.substring(begin, end+4);
    }

    private static String readFromURL(String theUrl){ // đọc file rss từ đường dẫn cho trước.
        StringBuilder content = new StringBuilder();
        try{
            URL url = new URL(theUrl);
            URLConnection urlConnection = url.openConnection();
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(urlConnection.getInputStream())
            );

            String line;
            while ((line = bufferedReader.readLine()) != null){
                content.append(line + "\n");
            }
            bufferedReader.close();
        }
        catch(Exception e){
            e.printStackTrace();
        }
        return content.toString();
    }

}</pre>

Không quên thêm permission cho phép kết nối đến Internet

Nếu có thắc mắc, bạn có thể comment bên dưới :)

 

 

 

 

 

 

 

 

 

Advertisements

9 thoughts on “VNExpress RSS Reader Simple Demo

    • À do mình post code lên wordpress đây nó bị một số lỗi do thừa dòng, bạn đừng để ý cặp “pre” đó nhe :)

      Like

  1. Bạn ơi, mình làm theo thì bị lỗi org.xml.sax.SAXParseException: Unexpected end of document, báo lỗi ở dòng document = db.parse(is). Mình vẫn chưa fix được, mong bạn giúp đỡ. Cảm ơn bạn nhiều.

    Like

      • :D Uhm. Dạo này bận nên mình không ra những bài hướng dẫn mới được. cám ơn bạn đã quan tâm những bài viết của mình! :)

        Like

  2. Bạn có thể giải thích thêm về hàm getTextFromNodeValue được không? Mình vẫn chưa hiểu hàm đó, hiện tại mình đang bị lỗi là khi hiển thị lên listview, một số view hiển thị nội dung giống nhau.

    Like

    • Học lập trình thật ra còn phải linh hoạt xíu bạn ơi, có thể là hiện tại VNExpress nó đã có thay đổi nên đọc không được, hoặc là sai ở đâu đó. bạn có thể lên daynhauhoc.com để hỏi những thắc mắc này cho dễ :)

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s