• 使用异步任务加载网络上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界面组件

      具体的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)如下所示:
     
     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中异步任务的理解,也加深了访问网络和自定义适配器的使用。
      最后的截图如下:
     
  • 相关阅读:
    linux下yum无法使用
    判断某个网卡是否是dhcp获取的ip
    个人作业---词频统计
    第四周读书笔记
    设计关键词
    好文收藏
    Apritag角点代码检测
    处理txt文件,保存为yml和cal文件
    欧拉角欧拉矩阵
    Mysql笔记01-安装和SQL基础
  • 原文地址:https://www.cnblogs.com/RabbitLx/p/5758953.html
Copyright © 2020-2023  润新知