android--网络编程

Http请求方式
方法 描述
GET 请求指定url的数据,请求体为空(例如打开网页)。
POST 请求指定url的数据,同时传递参数(在请求体中)。
HEAD 类似于get请求,只不过返回的响应体为空,用于获取响应头。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。

常用只有Post与Get。

HttpURLConnection的用法

申明网络权限!

<uses-permission android:name="android.permission.INTERNET"/>

使用post请求方式

public String post(String url, String content) {
    HttpURLConnection conn = null;
    try {
        // 创建一个URL对象
        URL mURL = new URL(url);
        // 调用URL的openConnection()方法,获取HttpURLConnection对象
        conn = (HttpURLConnection) mURL.openConnection();

        conn.setRequestMethod("POST");// 设置请求方法为post
        conn.setReadTimeout(5000);// 设置读取超时为5秒
        conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
        conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容

        // post请求的参数
        String data = content;
        // 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
        OutputStream out = conn.getOutputStream();// 获得一个输出流,向服务器写数据
        out.write(data.getBytes());
        out.flush();
        out.close();

        int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
        if (responseCode == 200) {
            InputStream is = conn.getInputStream();
            String response = getStringFromInputStream(is);
            return response;
        } else {
            throw new NetworkErrorException("response status is "+responseCode);
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (conn != null) {
            conn.disconnect();// 关闭连接
        }
    }

    return null;
}

使用GET请求方式

public String get(String url) {
    HttpURLConnection conn = null;
    try {
        // 利用string url构建URL对象
        URL mURL = new URL(url);
        conn = (HttpURLConnection) mURL.openConnection();

        conn.setRequestMethod("GET");
        conn.setReadTimeout(5000);
        conn.setConnectTimeout(10000);

        int responseCode = conn.getResponseCode();
        if (responseCode == 200) {
            InputStream is = conn.getInputStream();
            String response = getStringFromInputStream(is);
            return response;
        } else {
            throw new NetworkErrorException("response status is "+responseCode);
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {

        if (conn != null) {
            conn.disconnect();
        }
    }

    return null;
}

getStringFromInputStream方法

private String getStringFromInputStream(InputStream is)
        throws IOException {
    //字节数组输出流在内存中创建一个字节数组缓冲区,
    //所有发送到输出流的数据保存在该字节数组缓冲区中。
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = -1;
    while ((len = is.read(buffer)) != -1) {
        os.write(buffer, 0, len);
       //将指定字节数组中从偏移量off开始的len个字节写入此字节数组输出流。
    }
    is.close();
    // 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
    String state = os.toString();
    os.close();
    return state;
}

网络请求响应码
200:表示成功,正常结果;
302:表示重定向,转到别的站点;
304:表示未修改;
404:表示找不到资源;
500:表示内部服务器错误;

使用AsyncTask异步任务

做Android应用的时候,进程需要在一个子线程执行一些耗时的操作,例如下载等。这种情况我们一般使用Handler和线程结合处理,子线程负责处理耗时操作,然后通知Handler处理UI更新。Handler和子线程结合处理适合对精度控制要求比较高或者任务耗时比较长或者比较反复的情况。除了Handler和线程结合使用,Android也为我们提供了另外一种选择,也就是AsyncTask。

AsyncTask被设计为Thread 和 Handler一个帮助类并且不会建立一个通用的线程框架。AsyncTasks适用于耗时较短的操作。

如果需要保持线程长时间运行,android官方开发者网站推荐使用java.util.concurrent包里提供的不同的API,例如Executor,ThreadPoolExecutor 和 FutureTask。

1.android.os.AsyncTask的定义

public abstract class AsyncTask<Params, Progress, Result>

  • Params:发送到任务执行的参数
  • Progress:更新的进度,一般用来更新UI的进度信息
  • Result:是执行后的返回结果

这些参数都是泛型定义,所以我们可以定义自己的数据类型作为参数,另外如果不需要相关传输,可以传入Void即可。

2.AsyncTask中的方法

执行异步任务,启动异步任务方法:excute(Params... params)

public final AsyncTask<Params, Progress, Result> execute(Params... params) 
{
   return executeOnExecutor(sDefaultExecutor, params);
}

execute()被调用后立即执行的方法onPreExecute(),可以做一些任务初始化

// 在后台work之前
 // 主线程
protected void onPreExecute() { }

在onPreExecute()执行后执行的方法doInBackground( )
在此方法中可以执行一些耗时操作,方法将接收输入参数和返回计算结果。在执行过程中可以调用publishProgress()来更新进度信息

//不能在里面更新UI,否则有异常。
protected abstract Result doInBackground(Params... params);
protected void onProgressUpdate(Progress... values){ }

doInBackground执行完后,会回调onPostExecute方法,用于更新界面信息

//执行完之后在主线程中
protected void onPostExecute(Result result) { }
3.使用AsyncTask

使用AsyncTask必须创建一个子类。子类至少重写一个方法 (doInBackground(Params…)),通常重写的第二个是(onPostExecute(Result))。

使用AsyncTask下载图片

private class DownLoad extends AsyncTask<String, Integer, String> 
{
    //onPreExecute方法在execute()后执行
    @Override  
    protected void onPreExecute() 
    {  
        Log.i(TAG, "onPreExecute() enter");  
        mShowLogTextView.setText("onPreExecute。。。begin downLoad");  
    }  
      
    //doInBackground方法内部执行后台任务,不能在里面更新UI,否则有异常。
    @Override  
    protected String doInBackground(String... params) 
    {  
        Log.i(TAG, "doInBackground(String... params) enter");  
        
        URL imageUrl=null;
        try 
        {
            imageUrl=new URL(params[0]);
        } 
        catch (MalformedURLException e) 
        {
            e.printStackTrace();
            Log.e(TAG, e.getMessage());
        }
        try
        {
            //使用HttpURLConnection打开连接
            HttpURLConnection urlConn=(HttpURLConnection)imageUrl.openConnection();
            urlConn.setDoInput(true);
            urlConn.connect();
            //将得到的数据转化成InputStream
            InputStream is=urlConn.getInputStream();
            //将InputStream转换成Bitmap
            mDownLoadBtBitmap=BitmapFactory.decodeStream(is);
            is.close();
            //不能在这里更新UI,否则有异常******
            //mNetImageView.setImageBitmap(bitmap);
        }catch(IOException e)
        {
            Log.e(TAG,e.getMessage());
        }
        
        return "ok";
    }  
      
    //onProgressUpdate方法用于更新进度信息  
    @Override  
    protected void onProgressUpdate(Integer... progresses) 
    {  
        Log.i(TAG, "onProgressUpdate(Integer... progresses) enter");  

        mShowLogTextView.setText("onProgressUpdate Downloading...");  
    }  
      
    //onPostExecute用于doInBackground执行完后,更新界面UI。
    //result是doInBackground返回的结果
    @Override  
    protected void onPostExecute(String result) 
    {  
        Log.i(TAG, "onPostExecute(Result result) called");  
        mShowLogTextView.setText("Down load finish result="+result);  
          
        mNetImageView.setImageBitmap(mDownLoadBtBitmap);
    }  
      
    //onCancelled方法用于取消Task执行,更新UI
    @Override  
    protected void onCancelled() 
    {  
        Log.i(TAG, "onCancelled() called");  
        mShowLogTextView.setText("onCancelled");  
    }  
}
public void onClick(View v)
{
    if (v==mPlayMusicButton)
    {
        //传入下载图片的地址 
         mDownLoad.execute("http://www.baidu.com/img/bdlogo.gif");
    } 
} 

AsyncTask使用的时候需要注意的事项

  • AsyncTask类必须在UI线程中加载。这个在Android 4.1 上是自动完成。
  • 必须在UI线程中实例化。
  • execute(Params…)必须在UI线程中调用。
  • 不能手动调用 onPreExecute(), onPostExecute(Result),
    doInBackground(Params…), onProgressUpdate(Progress…)。
  • 任务只能被执行一次(第二次执行会抛出异常)。

AsyncTask的doInBackground方法默认是返回 true ,表示任务完成,如果想返回具体的数据呢,怎么做。如果Activity被销毁了,还会执行到postexcutd方法吗?
如果需要返回具体的数据,在创建子类继承AsyncTask时,指定泛型的时候将第三个泛型值指定为需要返回具体数据的类型,然后在doInBackground任务完成时,return具体的数据即可。

AsyncTask会一直执行, 直到doInBackground()方法执行完毕。然后,如果 cancel(boolean)被调用, 那么onCancelled(Result result) 方法会被执行;否则,执行onPostExecute(Result result) 方法。如果我们的Activity销毁之前,没有取消 AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。因为它想要处理的view已经不存在了。所以,我们总是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确地取消。另外,即使我们正确地调用了cancle() 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • Android Handler机制系列文章整体内容如下: Android Handler机制1之ThreadAnd...
    隔壁老李头阅读 3,193评论 1 15
  • 在Android中我们可以通过Thread+Handler实现多线程通信,一种经典的使用场景是:在新线程中进行耗时...
    吕侯爷阅读 2,044评论 2 23
  • Android开发者:你真的会用AsyncTask吗? 导读.1 在Android应用开发中,我们需要时刻注意保证...
    cxm11阅读 2,703评论 0 29
  • 文章简介AsyncTask 是Android 开发一个常用的多线程异步任务组件。网上资料很多也很杂,所以我决定整理...
    chen_yip阅读 13,390评论 0 14
  • 下载简书也挺久了,一直没发过什么文章,不知道该从哪说起,觉得也该说说自己了,不求有人去看,晚上睡前从认识她那天开始吧!
    曹瑞旭阅读 205评论 0 0