android 网络请求Ⅰ

    本章讲述在android开发中,常用的网络请求操作。网络请求利用android基本的HttpURLConnection连接URL和开源网络请求包AsyncHttpClient。本次网络请求以调取天气接口查询天气为案例,对请求到的天气数据采用SQLite数据库存储,并利用ContentProvider数据共享模式操作存储数据。本章主要介绍知识点HttpURLConnection,AsyncHttpClient,ContentProvider,Json解析插件GsonFormat及Json解析类Gson。

1.功能需求

   做一个天气应用

  •  参考接口:http://apistore.baidu.com/apiworks/servicedetail/880.html,只是参考API,可自行查找使用其他API接口
  • 考察内容:获取数据,解析JSON
  • 数据缓存在数据库中,使用ContentProvider来处理
  • 如果不强制刷新,则使用缓存数据每隔一定时间再刷新一次

2.软件实现

                           图1

                            图2

                            图3

    简要说明:启动软件,通过图1界面可以选择查询天气的城市,点击查询直接查询该城市最近一周的天气指数,通过图3,下拉页面可重新请求刷新对应城市的天气指数。

3.相关知识

(1)ContentProvider

1.ContentProvider简介

    ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。

    内容提供者将一些特定的应用程序数据供给其它应用程序使用。数据可以存储于文件系统、 SQLite数据库或其它方式。内容提供者继承于ContentProvider 基类,为其它应用程序取用和存储它管理的数据实现了一套标准方法。然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。

2.ContentProvider用法

  • public boolean onCreate() 在创建ContentProvider时调用
  • public Cursor query(Uri, String[], String, String[], String) 用于查询指定Uri的ContentProvider,返回一个Cursor
  • public Uri insert(Uri, ContentValues) 用于添加数据到指定Uri的ContentProvider中
  • public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的数据
  • public int delete(Uri, String, String[]) 用于从指定Uri的ContentProvider中删除数据
  • public String getType(Uri) 用于返回指定的Uri中的数据的MIME类型

3.ContentResolver用法
     当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。 ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。

  • public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。
  • public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。
  • public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。
  • public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查询指定Uri的ContentProvider。

4.Uri类简介

    在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如select, add, delete, modify等操作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”, 代表数据的路径,和一个可选的标识数据的ID。以下是一些示例URI:

  • content://media/internal/images  这个URI将返回设备上存储的所有图片   
  • content://contacts/people/  这个URI将返回设备上的所有联系人信息
  • content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)
  • 自定义共享数据表路径规则:“content://”+项目包名称+数据表名称,如:content://www.csnt.com.geekbandsevenhomework/weather

5.ContentProvider与ContentResolver的区分

  • ContentProvider向外部提供操作数据的接口,相当于定义好规则,但并不能直接调用它定义的方法操作数据;
  • ContentResolver通过Uri这个类似桥梁的通道,调用 ContentProvider定义好的规则接口;

(2)HttpURLConnection简介

    标准Java接口(java.net) ,HttpURLConnection,可以实现简单的基于URL请求、响应功能;基本操作如下:

 1 //创建一个URL对象
 2 URL url = new URL(http://www.baidu.com);
 3 //利用HttpURLConnection对象从网络中获取网页数据
 4 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 5 //设置连接超时
 6 conn.setConnectTimeout(6*1000);
 7 //对响应码进行判断
 8 if (conn.getResponseCode() != 200)    //从Internet获取网页,发送请求,将网页以流的形式读回来
 9 throw new RuntimeException("请求url失败");
10 //得到网络返回的输入流
11 InputStream is = conn.getInputStream();
12 //String result = readData(is, "GBK"); //文件流输入出文件用outStream.write
13 //conn.disconnect();

(3)AsyncHttpClient

1.AsyncHttpClient简介

    An asynchronous callback-based Http client for Android built on top of Apache’s HttpClient libraries. All requests are made outside of your app’s main UI thread, but any callback logic will be executed on the same thread as the callback was created using Android’s Handler message passing.( 异步基于回调的Http客户端为Android构建,是基于Apache HttpClient库的。所有的请求都是位于应用程序主线程 UI 之外,但任何回调逻辑将相同的线程上执行回调,使用Android的处理程序创建消息传递。)官网地址:http://loopj.com/android-async-http

2.AsyncHttpClient特性

  • Make asynchronous HTTP requests, handle responses in anonymous callbacks  异步请求,回调处理响应
  • HTTP requests happen outside the UI thread 请求在子线程中
  • Requests use a threadpool to cap concurrent resource usage 使用线程池管理请求(线程)
  • GET/POST params builder (RequestParams)  使用RequestParams来设置请求参数
  • Multipart file uploads with no additional third party libraries    文件上传不使用第三方类库
  • Tiny size overhead to your application, only 60kb for everything   包大小只有60K
  • Automatic smart request retries optimized for spotty mobile connections 请求的重连功能
  • Automatic gzip response decoding support for super-fast requests  支持gzip
  • Optional built-in response parsing into JSON (JsonHttpResponseHandler)  可以使用JsonHttpResponseHandler将响应转化为JSON 类型
  • Optional persistent cookie store, saves cookies into your app's SharedPreferences 持久化数据,将Cookie数据保存在SharedPreferences中

3.AsyncHttpClient使用

创建一个新的AsyncHttpClient网络请求操作代码如下:
 1 AsyncHttpClient client = new AsyncHttpClient();
 2 client.get("https://www.google.com", new AsyncHttpResponseHandler() {
 3 
 4     @Override
 5     public void onStart() {
 6         // called before request is started
 7     }
 8 
 9     @Override
10     public void onSuccess(int statusCode, Header[] headers, byte[] response) {
11         // called when response HTTP status is "200 OK"
12     }
13 
14     @Override
15     public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
16         // called when response HTTP status is "4XX" (eg. 401, 403, 404)
17     }
18 
19     @Override
20     public void onRetry(int retryNo) {
21         // called when request is retried
22     }
23 });
AsyncHttpClient网络参数传递规则定义如下:
 1 //Create empty RequestParams and immediately add some parameters:
 2 RequestParams params = new RequestParams();
 3 params.put("key", "value");
 4 params.put("more", "data");
 5 //Add a File object to the RequestParams to upload:
 6 File myFile = new File("/path/to/file.png");
 7 RequestParams params = new RequestParams();
 8 try {
 9     params.put("profile_picture", myFile);
10 } catch(FileNotFoundException e) {}
11 //Add a byte array to the RequestParams to upload:
12 byte[] myByteArray = blah;
13 RequestParams params = new RequestParams();
14 params.put("soundtrack", new ByteArrayInputStream(myByteArray), "she-wolf.mp3");
15 //create Header 
16 client.addHeader("apikey", "keyvalue");

 4.GsonFormat插件

    GsonFormat安装方法:Android studio File->Settings..->Plugins–>Browse repositores..搜索GsonFormat。安装插件,重启android studio。GsonFormat插件主要是用于一键创建实体类的,创建一个类,在类的内部使用alt+Inset后,在弹出的对话框中将json数据粘贴到里边,json格式正确即可生成对应的类。界面操作如下图所示:

 

5.Gson简介

    Gson 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库。可以将一个 JSON 字符串转成一个 Java 对象,或者反过来。更多关于GSON的API可以访问:http://sites.google.com/site/gson

基本使用如下:

1 //声明Gson对象
2 Gson gson=new Gson();
3 //json字符串转换为对应类的对象
4 Person person = gson.fromJson(str, Person.class);

4.项目核心代码解析

    Android天气接口调用项目结构图如下所示:

(1)项目结构说明

  • db目录下的DataBaseHelper设置存储天气的数据库,设置数据表weather,存储从百度天气接口获取到的json数据。
  • fragment目录下的NetWorkFragmet表示天气查询页面处理类,其中查询是利用HttpURLConnection网络请求加异步操作处理获取的。
  • provider目录下的WeatherContentProvider表示本项目中共有数据接口定义。主要是提供通过ContentProvider模式管理数据库。
  • util目录下的httpUtils表示利用AsyncHttpClient的方式请求网络数据。
  • MainActivity中利用SwipeRefreshLayout控件,监听页面刷新时调用httpUtils中天气接口的函数完成天气数据的刷新。

(2)百度天气接口说明

    接口地址: http://apis.baidu.com/heweather/weather/free网页介绍地址:http://apistore.baidu.com/apiworks/servicedetail/478.html。点击网页调试界面如下所示:

(3)天气数据获取与存储

    天气获取是通过在MainActivity中刷新时,重新向网络发送请求获取数据。获取到天气数据后利用ContentProvider提供的共有模式保存数据,其中,由于返回格式的json数据格式利用GsonFormat插件生成类时会异常,主要是类的命名不规则,替换HeWeather data service 3.0字符串,改为一个规范的类名称即可。生成对应的Bean类以后,利用Gson的方式并可彻底解析Json字符串数据了。 天气数据请求及保存核心代码如下:

 1   /*
 2     利用异步网络请求:AsyncHttpClient 请求天气数据
 3      */
 4     public void GetWeather()
 5     {
 6         try {
 7             String select_city = "?city=" + citypinyin + "";
 8             HttpUtils.get(select_city, null, new TextHttpResponseHandler() {
 9                 @Override
10                 public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
11                 }
12                 @Override
13                 public void onSuccess(int statusCode, Header[] headers, String responseString) {
14                     //返回字符串不规则,先替换一下 对于Json数据,做数据分割,对于双引号之间的内容分割,用split("\"")
15                     String temp_old_replace= responseString.split("\"")[1];
16                     String temp_new_replace="HeWeatherDataService";
17                     responseString = responseString.replaceAll(temp_old_replace, temp_new_replace);  
18                     //获取到数据以后,做数据保存
19                     ContentValues contentValues = new ContentValues();
20                     contentValues.put(DatabaseHelper.City_name, citypinyin);
21                     contentValues.put(DatabaseHelper.City_Weather, responseString);
22                     //先删除数据
23                     int delete_result = weatherprovider.delete(weather_uri, null, null);
24                     if (delete_result != -1) {
25                         Uri insert_result = weatherprovider.insert(weather_uri, contentValues);
26                         if (insert_result != null) {
27                             //Toast.makeText(MainActivity.this, "数据本地保存成功", Toast.LENGTH_SHORT).show();
28                         } else {
29                             Toast.makeText(MainActivity.this, "数据本地保存失败", Toast.LENGTH_SHORT).show();
30                         }
31                     } else {
32                         Toast.makeText(MainActivity.this, "本地数据清除失败", Toast.LENGTH_SHORT).show();
33                     }
34                 }
35             });
36         }catch (Exception ex)
37         {
38         }
39     }

 (4)ContentProvider定义

    ContentProvider中定义操作数据库的函数及Uri,详细代码如下:

 1 package www.csnt.com.geekbandsevenhomework.provider;
 2 
 3 import android.content.ContentProvider;
 4 import android.content.ContentUris;
 5 import android.content.ContentValues;
 6 import android.content.UriMatcher;
 7 import android.database.Cursor;
 8 import android.database.sqlite.SQLiteDatabase;
 9 import android.net.Uri;
10 import android.support.annotation.Nullable;
11 import android.text.TextUtils;
12 
13 import www.csnt.com.geekbandsevenhomework.db.DatabaseHelper;
14 
15 /**
16  * Function:Create ContentProvider for Weather table
17  * Create date on 16/4/7.
18  *
19  * @author wangling
20  * @version 1.0
21  */
22 public class WeatherContentProvider extends ContentProvider {
23     private SQLiteDatabase mSqLiteDatabase;
24     private static UriMatcher sUriMatcher;
25     public static final int URI_MATCH_WEATHER = 1;
26     @Override
27     public boolean onCreate() {
28         DatabaseHelper databaseHelper = new DatabaseHelper(getContext());
29         mSqLiteDatabase = databaseHelper.getWritableDatabase();
30         sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
31         // content://www.csnt.com.geekbandsevenhomework/weather   1
32         sUriMatcher.addURI(URIList.AUTHORITY, DatabaseHelper.WEATHER_TABEL_NAME, URI_MATCH_WEATHER);
33         return false;
34     }
35 
36     @Nullable
37     @Override
38     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
39         String tableName = getTableName(uri);
40         if(TextUtils.isEmpty(tableName)){
41             return null;
42         }
43         Cursor cursor = mSqLiteDatabase
44                 .query(tableName, projection,selection, selectionArgs,null, null, sortOrder);
45         return cursor;
46     }
47 
48     @Nullable
49     @Override
50     public String getType(Uri uri) {
51         return null;
52     }
53 
54     @Nullable
55     @Override
56     public Uri insert(Uri uri, ContentValues values) {
57         String tableName = getTableName(uri);
58         if(TextUtils.isEmpty(tableName)){
59             return null;
60         }
61          long id = mSqLiteDatabase.insert(tableName, null,values);
62         return ContentUris.withAppendedId(uri, id);
63     }
64 
65     @Override
66     public int delete(Uri uri, String selection, String[] selectionArgs) {
67         String tableName = getTableName(uri);
68         if(TextUtils.isEmpty(tableName)){
69             return -1;
70         }
71         int count =mSqLiteDatabase.delete(tableName, selection,selectionArgs);
72         return count;
73     }
74 
75     @Override
76     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
77         String tableName = getTableName(uri);
78         if(TextUtils.isEmpty(tableName)){
79             return -1;
80         }
81         int count = mSqLiteDatabase.update(tableName, values,selection,selectionArgs);
82         return count;
83     }
84 
85     private String getTableName(Uri uri){
86         int type = sUriMatcher.match(uri);
87         String tableName = null;
88         switch (type){
89             case URI_MATCH_WEATHER:  //定义天气查询
90                 tableName = DatabaseHelper.WEATHER_TABEL_NAME;
91                 break;
92         }
93         return tableName;
94 
95     }
96 }
WeatherContentProvider

5.项目源代码下载

本项目源代码在360云盘上,开发环境为 Android Studio 2.0 。

https://yunpan.cn/cYamkZG3sq9jf  访问密码 f3d5。文件名称:android天气查询demo。

posted @ 2016-04-09 20:46  无涯Ⅱ  阅读(1211)  评论(0编辑  收藏  举报