ifranrFeed original
ifanrFeed 中世纪版!随着移动App的流行,曾经在网络阅读中很流行的RSS技术已经很少有人使用了!可是我还是喜欢这种轻量级的简单的阅读体验,ifanr是我很喜欢的科技媒体,所以这个白垩纪的App就以ifanr左右信息源(Feed)!
项目结构
信息源Feed
首先找到ifanr的RSS地址 http://www.ifanr.com/Feed
可以看出RSS也基于xml的一种数据交换格式,所有解析xml的方式 Dom Pull Saxx都可以使用来解析数据。
Pull解析RSS数据
使用Pull方式解析,KXML作为xml的具体实现!
- try {
- // 得到解析器工厂,通过静态方法获取一个解析工程对象的引用
- XmlPullParserFactory xpf = XmlPullParserFactory.newInstance();
- // 通过解析器工厂的得到一个XmlPullParser解析器对象
- XmlPullParser parser = xpf.newPullParser();
- // 獲得時間類型
- int eventType = parser.getEventType();
-
- // 解析器设置输入流和编码格式
- // 把这一句漏了还搞个毛呀
- parser.setInput(is,"UTF-8");
-
- // while 遍历 ,只要事件类型不等于文档结束标志
- while (eventType != XmlPullParser.END_DOCUMENT) {
-
- switch (eventType) {
- // 如果事件类型为START_DOCUMENT,即读取文档开头
- case XmlPullParser.START_DOCUMENT:
-
- list = new ArrayList<News>();
-
- break;
- // 元素标记开头标志
- // 运用pull方式解析xml需要知道节点标签的名称
- case XmlPullParser.START_TAG:
-
- if ("item".equals(parser.getName())) {
- // 衹有當標簽名稱爲user時,新建一個對象
- news = new News();
- Log.i("MainActivity","------> " + "new News()");
-
- } else if ("index".equals(parser.getName())) {
- int index = Integer.parseInt(parser.nextText());
- news.setIndex(index);
- Log.i("MainActivity","------------------> "
- + "設置Index");
- } else if ("title".equals(parser.getName())) {
-
- String title = parser.nextText();// 获取该节点内容
- if (!title.equals("爱范儿")) {
- news.setTitle(title);
- }
- Log.i("MainActivity","------------------> "
- + "設置Title");
- } else if ("image".equals(parser.getName())) {
- String image = parser.nextText();// 获取该节点内容
- news.setImage(image);
- } else if ("description".equals(parser.getName())) {
-
- String description = parser.nextText();// 获取该节点内容
- if (!description.equals("连接热爱")) {
- news.setDescription(description);
- }
- } else if ("content:encoded".equals(parser.getName())) {
- // System.out.println("設置password");
- String content = parser.nextText();// 获取该节点内容
- news.setContent(content);
- }
-
- break;
-
- case XmlPullParser.END_TAG:
- if ("item".equals(parser.getName())) {
- Log.i("MainActivity","------> " + "得到RSS item");
- list.add(news);
- news = null;
-
- }
-
- break;
-
- }
- // 每次switch选择后跳转到下一标签,事件类型
- eventType = parser.next();
- }
-
- } catch (XmlPullParserException e) {
- // TODO Auto-generated catch block
- System.out.println("nikan 出错了吧");
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return list;
HttpUtils辅助类获取xml信息
- package com.example.ifanrFeed.service;
-
-
-
- import java.io.InputStream;
- import java.net.HttpURLConnection;
- import java.net.URL;
- /** * http工具類 * @author QT * */
- public class HttpUtils {
- public HttpUtils() {
- // TODO Auto-generated constructor stub
- }
- /** * 通過URL獲取輸入流 * @param path * @return */
- public static InputStream getXml(String path){
- InputStream is=null;
- try {
- URL url=new URL(path);
- if(url!=null){
- //獲得HttpURLConnnection
- HttpURLConnection connection =(HttpURLConnection)url.openConnection();
- //設置屬性
- connection.setConnectTimeout(3000);
- connection.setDoInput(true);
- connection.setRequestMethod("GET");
- int code=connection.getResponseCode();
- //GET請求成功
- if(code==200){
- is=connection.getInputStream();
- }
- }
-
- } catch (Exception e) {
- // TODO: handle exception
- }
- return is;
-
- }
- }
@H_859_404@使用AsyncTask执行后台任务
- AsyncTask<String,Void,List<News>> parseTask = new AsyncTask<String,List<News>>() {
- //后台获取List<News>()
- @Override
- protected List<News> doInBackground(String... arg0) {
- String RSSInfo = arg0[0];
- News news = null;
- InputStream is = HttpUtils.getXml(URL);
- Log.i("MainActivity","------> " + "得到RSS Info");
- try {
- // 得到解析器工厂,通过静态方法获取一个解析工程对象的引用
- XmlPullParserFactory xpf = XmlPullParserFactory.newInstance();
- // 通过解析器工厂的得到一个XmlPullParser解析器对象
- XmlPullParser parser = xpf.newPullParser();
- // 獲得時間類型
- int eventType = parser.getEventType();
-
- // 解析器设置输入流和编码格式
- // 把这一句漏了还搞个毛呀
- parser.setInput(is,"UTF-8");
-
- // while 遍历 ,只要事件类型不等于文档结束标志
- while (eventType != XmlPullParser.END_DOCUMENT) {
-
- switch (eventType) {
- // 如果事件类型为START_DOCUMENT,即读取文档开头
- case XmlPullParser.START_DOCUMENT:
-
- list = new ArrayList<News>();
-
- break;
- // 元素标记开头标志
- // 运用pull方式解析xml需要知道节点标签的名称
- case XmlPullParser.START_TAG:
-
- if ("item".equals(parser.getName())) {
- // 衹有當標簽名稱爲user時,新建一個對象
- news = new News();
- Log.i("MainActivity","------> " + "new News()");
-
- } else if ("index".equals(parser.getName())) {
- int index = Integer.parseInt(parser.nextText());
- news.setIndex(index);
- Log.i("MainActivity","------------------> "
- + "設置Index");
- } else if ("title".equals(parser.getName())) {
-
- String title = parser.nextText();// 获取该节点内容
- if (!title.equals("爱范儿")) {
- news.setTitle(title);
- }
- Log.i("MainActivity","------------------> "
- + "設置Title");
- } else if ("image".equals(parser.getName())) {
- String image = parser.nextText();// 获取该节点内容
- news.setImage(image);
- } else if ("description".equals(parser.getName())) {
-
- String description = parser.nextText();// 获取该节点内容
- if (!description.equals("连接热爱")) {
- news.setDescription(description);
- }
- } else if ("content:encoded".equals(parser.getName())) {
- // System.out.println("設置password");
- String content = parser.nextText();// 获取该节点内容
- news.setContent(content);
- }
-
- break;
-
- case XmlPullParser.END_TAG:
- if ("item".equals(parser.getName())) {
- Log.i("MainActivity","------> " + "得到RSS item");
- list.add(news);
- news = null;
-
- }
-
- break;
-
- }
- // 每次switch选择后跳转到下一标签,事件类型
- eventType = parser.next();
- }
-
- } catch (XmlPullParserException e) {
- // TODO Auto-generated catch block
- System.out.println("nikan 出错了吧");
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return list;
-
- }
-
- @Override
- protected void onPreExecute() {
- // TODO Auto-generated method stub
- super.onPreExecute();
- }
- //返回主线程,设置数据Adapter
- @Override
- protected void onPostExecute(List<News> result) {
- // TODO Auto-generated method stub
- super.onPostExecute(result);
- adapter = new NewsAdapter();
- listView.setAdapter(adapter);
-
- }
- };
自定义Adapter,使用ViewHolder模式
- class NewsAdapter extends BaseAdapter {
-
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return list.size();
- }
-
- @Override
- public Object getItem(int arg0) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public long getItemId(int arg0) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public View getView(int position,View convertView,ViewGroup arg2) {
- LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
- ViewHolder viewHolder = null;
-
- if (convertView == null) {
- // 若为空,则动态加载一个View
- convertView = inflater.inflate(R.layout.new_item,null);
-
- // ViewHolder初体验
- viewHolder = new ViewHolder();
- // 减少findViewById()的执行
- /* 不需要每次调用getView()方法就必定调用findViewById() */
- viewHolder.imageItem = (ImageView) convertView
- .findViewById(R.id.item_image);
- viewHolder.textItem = (TextView) convertView
- .findViewById(R.id.item_text);
-
- convertView.setTag(viewHolder);
-
- } else {
-
- /* viewHolder通过getTag()完成初始化 */
- viewHolder = (ViewHolder) convertView.getTag();
- }
-
- News news = list.get(position);
-
- Picasso.with(MainActivity.this).load(news.getImage()).resize(288,180).centerCrop()
- .into(viewHolder.imageItem);
- // viewHolder.imageItem.setImageUrl(IMAGE_URL,mImageLoader);
- viewHolder.textItem.setText(news.getTitle());
-
- return convertView;
- }
-
- }
-
- static class ViewHolder {
- private ImageView imageItem;
- private TextView textItem;
- }
实体类News
- package com.example.ifanrFeed.model;
-
- import java.io.Serializable;
-
- public class News implements Serializable{
- //索引
- private int index;
- //文章标题
- private String title;
- //文章题图
- private String image;
- //标签
- private String[] category;
- //描述
- private String description;
- //内容
- private String content;
- public int getIndex() {
- return index;
- }
- public void setIndex(int index) {
- this.index = index;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public String getImage() {
- return image;
- }
- public void setImage(String image) {
- this.image = image;
- }
- public String[] getCategory() {
- return category;
- }
- public void setCategory(String[] category) {
- this.category = category;
- }
- public String getDescription() {
- return description;
- }
- public void setDescription(String description) {
- this.description = description;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- @Override
- public String toString() {
- return "News [index=" + index + ",title=" + title + ",image=" + image
- + ",content=" + content + "]";
- }
-
-
-
- }
布局文件
activity_main.xml
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.ifanrFeed.MainActivity" tools:ignore="MergeRootFrame" >
-
- <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" >
- </ListView>
-
- </FrameLayout>
news_item.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="90dp" android:orientation="vertical" >
-
- <ImageView android:id="@+id/item_image" android:layout_width="144dp" android:layout_height="90dp" android:layout_marginLeft="10dp" android:src="@drawable/ic_launcher" />
-
- <TextView android:id="@+id/item_text" android:layout_toRightOf="@id/item_image" android:layout_width="wrap_content" android:layout_height="90dp" android:padding="10dp" android:textSize="15sp" android:text="神秘北极圈 阿拉斯加的山巅 谁的脸 出线海角的天边" >
- </TextView>
-
-
- </RelativeLayout>
获取信息结果
为每个Item添加事件响应
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> parent,View view,int position,long id) {
- News news=list.get(position);
- Bundle bundle=new Bundle();
- bundle.putSerializable("news",news);
-
- Intent intent=new Intent(MainActivity.this,NewsActivity.class);
- intent.putExtras(bundle);
- startActivity(intent);
-
- }
- });
注册创建News展示activity
activity_news.xml
- <?xml version="1.0" encoding="utf-8"?>
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
-
- <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5dp" android:orientation="vertical" >
-
- <TextView android:id="@+id/NewsTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margin="5dp" android:text="Title" android:textSize="25sp" />
-
- <ImageView android:id="@+id/TitleImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margin="5dp" />
-
- <TextView android:id="@+id/NewsContent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margin="5dp" android:text="Content" />
- </LinearLayout>
-
- </ScrollView>
- <activity android:name="com.example.ifanrFeed.NewsActivity" android:label="@string/app_name" >
- </activity>
TextView显示Html格式信息
- setContentView(R.layout.activity_news);
- final News news = (News) getIntent().getExtras().getSerializable("news");
- Log.i("MainActivity",news.toString());
-
- title = (TextView) this.findViewById(R.id.NewsTitle);
- titleImage = (ImageView) this.findViewById(R.id.TitleImage);
- content = (TextView) this.findViewById(R.id.NewsContent);
-
- title.setText(news.getTitle());
- Picasso.with(getApplicationContext()).load(news.getImage())
- .into(titleImage);
-
- Spanned newsSpan = Html.fromHtml(news.getContent());
- // content.setText(newsSpan);
- content.setMovementMethod(LinkMovementMethod.getInstance());
这种情况下只支持Html中文字信息,所有图片信息都是一个小方块儿,需要点击才能转到浏览器加载,很影响体验!
TextView异步显示Html中的图片
主要是运用Html.fromHtml 通过设置ImageGetter 获取html 中img 标签的图片信息。
- static Spanned fromHtml(String source,Html.ImageGetter imageGetter,Html.TagHandler tagHandler)
- package com.example.ifanrFeed;
-
- import java.io.IOException;
- import java.net.MalformedURLException;
- import java.net.URL;
-
- import android.app.Activity;
- import android.graphics.drawable.Drawable;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.text.Html;
- import android.text.Html.ImageGetter;
- import android.text.Spanned;
- import android.text.method.LinkMovementMethod;
- import android.util.Log;
- import android.widget.ImageView;
- import android.widget.TextView;
-
- import com.example.ifanrFeed.model.News;
- import com.squareup.picasso.Picasso;
-
- public class NewsActivity extends Activity {
- private TextView title;
- private ImageView titleImage;
- private TextView content;
- private Handler handler;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_news);
- final News news = (News) getIntent().getExtras()
- .getSerializable("news");
- Log.i("MainActivity",news.toString());
-
- title = (TextView) this.findViewById(R.id.NewsTitle);
- titleImage = (ImageView) this.findViewById(R.id.TitleImage);
- content = (TextView) this.findViewById(R.id.NewsContent);
-
- title.setText(news.getTitle());
- Picasso.with(getApplicationContext()).load(news.getImage())
- .into(titleImage);
-
- Spanned newsSpan = Html.fromHtml(news.getContent());
- // content.setText(newsSpan);
- content.setMovementMethod(LinkMovementMethod.getInstance());
-
- handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- if (msg.what == 0x101) {
-
- content.setText((CharSequence) msg.obj);
- }
- super.handleMessage(msg);
- }
- };
-
- // 因为从网上下载图片是耗时操作 所以要开启新线程
- Thread t = new Thread(new Runnable() {
- Message msg = Message.obtain();
-
- @Override
- public void run() {
-
- /** * 要实现图片的显示需要使用Html.fromHtml的一个重构方法:public static Spanned * fromHtml (String source,Html.ImageGetterimageGetter,* Html.TagHandler * tagHandler)其中Html.ImageGetter是一个接口,我们要实现此接口,在它的getDrawable * (String source)方法中返回图片的Drawable对象才可以。 */
- ImageGetter imageGetter = new ImageGetter() {
- @Override
- public Drawable getDrawable(String source) {
- // TODO Auto-generated method stub
- URL url;
- Drawable drawable = null;
- try {
- url = new URL(source);
- drawable = Drawable.createFromStream(
- url.openStream(),null);
- drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
- } catch (MalformedURLException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return drawable;
- }
- };
- CharSequence test = Html.fromHtml(news.getContent(),imageGetter,null);
- msg.what = 0x101;
- msg.obj = test;
- handler.sendMessage(msg);
- }
- });
- t.start();
-
- }
-
- @Override
- protected void onStart() {
- // TODO Auto-generated method stub
- super.onStart();
- }
-
- @Override
- protected void onRestart() {
- // TODO Auto-generated method stub
- super.onRestart();
- }
-
- @Override
- protected void onResume() {
- // TODO Auto-generated method stub
- super.onResume();
- }
-
- @Override
- protected void onPause() {
- // TODO Auto-generated method stub
- super.onPause();
- }
-
- @Override
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- }
- }
News展示页面
MainActivity.java
- package com.example.ifanrFeed;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.List;
-
- import org.xmlpull.v1.XmlPullParser;
- import org.xmlpull.v1.XmlPullParserException;
- import org.xmlpull.v1.XmlPullParserFactory;
-
- import android.app.Activity;
- import android.content.Intent;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.AdapterView;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.ListAdapter;
- import android.widget.ListView;
- import android.widget.TextView;
-
- import com.example.ifanrFeed.model.News;
- import com.example.ifanrFeed.service.HttpUtils;
- import com.example.ifanrFeed.service.RSSService.RSSList;
- import com.squareup.picasso.Picasso;
-
- public class MainActivity extends Activity implements RSSList {
- public static final String URL = "http://www.ifanr.com/Feed";
- private List<News> list;
- private ListAdapter adapter;
- private ListView listView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- listView = (ListView) this.findViewById(R.id.listView1);
-
- /* * RSSService service = new RSSService(getApplicationContext(),this); * // 监听事件,多线程,此处result还为null service.getRSSInfo(URL); */
- /* * 没吊用,错误的示范 String result=service.getResult(); Log.i("MainActivity",* "00000000000000------>"+result); */
- // Toast.makeText(this,result.subSequence(0,10),
- // Toast.LENGTH_SHORT).show();
- parseTask.execute("kanbujian");
-
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> parent,long id) {
- News news=list.get(position);
- Bundle bundle=new Bundle();
- bundle.putSerializable("news",NewsActivity.class);
- intent.putExtras(bundle);
- startActivity(intent);
-
- }
- });
- }
-
- AsyncTask<String,List<News>>() {
-
- @Override
- protected List<News> doInBackground(String... arg0) {
- String RSSInfo = arg0[0];
- News news = null;
- InputStream is = HttpUtils.getXml(URL);
- Log.i("MainActivity","------> " + "得到RSS item");
- list.add(news);
- news = null;
-
- }
-
- break;
-
- }
- // 每次switch选择后跳转到下一标签,事件类型
- eventType = parser.next();
- }
-
- } catch (XmlPullParserException e) {
- // TODO Auto-generated catch block
- System.out.println("nikan 出错了吧");
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return list;
-
- }
-
- @Override
- protected void onPreExecute() {
- // TODO Auto-generated method stub
- super.onPreExecute();
- }
-
- @Override
- protected void onPostExecute(List<News> result) {
- // TODO Auto-generated method stub
- super.onPostExecute(result);
- adapter = new NewsAdapter();
- listView.setAdapter(adapter);
-
- }
- };
-
- class NewsAdapter extends BaseAdapter {
-
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return list.size();
- }
-
- @Override
- public Object getItem(int arg0) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public long getItemId(int arg0) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public View getView(int position,mImageLoader);
- viewHolder.textItem.setText(news.getTitle());
-
- return convertView;
- }
-
- }
-
- static class ViewHolder {
- private ImageView imageItem;
- private TextView textItem;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
-
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main,menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button,so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void setRSSInfo(String RSSInfo) {
- Log.i("MainActivity","000000000000003------>" + RSSInfo);
-
- }
-
- }