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界面组件

  具体的AsyncTask的使用及源码分析请看这篇链接:http://blog.csdn.net/seu_calvin/article/details/52172248

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

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

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

又定义了一个返回byte数组downloadFromNet()方法,来获取数据的byte[]数组:
  /**
* 获取网络上下载下来的数据的byte数组
*
* @param urlPath 网络URL路径
* @return 网络上获取的json字符串的byte数组形式
*/
public static byte[] downloadFromNet(String urlPath) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
URL url = null;
try {
url = new URL(urlPath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setDoInput(true);
conn.connect();
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
int len;
byte b[] = new byte[1024];
//注意这里:is.read(b) 中的b数组一定要写,不然读取的数据不对
while ((len = is.read(b)) != -1) {
baos.write(b, 0, len);
baos.flush();
}
return baos.toByteArray();
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return baos.toByteArray();
}

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

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

json串对应的实体类:

 package com.yztc.lx.asynctasklistview.com.yztc.lx.bean;

 import java.util.List;

 /**
* 外层JsonObject对象
* Created by Lx on 2016/8/10.
*/ public class ShiGuang { private int totalCount;
private int pageCount;
private List<News> newsList;
}
 package com.yztc.lx.asynctasklistview.com.yztc.lx.bean;

 /**
* Created by Lx on 2016/8/10.
*/ public class News {
private int id;
private int type;
private String image;
private String title;
private String title2;
private String summary;
private String summaryInfo;
private String tag;
private int commentCount; @Override
public String toString() {
return "News{" +
"id=" + id +
", type=" + type +
", image='" + image + '\'' +
", title='" + title + '\'' +
", title2='" + title2 + '\'' +
", summary='" + summary + '\'' +
", summaryInfo='" + summaryInfo + '\'' +
", tag='" + tag + '\'' +
", commmentCount=" + commentCount +
'}';
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public int getType() {
return type;
} public void setType(int type) {
this.type = type;
} 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 getTitle2() {
return title2;
} public void setTitle2(String title2) {
this.title2 = title2;
} public String getSummary() {
return summary;
} public void setSummary(String summary) {
this.summary = summary;
} public String getSummaryInfo() {
return summaryInfo;
} public void setSummaryInfo(String summaryInfo) {
this.summaryInfo = summaryInfo;
} public String getTag() {
return tag;
} public void setTag(String tag) {
this.tag = tag;
} public int getCommmentCount() {
return commentCount;
} public void setCommmentCount(int commmentCount) {
this.commentCount = commmentCount;
}
}

下面是ParserJson类:

 package com.yztc.lx.asynctasklistview.com.yztc.lx.utils;

 import com.yztc.lx.asynctasklistview.com.yztc.lx.bean.News;

 import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import java.util.ArrayList;
import java.util.List; /**
* Created by Lx on 2016/8/10.
*/ public class ParserJson {
public static List<News> parserJsonToNews(String jsonString){
List<News> list=null;
try {
list=new ArrayList<>();
JSONObject obj=new JSONObject(jsonString);
JSONArray arr=obj.getJSONArray("newsList");
for(int i=0;i<arr.length();i++){
JSONObject obj1=arr.getJSONObject(i);
News news=new News();
news.setId(obj1.getInt("id"));
news.setTitle(obj1.getString("title"));
news.setSummary(obj1.getString("summary"));
list.add(news);
}
} catch (JSONException e) {
e.printStackTrace();
}
return list;
}
}

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

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

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

 <?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="wrap_content"> <TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Title"
android:textSize="20sp" /> <TextView
android:id="@+id/tv_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title"
android:padding="10dp"
android:text="Summary"
android:textSize="12sp" /> <TextView
android:id="@+id/tv_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/tv_summary"
android:padding="10dp"
android:text="id"
android:textSize="12sp" /> </RelativeLayout>

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

 package com.yztc.lx.asynctasklistview.com.yztc.lx.async;

 import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast; import com.yztc.lx.asynctasklistview.com.yztc.lx.adapter.MyBaseAdapter;
import com.yztc.lx.asynctasklistview.com.yztc.lx.bean.News;
import com.yztc.lx.asynctasklistview.com.yztc.lx.utils.HttpUtils;
import com.yztc.lx.asynctasklistview.com.yztc.lx.utils.ParserJson; import java.util.List; /**
* Created by Lx on 2016/8/10.
*/ public class DownloadAsyncTask extends AsyncTask<String, Void, List<News>> {
private Context mContext;
private ListView lv;
private Spinner sp; public DownloadAsyncTask(Context mContext, ListView lv) {
this.mContext = mContext;
this.lv = lv;
} @Override
protected List<News> doInBackground(String... params) {
List<News> list = null;
if(HttpUtils.isNetConn(mContext)){
byte[] b=HttpUtils.downloadFromNet(params[0]); //可变参数params当成一个数组使用,其中的params[0]就是我们传递过来的参数
String jsonString=new String(b);
Log.d("Tag",jsonString);
list=ParserJson.parserJsonToNews(jsonString);
Log.d("List",list.toString());
}
return list;
} @Override
protected void onPostExecute(List<News> newses) {
if(newses!=null&&newses.size()!=0){
MyBaseAdapter adapter=new MyBaseAdapter(mContext,newses);
lv.setAdapter(adapter);
}else {
Toast.makeText(mContext,"数据加载失败", Toast.LENGTH_SHORT).show();
}
}
}

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

 package com.yztc.lx.asynctasklistview.com.yztc.lx.adapter;

 import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView; import com.yztc.lx.asynctasklistview.R;
import com.yztc.lx.asynctasklistview.com.yztc.lx.bean.News; import java.util.List; /**
* Created by Lx on 2016/8/10.
*/ public class MyBaseAdapter extends BaseAdapter {
private Context mContext;
private List<News> list;
private LayoutInflater inflater; public MyBaseAdapter(Context context, List<News> list) {
this.mContext = context;
this.list = list;
this.inflater=LayoutInflater.from(mContext);
} /**
*
* @return 要填充的集合的长度
*/
@Override
public int getCount() {
return list.size();
} @Override
public Object getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} /**
*
* @param position 在适配器数据集合中的item的位置
* @param convertView 已经填充过的View,可以用来重用来提高加载速度
* @param parent 这个view将要展示的父容器
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
News news=list.get(position);
ViewHolder holder;
if(convertView==null){
holder=new ViewHolder();
convertView=inflater.inflate(R.layout.item,null);
holder.tv_id= (TextView) convertView.findViewById(R.id.tv_id);
holder.tv_summary= (TextView) convertView.findViewById(R.id.tv_summary);
holder.tv_title= (TextView) convertView.findViewById(R.id.tv_title);
convertView.setTag(holder);
}else{
holder= (ViewHolder) convertView.getTag();
}
holder.tv_id.setText(""+news.getId());
holder.tv_title.setText(news.getTitle());
holder.tv_summary.setText(news.getSummary());
return convertView;
} class ViewHolder{
private TextView tv_title,tv_summary,tv_id;
}
}

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

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

 package com.yztc.lx.asynctasklistview;

 import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import android.widget.Spinner; import com.yztc.lx.asynctasklistview.com.yztc.lx.async.DownloadAsyncTask; public class MainActivity extends AppCompatActivity { private ListView lv;
private String urlPath = "http://api.m.mtime.cn/News/NewsList.api?pageIndex=1"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.listview);
new DownloadAsyncTask(MainActivity.this,lv).execute(urlPath);
}
}

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

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

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

  1. Android 自定义 ListView 显示网络上 JSON 格式歌曲列表

    本文内容 环境 项目结构 演示自定义 ListView 显示网络上 JSON 歌曲列表 参考资料 本文最开始看的是一个国人翻译的文章,没有源代码可下载,根据文中提供的代码片段,自己新建的项目(比较可恶 ...

  2. KnockoutJS 3.X API 第七章 其他技术(1) 加载和保存JSON数据

    Knockout允许您实现复杂的客户端交互性,但几乎所有Web应用程序还需要与服务器交换数据,或至少将本地存储的数据序列化. 最方便的交换或存储数据的方式是JSON格式 - 大多数Ajax应用程序今天 ...

  3. Knockout应用开发指南 第六章:加载或保存JSON数据

    原文:Knockout应用开发指南 第六章:加载或保存JSON数据 加载或保存JSON数据 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地 ...

  4. 第六章:加载或保存JSON数据

    加载或保存JSON数据 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多 ...

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

    iOS开发网络篇—JSON数据的解析 iOS开发网络篇—JSON介绍 一.什么是JSON JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式 ...

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

    本文内容 什么是 Volley 库 Volley 能做什么 Volley 架构 环境 演示 Volley 库通过网络获取 JSON 数据 参考资料 Android 关于网络操作一般都会介绍 HttpC ...

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

    在开发项目project中,尤其是手机APP,一般都是先把界面给搭建出来.然后再从网上down数据 来填充 那么网上的数据是怎么得来的呢,网络上的数据无非就经常使用的两种JSON和XML 如今 大部分 ...

  8. D3.js加载csv和json数据

    1.加载数据的基本命令 D3提供了方法可以对不同的数据类型进行加载,比如d3.text(), d3.xml(), d3.json(), d3.csv(), 和d3.html(). <!DOCTY ...

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

    前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程 ...

随机推荐

  1. eclipse:failed to create the java virtual machine

    今天eclipse出现failed to create the java virtual machine无法启动,在网上找了解决办法如下: 找到eclipse目录下的eclipse.ini,可以看到如 ...

  2. QT 读取文件夹下所有文件(超级简单的方法,不需要QDirIterator)

    之前,用标准C++写过读取文件夹.现在用QT重写代码,顺便看了下QT如何实现,还是相当简单的.主要用到QDir,详细文档可见这里 A program that lists all the files ...

  3. CentOS查看内核版本,位数,版本号

    1)[root@localhost ~]# cat /proc/version Linux version 2.6.18-194.el5 (mockbuild@builder10.CentOS.org ...

  4. android sqlite 怎么写入存储时间

    字符串类型2013-12-10 12:12:12 SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd"); ...

  5. 120条Photoshop新手必看技巧

    Photoshop越来越强大了!试图掌控它的全部特性是不现实的(更何况有那么多隐藏的功能!),那么我们不妨收藏一下大神们总结的这120个PS技巧,偶尔翻看一下,让自己的设计更强大更高效! 这120款技 ...

  6. ubuntu12.10升级至14.04

    之前执行apt-get 不管是什么软件或apt-get update都会遇到fail to fetch http://us.archive.ubuntu.com quantal-updates/mai ...

  7. 如何实现上下左右键盘控制焦点使之落在相邻文本框或下拉框中-Web开发/JavaScript

    我用jquery只实现了文本框的移动(暂时上下移动等同于左右移动) $(function () { var cols = 1;//按一下跳几个控件 var obj = $("input[id ...

  8. YTU 2619: B 友元类-计算两点间距离

    2619: B 友元类-计算两点间距离 时间限制: 1 Sec  内存限制: 128 MB 提交: 469  解决: 252 题目描述 类Distance定义为类Point的友元类来实现计算两点之间距 ...

  9. Android模拟器分辨率介绍

    转自: http://www.cnblogs.com/xrtd/p/3746935.html 本人喜欢用  HVGA(320x480) Skins:HVGA.HVGA-L.HVGA-P.QVGA-L. ...

  10. BZOJ 2173 整数的lqp拆分

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2173 题意:给出输出n.设一种拆分为n=x1+x2+x3,那么这种拆分的价值为F(x1) ...