使用异步任务加载网络上json数据并加载到ListView中

  Android中使用网络访问来加载网上的内容,并将其解析出来加载到控件中,是一种很常见的操作。但是Android的UI线程(也就是主线程)中是不允许进行耗时操作的,因为耗时操作会阻塞主线程,影响用户体验。而访问网络同样是一个耗时操作,并且Android3.0以后是不允许在主线程中访问网络的,所以我们这里用Android封装好的AsyncTask类来完成这些耗时操作。

  项目的目录结构如下:

  

  AsyncTask是一个抽象类,实际上他是封装好的一个类,底层也是用handler和thread来实现的,我们首先应该定义一个类来继承它。AsyncTask的继承是包含三个泛型参数的,这点官方文档上有详细说明,第一个参数是要操作的数据的类型,我们一般传入一个String字符串来表示网址;第二个参数是想要展示进度条的时候,进度条的参数类型,一般指定为Integer;第三个参数是doInBackground()方法操作返回的数据类型,这里根据你想操作什么样的数据类型,就返回什么样的数据类型。注意:这三个参数不是一定要设置,用到了哪个设置哪个,不需要的参数可以设置为Void。

  然后我们来看一下AsyncTask中的四个重要方法,基本上使用的时候我们都要重写这几个方法:

  • onPreExecute():这个方法是在UI线程中调用,当我们调用AsyncTask的execute()方法的时候,此方法会首先执行,主要是完成一些初始化的操作,比如多用于初始化并显示进度条
  • doInBackground(Params...):该方法在onPreExecute()方法调用结束之后调用,他的形参是一个可变参数,此方法在WorkThread也就是工作线程中完成,所有的耗时操作都要放在这个方法中执行,他可以将计算的结果返回到onPostExecute()方法中,同时在这里也可以调用publishProgress()方法来跳到onProgressUpdate()方法完成进度条刻度的更新,需要主要的是publishProgress()方法在WorkThread中完成,而onProgressUpdate()方法在UI线程中完成
  • onProgressUpdate(Progress...):当调用了publishProgress()方法的时候,在UI线程被调用此方法,实现进度条的更新
  • onPostExecute(Result):此方法在后台任务执行完后调用,在UI线程中执行,后台执行计算出的Result可以返回到此方法中,在此方法中可以更新UI界面组件

  大概看完了这四个方法,下面我们开始看看这次的Demo:

  因为是想要从网络上获取json数据,所以要先准备一个接口,我的接口是时光网的:

 http://api.m.mtime.cn/News/NewsList.api?pageIndex=1  为了得到这个接口中的Json格式的数据,我们先定义了一个HttpUtils类,在其中先定义了一个测试网络是否联通的类isNetConn(Context context)如下所示: 
 1 /**
 2      * 获取网络状态
 3      *
 4      * @param context 上下文
 5      * @return 联通状态
 6      */
 7     public static boolean isNetConn(Context context) {
 8         //获取网络连接管理对象
 9         ConnectivityManager manager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
10         //获取活跃状态的网络信息对象
11         NetworkInfo info = manager.getActiveNetworkInfo();
12         if (info != null) {
13             return info.isConnected();  //返回是否链接
14         } else {
15             return false;
16         }
17
18     }

又定义了一个返回byte数组downloadFromNet()方法,来获取数据的byte[]数组:
 1  /**
 2      * 获取网络上下载下来的数据的byte数组
 3      *
 4      * @param urlPath 网络URL路径
 5      * @return  网络上获取的json字符串的byte数组形式
 6      */
 7     public static byte[] downloadFromNet(String urlPath) {
 8         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 9         URL url = null;
10         try {
11             url = new URL(urlPath);
12             HttpURLConnection conn = (HttpURLConnection) url.openConnection();
13             conn.setRequestMethod("GET");
14             conn.setConnectTimeout(5000);
15             conn.setReadTimeout(5000);
16             conn.setDoInput(true);
17             conn.connect();
18             if (conn.getResponseCode() == 200) {
19                 InputStream is = conn.getInputStream();
20                 int len;
21                 byte b[] = new byte[1024];
22                 //注意这里:is.read(b) 中的b数组一定要写,不然读取的数据不对
23                 while ((len = is.read(b)) != -1) {
24                     baos.write(b, 0, len);
25                     baos.flush();
26                 }
27                 return baos.toByteArray();
28             }
29             return baos.toByteArray();
30         } catch (IOException e) {
31             e.printStackTrace();
32         }
33         return baos.toByteArray();
34     }

之所以返回byte[]数组类型,是方便我们下载其他东西的时候也可以使用。

  获取到了json字符串,下一步就是将其解析出来,定义一个ParserJson方法,json字符串的解析相信大家应该都是了解的,因为这是Android中非常重要的一部分知识,这里就不再赘述,直接上代码:

json串对应的实体类:

 1 package com.yztc.lx.asynctasklistview.com.yztc.lx.bean;
 2
 3 import java.util.List;
 4
 5 /**
 6  * 外层JsonObject对象
 7  * Created by Lx on 2016/8/10.
 8  */
 9
10 public class ShiGuang {
11
12     private int totalCount;
13     private int pageCount;
14     private List<News> newsList;
15 }
  1 package com.yztc.lx.asynctasklistview.com.yztc.lx.bean;
  2
  3 /**
  4  * Created by Lx on 2016/8/10.
  5  */
  6
  7 public class News {
  8     private int id;
  9     private int type;
 10     private String image;
 11     private String title;
 12     private String title2;
 13     private String summary;
 14     private String summaryInfo;
 15     private String tag;
 16     private int commentCount;
 17
 18     @Override
 19     public String toString() {
 20         return "News{" +
 21                 "id=" + id +
 22                 ", type=" + type +
 23                 ", image=‘" + image + ‘\‘‘ +
 24                 ", title=‘" + title + ‘\‘‘ +
 25                 ", title2=‘" + title2 + ‘\‘‘ +
 26                 ", summary=‘" + summary + ‘\‘‘ +
 27                 ", summaryInfo=‘" + summaryInfo + ‘\‘‘ +
 28                 ", tag=‘" + tag + ‘\‘‘ +
 29                 ", commmentCount=" + commentCount +
 30                 ‘}‘;
 31     }
 32
 33     public int getId() {
 34         return id;
 35     }
 36
 37     public void setId(int id) {
 38         this.id = id;
 39     }
 40
 41     public int getType() {
 42         return type;
 43     }
 44
 45     public void setType(int type) {
 46         this.type = type;
 47     }
 48
 49     public String getTitle() {
 50         return title;
 51     }
 52
 53     public void setTitle(String title) {
 54         this.title = title;
 55     }
 56
 57     public String getImage() {
 58         return image;
 59     }
 60
 61     public void setImage(String image) {
 62         this.image = image;
 63     }
 64
 65     public String getTitle2() {
 66         return title2;
 67     }
 68
 69     public void setTitle2(String title2) {
 70         this.title2 = title2;
 71     }
 72
 73     public String getSummary() {
 74         return summary;
 75     }
 76
 77     public void setSummary(String summary) {
 78         this.summary = summary;
 79     }
 80
 81     public String getSummaryInfo() {
 82         return summaryInfo;
 83     }
 84
 85     public void setSummaryInfo(String summaryInfo) {
 86         this.summaryInfo = summaryInfo;
 87     }
 88
 89     public String getTag() {
 90         return tag;
 91     }
 92
 93     public void setTag(String tag) {
 94         this.tag = tag;
 95     }
 96
 97     public int getCommmentCount() {
 98         return commentCount;
 99     }
100
101     public void setCommmentCount(int commmentCount) {
102         this.commentCount = commmentCount;
103     }
104 }

下面是ParserJson类:

 1 package com.yztc.lx.asynctasklistview.com.yztc.lx.utils;
 2
 3 import com.yztc.lx.asynctasklistview.com.yztc.lx.bean.News;
 4
 5 import org.json.JSONArray;
 6 import org.json.JSONException;
 7 import org.json.JSONObject;
 8
 9 import java.util.ArrayList;
10 import java.util.List;
11
12 /**
13  * Created by Lx on 2016/8/10.
14  */
15
16 public class ParserJson {
17     public static List<News> parserJsonToNews(String jsonString){
18         List<News> list=null;
19         try {
20             list=new ArrayList<>();
21             JSONObject obj=new JSONObject(jsonString);
22             JSONArray arr=obj.getJSONArray("newsList");
23             for(int i=0;i<arr.length();i++){
24                 JSONObject obj1=arr.getJSONObject(i);
25                 News news=new News();
26                 news.setId(obj1.getInt("id"));
27                 news.setTitle(obj1.getString("title"));
28                 news.setSummary(obj1.getString("summary"));
29                 list.add(news);
30             }
31         } catch (JSONException e) {
32             e.printStackTrace();
33         }
34         return list;
35     }
36 }

json串格式化后的一部分如下所示:

本Demo中只解析了newsList中的部分内容,包括id,title,summary这三部分,但是实体类中基本上都定义了。

  定义完了这些工具类之后,我们在主页面的布局中加入一个ListView控件,再定义一个item.xml用来作为ListView的自布局,主界面就不上代码了,下面看一下item的布局:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content">
 5
 6     <TextView
 7         android:id="@+id/tv_title"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:padding="10dp"
11         android:text="Title"
12         android:textSize="20sp" />
13
14     <TextView
15         android:id="@+id/tv_summary"
16         android:layout_width="wrap_content"
17         android:layout_height="wrap_content"
18         android:layout_below="@+id/tv_title"
19         android:padding="10dp"
20         android:text="Summary"
21         android:textSize="12sp" />
22
23     <TextView
24         android:id="@+id/tv_id"
25         android:layout_width="wrap_content"
26         android:layout_height="wrap_content"
27         android:layout_alignParentRight="true"
28         android:layout_alignTop="@+id/tv_summary"
29         android:padding="10dp"
30         android:text="id"
31         android:textSize="12sp" />
32
33 </RelativeLayout>

   基本工作都完成了,下面完成异步任务类DownloadAsyncTask中的内容,因为在进入后台线程前没有什么准备工作,并且也不需要进度条,所以就只重写了doInBackground()方法和onPostExecute()方法,代码如下:

 1 package com.yztc.lx.asynctasklistview.com.yztc.lx.async;
 2
 3 import android.content.Context;
 4 import android.os.AsyncTask;
 5 import android.util.Log;
 6 import android.widget.ListView;
 7 import android.widget.Spinner;
 8 import android.widget.Toast;
 9
10 import com.yztc.lx.asynctasklistview.com.yztc.lx.adapter.MyBaseAdapter;
11 import com.yztc.lx.asynctasklistview.com.yztc.lx.bean.News;
12 import com.yztc.lx.asynctasklistview.com.yztc.lx.utils.HttpUtils;
13 import com.yztc.lx.asynctasklistview.com.yztc.lx.utils.ParserJson;
14
15 import java.util.List;
16
17 /**
18  * Created by Lx on 2016/8/10.
19  */
20
21 public class DownloadAsyncTask extends AsyncTask<String, Void, List<News>> {
22     private Context mContext;
23     private ListView lv;
24     private Spinner sp;
25
26     public DownloadAsyncTask(Context mContext, ListView lv) {
27         this.mContext = mContext;
28         this.lv = lv;
29     }
30
31
32     @Override
33     protected List<News> doInBackground(String... params) {
34         List<News> list = null;
35         if(HttpUtils.isNetConn(mContext)){
36             byte[] b=HttpUtils.downloadFromNet(params[0]);  //可变参数params当成一个数组使用,其中的params[0]就是我们传递过来的参数
37             String jsonString=new String(b);
38             Log.d("Tag",jsonString);
39             list=ParserJson.parserJsonToNews(jsonString);
40             Log.d("List",list.toString());
41         }
42         return list;
43     }
44
45     @Override
46     protected void onPostExecute(List<News> newses) {
47         if(newses!=null&&newses.size()!=0){
48             MyBaseAdapter adapter=new MyBaseAdapter(mContext,newses);
49             lv.setAdapter(adapter);
50         }else {
51             Toast.makeText(mContext,"数据加载失败", Toast.LENGTH_SHORT).show();
52         }
53     }
54 }

  因为要更新UI中的ListView,所以在DownloadAsyncTask的构造函数中传入了ListView和Context两个形参。在doInBackground()方法中完成了数据计算操作后,将返回一个List<News>类型的变量,会接着执行onPostExecute()方法,变量会传到他的形参中。通过这个List集合,我们来完成ListView的数据的填充。填充ListView首先需要自定义一个适配器继承自BaseAdapter,我们取名为MyBaseAdapter。为其传入Context和list两个参数,至于ListView的填充请看我的另一篇博客,下面直接上代码:

 1 package com.yztc.lx.asynctasklistview.com.yztc.lx.adapter;
 2
 3 import android.content.Context;
 4 import android.view.LayoutInflater;
 5 import android.view.View;
 6 import android.view.ViewGroup;
 7 import android.widget.BaseAdapter;
 8 import android.widget.TextView;
 9
10 import com.yztc.lx.asynctasklistview.R;
11 import com.yztc.lx.asynctasklistview.com.yztc.lx.bean.News;
12
13 import java.util.List;
14
15 /**
16  * Created by Lx on 2016/8/10.
17  */
18
19 public class MyBaseAdapter extends BaseAdapter {
20     private Context mContext;
21     private List<News> list;
22     private LayoutInflater inflater;
23
24     public MyBaseAdapter(Context context, List<News> list) {
25         this.mContext = context;
26         this.list = list;
27         this.inflater=LayoutInflater.from(mContext);
28     }
29
30     /**
31      *
32      * @return  要填充的集合的长度
33      */
34     @Override
35     public int getCount() {
36         return list.size();
37     }
38
39
40     @Override
41     public Object getItem(int position) {
42         return list.get(position);
43     }
44
45     @Override
46     public long getItemId(int position) {
47         return position;
48     }
49
50     /**
51      *
52      * @param position  在适配器数据集合中的item的位置
53      * @param convertView  已经填充过的View,可以用来重用来提高加载速度
54      * @param parent  这个view将要展示的父容器
55      * @return
56      */
57     @Override
58     public View getView(int position, View convertView, ViewGroup parent) {
59         News news=list.get(position);
60         ViewHolder holder;
61         if(convertView==null){
62             holder=new ViewHolder();
63             convertView=inflater.inflate(R.layout.item,null);
64             holder.tv_id= (TextView) convertView.findViewById(R.id.tv_id);
65             holder.tv_summary= (TextView) convertView.findViewById(R.id.tv_summary);
66             holder.tv_title= (TextView) convertView.findViewById(R.id.tv_title);
67             convertView.setTag(holder);
68         }else{
69             holder= (ViewHolder) convertView.getTag();
70         }
71         holder.tv_id.setText(""+news.getId());
72         holder.tv_title.setText(news.getTitle());
73         holder.tv_summary.setText(news.getSummary());
74         return convertView;
75     }
76
77     class ViewHolder{
78         private TextView tv_title,tv_summary,tv_id;
79     }
80 }

  这里需要注意的是,不要忘了为ListView设置适配器setAdapter(adapter).。还有就是setText()方法有一个重载形式是:setText(int i)传入了一个int类型的形参的话,系统会根据这个int类型的参数去查找资源ID,所以如果要为TextView设置一个整型的形参的话,需要将其转换为字符串的格式,不然会报错。

  接下来要做的就是在主函数中调用我们的异步任务了:

 1 package com.yztc.lx.asynctasklistview;
 2
 3 import android.os.Bundle;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.widget.ListView;
 6 import android.widget.Spinner;
 7
 8 import com.yztc.lx.asynctasklistview.com.yztc.lx.async.DownloadAsyncTask;
 9
10 public class MainActivity extends AppCompatActivity {
11
12     private ListView lv;
13     private String urlPath = "http://api.m.mtime.cn/News/NewsList.api?pageIndex=1";
14
15     @Override
16     protected void onCreate(Bundle savedInstanceState) {
17         super.onCreate(savedInstanceState);
18         setContentView(R.layout.activity_main);
19         lv = (ListView) findViewById(R.id.listview);
20         new DownloadAsyncTask(MainActivity.this,lv).execute(urlPath);
21     }
22 }

  注意:不要忘了写execute()方法。

  至此,整个Demo就完成了,没有什么难得逻辑,就是一些小的问题需要注意一下,通过这个小Demo提高了我对Android中异步任务的理解,也加深了访问网络和自定义适配器的使用。  最后的截图如下:
 
时间: 2024-08-09 21:55:40

使用异步任务加载网络上json数据并加载到ListView中的相关文章

ios学习(从网络上获取数据)

从网络上获取数据: 1.从网络上获取数据,采用如下这种方式会带来主线成阻塞现象,主线成主要是负责的是ui的交互(用户输入指令或数据,系统给一个反馈) 会进一步让ui停止交互 1)首先给我们将要下载的图片设置好位置 UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"地址"]]]; UIImageView *imageView = [[UIImageVie

iOS开发网络篇—JSON数据的解析

iOS开发网络篇—JSON数据的解析 iOS开发网络篇—JSON介绍 一.什么是JSON JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) JSON的格式很像OC中的字典和数组 {"name" : "jack", "age" : 10} {"names" : ["jack", "rose", "jim

Android Volley 库通过网络获取 JSON 数据

本文内容 什么是 Volley 库 Volley 能做什么 Volley 架构 演示 Volley 库通过网络获取 JSON 数据 参考资料 Android 关于网络操作一般都会介绍 HttpClient 以及 HttpConnection 这两个包.前者是 Apache 开源库,后者是 Android 自带 API.企业级应用,一般都会选择使用已经封装好的 http 框架.比较流行有 Volley.android-async-http.retrofit.okhttp.androidquery.

Snail—iOS网络学习之得到网络上的数据

在开发项目工程中,尤其是手机APP,一般都是先把界面给搭建出来,然后再从网上down数据 来填充 那么网上的数据是怎么得来的呢,网络上的数据无非就常用的两种JSON和XML 现在 大部分都是在用JSON 网络上传输数据都是以二进制形式进行传输的 ,只要我们得到网上的二进制数据 如果它是JSON的二进制形式 那么我们就可以用JSON进行解析 如果是XML,那么我们可以用XML解析 关键是怎么得到网上的二进制数据呢 设计一个常用的工具类 很简单 给我一个接口(URL),那我就可以用这个类得到二进制文

Android 网络请求json数据,解析json数据,生成对应的java bean类一步到位,快速开发

Android 网络请求一般都涉及到图片和JSON数据,怎样快速的请求网络JSON数据,解析JSON数据,并且一步生成自己想要的Java bean实体类?这个涉及到Android 开发效率的问题.由于接触Android 网络这方面比较多,自然就找到一些好的方法来快速开发Android 网络模块的相关内容,接下来就为大家揭晓 一步快速请求,解析JSON 数据生成对应的Java bean实体类的方法. 注:我们先把思路讲解下吧: 1.网络请求JSON数据代码可以自己写,当然我还是推荐使用网络上开源的

(转)mac 下使用wireshark监听网络上的数据

mac 下使用wireshark监听网络上的数据 分三个步骤: 1.wireshark安装 wireshark运行需要mac上安装X11,mac 10.8的系统上默认是没有X11的.先去http://xquartz.macosforge.org/landing/下载最新的 xquartz安装,安装好就有X11了. wireshark的下载,网上有很多下载源.官网试了几次,没打开的成.可以考虑去华军之类的网站上下载. 2.打开网卡,允许wireshark访问 安装好xquartz和wireshar

D3.js加载csv和json数据

1.加载数据的基本命令 D3提供了方法可以对不同的数据类型进行加载,比如d3.text(), d3.xml(), d3.json(), d3.csv(), 和d3.html(). <!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>test</title> &l

6.Knockout.Js(加载或保存JSON数据)

前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程序也是使用这种格式. 加载或保存数据 Knockout不限制你用任何技术加载和保存数据.你可以使用任何技术和服务器来交互.用的最多的是使用jQuery的Ajax帮助,例如:getJSON,post和ajax.你可以通过这些方法从服务器端获取数据: $.getJSON("/some/url"

Volley 库通过网络获取 JSON 数据

1.通过Volley的newRequestQueue(Context context)方法初始化RequestQueue对象 2.定义一个JSON数据的字符串网络地址  可用的JSON接口(http://www.weather.com.cn/adat/sk/101010100.html) 3.根据Volley提供的JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener<JSONObject> list