【Android 网络数据解析实现一个简单的新闻实例(一)】

      一般安卓在学到异步任务AsyncTask之后都会有个安卓小项目的任务。得到(荔枝新闻,茶百科等)新闻网络接口来解析网络图片或文字到ListView组件上显示。其中要使用到的知识大概有:获取网络数据(HttpUtil),解析网络数据(NewsParse),防止因解析超时应用程序无响应(ANR:Application 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显示数据。

源码在这里……

    

  

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值