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_1000_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);
}
}