使用非同步任務載入網路上json數據並載入到ListView中

来源:http://www.cnblogs.com/RabbitLx/archive/2016/08/10/5758953.html
-Advertisement-
Play Games

Android中使用網路訪問來載入網上的內容,並將其解析出來載入到控制項中,是一種很常見的操作。但是Android的UI線程(也就是主線程)中是不允許進行耗時操作的,因為耗時操作會阻塞主線程,影響用戶體驗。而訪問網路同樣是一個耗時操作,並且Android3.0以後是不允許在主線程中訪問網路的,所以我們 ...


  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中非同步任務的理解,也加深了訪問網路和自定義適配器的使用。
  最後的截圖如下:

 

 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • <td style="text-align:center;"> 讓表格中的字居中 style="width:75px; margin-left:1100px;" 增加同一行的兩個標簽的距離: margin-left:1100px 距離屏幕左邊的像素距離。 <a href="#"><i class=" ...
  • objKeySort(obj) ; //函數執行Object {ace: 5, age: 8, name: "zhangsan", nbme: "lisi"};// 執行結果 如果要倒序排列,只需在newkey這個數組中的每一項進行顛倒即可,即var newkey = Object.keys(obj ...
  • 很多時候佈局中需要文字垂直居中,有個CSS屬性:vertical-align: middle;該屬性在table里用是有效果的,很多塊級元素沒反應。這裡有2個屬性可以模擬table,來讓vertical-align: middle屬性生效。 很簡單父級元素給固定寬高加上屬性display: tabl ...
  • 最近有學習了JavaScript,學習的過程中發現js對於前端工程師來說可以是最終要的一部分。 個人認為js就是一門語言,如果把前端比作一個人的身體,那麼html就是一個人的結構,css就是這個人長的樣子,那麼JS就是一個人的行為,不是說Html和css不重要,只是JS 相比較而言更難一點,而且可以 ...
  • 先看看勞動成果 佈局 左右各一半(col-md-6) 左側登錄框占左側一半的10/12 右側是登錄系統的註意事項 使用到的BootStrap元素 well 輸入框組(input-group) 按鈕(btn-success) well 輸入框組(input-group) 按鈕(btn-success) ...
  • AngularJS[1] 誕生於2009年,由Misko Hevery 等人創建,後為Google所收購。是一款優秀的前端JS框架,已經被用於Google的多款產品當中。AngularJS有著諸多特性,最為核心的是:MVVM、模塊化、自動化雙向數據綁定、語義化標簽、依賴註入等等。 AngularJs ...
  • jquery-slider是一款基於JSON格式數據的jQuery幻燈片插件。該幻燈片通過JSON數據來提供圖片地址和描述信息等,你可以通過更換JSON數據來動態切換不同的圖片。 線上預覽 源碼下載 使用方法 在頁面中引入jquery和slider.js文件和font-awesome字體圖標文件。 ...
  • 以下是datepicker的css文件和js代碼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...