【Android 网络数据解析实现一个简单的新闻实例(一)】
2015-11-10 21:17
1051 查看
一般安卓在学到异步任务AsyncTask之后都会有个安卓小项目的任务。得到(荔枝新闻,茶百科等)新闻网络接口来解析网络图片或文字到ListView组件上显示。其中要使用到的知识大概有:获取网络数据(HttpUtil),解析网络数据(NewsParse),防止因解析超时应用程序无响应(ANR:Application
Not Responding) 的异步任务(AsyncTask),还有一个自定义的适配器(NewsAdapter),还有就是实例化AsyncTask类传递路径进行解析加载的MainActivity了。剩下的就是两个xml了,一个是主方法的。一个是ListView的自定义布局xml,。本次博客就不讲解点击ListView后加载详情页面了。
先上图看看:
两个布局文件:
activity_main.xml
listview_item.xml
1,HttpUtil工具,专门用来网络获取数据的。直接上代码。
这是HttpGet获取的方式是一种特别简单的方式。
ImageUtil.java
今后这些工具类直接收藏起来,到时候要用的时候直接放入后调用就行。
4 AsyncTask异步任务类
上面已经谈到过一点了,在主线程中执行网络解析任务,响应时超过5秒,基本上会报一种叫ANR的错误。为了解决错误前期就用了异步任务去解决,当然等后期学到框架的时候,这些东西只需要一两个jar包就可以搞定。
NewsTask.java
DownloadImageTask.java
5 那就是主方法中要实现的了。MainActivity.java
哈哈,在这儿,基本就完成了ListView显示数据。
源码在这里……
Not Responding) 的异步任务(AsyncTask),还有一个自定义的适配器(NewsAdapter),还有就是实例化AsyncTask类传递路径进行解析加载的MainActivity了。剩下的就是两个xml了,一个是主方法的。一个是ListView的自定义布局xml,。本次博客就不讲解点击ListView后加载详情页面了。
先上图看看:
两个布局文件:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <TextView android:id="@+id/textView1" android:layout_width="fill_parent" android:layout_height="60dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:text="琦天下新闻" android:textColor="#ffffff" android:paddingTop="15dp" android:paddingLeft="110dp" android:background="#009999" android:textAppearance="?android:attr/textAppearanceLarge" /> <ListView android:id="@+id/listView1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#cccccc" android:layout_alignParentLeft="true" android:layout_below="@+id/textView1" > </ListView> </RelativeLayout>
listview_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="horizontal" android:layout_height="match_parent" > <RelativeLayout android:layout_width="fill_parent" android:layout_height="120dp" android:background="#fff">
<ImageView android:id="@+id/image" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/subject" android:layout_width="fill_parent" android:layout_height="40dp" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:textColor="#009966" android:textSize="14sp" android:layout_toRightOf="@+id/image" android:text="TextView" /> <TextView android:id="@+id/changed" android:layout_width="fill_parent" android:layout_height="20dp" android:layout_alignParentBottom="true" android:textColor="#999999" android:layout_toRightOf="@+id/image" android:text="TextView" /> <TextView android:id="@+id/summary" android:layout_width="fill_parent" android:layout_height="60dp" android:layout_above="@+id/changed" android:layout_toRightOf="@+id/image" android:text="TextView" /> </RelativeLayout> </LinearLayout>
1,HttpUtil工具,专门用来网络获取数据的。直接上代码。
这是HttpGet获取的方式是一种特别简单的方式。
public class HttpUtil { public static byte[] getJsonString(String path) throws ClientProtocolException, IOException{ byte[] data = null; HttpGet get = new HttpGet(path); HttpClient client = new DefaultHttpClient(); HttpResponse response = null; response = client.execute(get); if(response.getStatusLine().getStatusCode()==200) { data = EntityUtils.toByteArray(response.getEntity()); } return data; }再上一种获取数据方式吧,两种是一样的都是byte的类型,这些都是为了同时加载图片和使文字使用的方式,当然还有流的方式,但是我下面这个demo是将流的方式再转成byte方式。
public class HttpUtil { public static byte[] parseImage(String path){ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setReadTimeout(5000); connection.setDoInput(true); connection.connect(); if(connection.getResponseCode() == 200){ InputStream inputStream = connection.getInputStream(); int temp = 0; byte[] buffer = new byte[1024]; while ((temp = inputStream.read(buffer)) !=-1) { outputStream.write(buffer, 0, temp); outputStream.flush(); } } } catch (IOException e) { e.printStackTrace(); } return outputStream.toByteArray(); } }2,NewsParse解析获取到的数据也称JSON解析。
public class ParseTool { public static List<News> parseNews(String json) throws JSONException{ List<News> list = new ArrayList<News>(); JSONObject object = new JSONObject(json); object = object.getJSONObject("paramz"); //这个是获取集合名的字段“{ }” JSONArray array = object.getJSONArray("feeds");//这个是获取数组名的字段 “[ ]” int len = array.length(); for(int i = 0 ; i <len; i ++){ object = array.getJSONObject(i); object = object.getJSONObject("data"); String subject = object.getString("subject"); String summary = object.getString("summary"); String cover = object.getString("cover"); String changed = object.getString("changed"); News news = new News(); news.setSubject(subject); news.setCover(cover); news.setChanged(changed); news.setSummary(summary); list.add(news); } //这段用来查看有没有解析到 System.out.println("++++++++++++++++++++++++++++++++++++"+list); return list; } }3,自定义适配器NewsAdapter,是为了让ListView中的item是以自定义布局的方式显示的。而不是用ArrayAdapter的方式直接只显示一条数据。
public class NewsAdapter extends BaseAdapter { private List<News> list = null; private Context context =null; //private ViewHolder holder =null; public NewsAdapter(Context context, List<News> list) { // TODO Auto-generated constructor stub this.context = context; this.list = list; } @Override public int getCount() { int count = 0 ; if(list!=null){ count = list.size(); } return count; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null){ convertView = LayoutInflater.from(context).inflate(R.layout.item_person, parent,false); ViewHolder holder = new ViewHolder(); holder.cover = (ImageView) convertView.findViewById(R.id.image); holder.subject = (TextView) convertView.findViewById(R.id.subject); holder.summary = (TextView) convertView.findViewById(R.id.summary); holder.changed = (TextView) convertView.findViewById(R.id.changed); convertView.setTag(holder); } final ViewHolder holder = (ViewHolder) convertView.getTag(); String cover = list.get(position).getCover(); String subject = list.get(position).getSubject(); String summary = list.get(position).getSummary(); String changed = list.get(position).getChanged(); String imageUrl = "http://litchiapi.jstv.com"+cover; holder.subject.setText(subject); holder.summary.setText(summary); holder.changed.setText(changed); holder.cover.setImageResource(R.drawable.ic_launcher); //根据图片的地址去下载图片---用接口回调解决 Bitmap bitmap = ImageUtil.readImage(imageUrl);//这里还用到了图片缓存到扩展卡,方便图片加载 if(bitmap!=null){ holder.cover.setImageBitmap(bitmap); }else{ new DownImageTask(new DownImageTask.DownLoadBack() { //这儿用到了接口回调,下面会讲到 @Override public void response(Bitmap bitmap) { holder.cover.setImageBitmap(bitmap); } }).execute(imageUrl); } return convertView; } class ViewHolder{ TextView subject,changed,summary; ImageView cover; } }
ImageUtil.java
package com.example.newsapp.tool; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.os.Environment; import android.os.StatFs; /** * 操作扩展卡中文件的工具类(以缓存下载的图片为例 * 扩展卡对应的目录:mut/sdcard * @author Administrator * */ public class ImageUtil { //定义存储图片的目录 public static final String IMAGE_URL = Environment.getExternalStorageState()+"/cache/images"; public static final int FORMAT_PNG =1; public static final int FORMAT_JPEG =1; /** * 判断扩展卡是否挂载 * */ public static boolean isMounted(){ String state = Environment.getExternalStorageState();//获取扩展卡的状态 return state.equals(Environment.MEDIA_MOUNTED); } /** * 根据下载图片的路径获取图片的文件名 * */ public static String getFileName(String url){ return url.substring(url.lastIndexOf("/")+1); } /** * 保存图片到扩展卡 * @throws IOException * */ /* public static void saveImage(String url,byte[] data) throws IOException{ //判断扩展是否挂载 if(!isMounted()){ return ; } File dir = new File(IMAGE_URL); if(!dir.exists()){ dir.mkdir(); FileOutputStream fos = new FileOutputStream(new File(dir,getFileName(url))); fos.write(data); fos.close(); } } */ /** * 保存图片到扩展卡 * @throws IOException * */ public static void saveImage(String url , Bitmap bitmap,int format) throws IOException{ if(!isMounted()){ return; } File dir = new File(IMAGE_URL); if(!dir.exists()){ dir.mkdir(); } FileOutputStream fos = new FileOutputStream(new File(dir,getFileName(url))); bitmap.compress(format == 1? CompressFormat.PNG:CompressFormat.JPEG, 100, fos); fos.close(); } /** * 从扩展卡获取图片 */ public static Bitmap readImage(String url){ if(!isMounted()){ return null; } File file = new File(IMAGE_URL); Bitmap bitmap = null; if(file.exists()){ //根据图片文件路径得到Bitmap类型的对象 bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); } return bitmap; } /** * 清空图片缓存中的图片 */ public static void clear(){ File dir = new File(IMAGE_URL); if(dir.exists()){ File[] file = dir.listFiles(); for(File files : file){ files.delete(); } } } /** * 判断扩展卡的剩余空间 */ public static long getSize(){ StatFs statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath()); int count = statFs.getFreeBlocks();//得到剩余数据块的个数 int size = statFs.getBlockCount();//得到每个数据块的大小 long ssize = (count*size)/1024/1024; return ssize; } }
今后这些工具类直接收藏起来,到时候要用的时候直接放入后调用就行。
4 AsyncTask异步任务类
上面已经谈到过一点了,在主线程中执行网络解析任务,响应时超过5秒,基本上会报一种叫ANR的错误。为了解决错误前期就用了异步任务去解决,当然等后期学到框架的时候,这些东西只需要一两个jar包就可以搞定。
NewsTask.java
package com.example.newsapp.asyncTask; import java.io.IOException; import java.util.List; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; import com.example.newsapp.entity.News; import com.example.newsapp.newAdapter.NewsAdapter; import com.example.newsapp.tool.HttpUtil; import com.example.newsapp.tool.ParseTool; public class NewsTask extends AsyncTask<String, Void, List<News>> { private Context context; private ListView listView; public NewsTask(Context context, ListView listView) { super(); this.context = context; this.listView = listView; } @Override protected List<News> doInBackground(String... params) { // TODO Auto-generated method stub String url = params[0]; List<News> list = null; if(url!=null) { try { byte[] data = HttpUtil.getJsonString(url); String jsonString = new String(data,"utf-8"); list = ParseTool.parseNews(jsonString); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return list; } @Override protected void onPostExecute(List<News> result) { // TODO Auto-generated method stub super.onPostExecute(result); NewsAdapter adapter = new NewsAdapter(context, result); listView.setAdapter(adapter); } }当然下载图片也得用异步任务,有的图片5秒可下载不来的。
DownloadImageTask.java
package com.example.newsapp.asyncTask; import java.io.IOException; import org.apache.http.client.ClientProtocolException; import com.example.newsapp.tool.HttpUtil; import com.example.newsapp.tool.ImageUtil; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; public class DownImageTask extends AsyncTask<String, Void, Bitmap> { private DownLoadBack downLoadBack; public DownImageTask(DownLoadBack downLoadBack) { this.downLoadBack = downLoadBack; } @Override protected Bitmap doInBackground(String... params) { String url = params[0]; Bitmap bitmap = null; if(url!=null) { try { byte[] data = HttpUtil.getJsonString(url); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); //图片下载完成时,把图片存到扩展卡 ImageUtil.saveImage(url, bitmap, ImageUtil.FORMAT_JPEG); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bitmap; } @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); downLoadBack.response(result); } //在这里还用到接口回调,很多人都不理解接口回调是什么?当然在这儿只不过是用来传值而已。调用者需要被调用者的数据,那么被调用者就定义了一个接口(含方法),调用者在实例被调用者的时候,通过接口回调并实现接口中的方法,就可以得到被调用者的数据了。 public interface DownLoadBack { public void response(Bitmap bitmap); } }当然我这么说都不懂的,就看看:接口回调机制的详解
5 那就是主方法中要实现的了。MainActivity.java
package com.example.newsapp; import com.example.newsapp.asyncTask.NewsTask; import com.example.newsapp.entity.News; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; public class MainActivity extends Activity { private String path = "http://litchiapi.jstv.com/api/GetFeeds?column=0&PageSize=10&pageIndex=1&val=100511D3BE5301280E0992C73A9DEC41"; //这里就是地址了 private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.listView1); new NewsTask(this, listView/**这里传入的参数,与异步任务类构造函数的形参一致,位置别写反了*/).execute(path); //这里执行了异步任务的方法,并传入路径。 listView.setOnItemClickListener(new OnItemClickListener() { //这里我使用了一个点击ListView的监听,这儿一般是点击后就会跳转并显示该条目的详情,在这片文章中我还完善。 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String item = (String) listView.getItemAtPosition(position).toString(); Toast.makeText(getApplicationContext(), item, Toast.LENGTH_LONG).show(); } }); } }6 当然最后还得在清单文件(AndroidManifest.xml)中加上几个权限了。
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
哈哈,在这儿,基本就完成了ListView显示数据。
源码在这里……
相关文章推荐
- BP神经网络原理推导
- Hadoop2.7报It looks like you are making an HTTP request to a Hadoop IPC port. 问题解决
- light oj 1153 - Internet Bandwidth【网络流无向图】
- HTTP协议-telnet,httpwatch
- CentOS 网络配置详解
- 【应用笔记】【AN001】VC#开发环境下基于以太网的4-20mA电流采集(基于modbus tcp 协议)
- 【Android】 HttpClient 发送REST请求
- HttpURLConnection get post 方式请求 (笔记)
- Heritrix的介绍与使用
- 简易网络爬虫
- 网络爬虫介绍及数据采集
- 网络虚拟化服务之软件定义网络新机制 A New Mechanism for SDN Network Virtualization Service
- iOS开发网络篇—NSURLConnection基本使用
- [C#基础]网络编程(一):Socket
- asp.net httpmodule 访问页面控件 备忘
- 访问网络图片
- mac下搭建https服务器
- Android快速SDK(5)联网请求库QuickHttp
- AJAX之XMLHttpRequest对象
- Linux 本地yum源搭建和网络yum源搭建