1. 程式人生 > >Android okhttp3來進行網路資料請求和傳送

Android okhttp3來進行網路資料請求和傳送

在開發過程中我們很多地方都要和伺服器進行互動以及請求資料,本篇部落格簡單的介紹下okhttp3。

1.get請求

2.post請求

3.上傳檔案

4.下載檔案

ok,下面我們就要準備下如何封裝使用okhttp3。

在Android studio中我們可以在app---->build.gradle   新增

  compile 'com.squareup.okhttp3:okhttp:3.4.1'(如下圖所示)

這樣我們就把okhttp3所需的jar匯入成功了 下面我們開始進行okhttp3進行get、post封裝。

Get請求

/**
 *  建立OkHttpClient物件
*/ OkHttpClient client = new OkHttpClient(); /** * get請求 */ public String Get(String url) throws IOException { /** * 建立一個Request */ Request request = new Request.Builder() .url(url) .build(); Response response = client.newCall(request).execute(); return response.body().string();
}

以上就是傳送一個get請求的步驟,首先構造一個Request物件,引數最起碼有個url,當然你可以通過Request.Builder設定更多的引數。

然後通過request的物件去構造得到一個Call物件,類似於將你的請求封裝成了任務,既然是任務,就會有execute()cancel()等方法。

最後,我們希望以非同步的方式去執行請求,所以我們呼叫的是call.enqueue,將call加入排程佇列,然後等待任務執行完成,我們在Callback中即可得到結果。

說的再多 也就是封裝使用 使用起來方便快捷。

Post請求

/**
 * post請求
 */
public String Post
(String url, FormBody form) throws IOException { Request request = new Request.Builder() .url(url) .post(form) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); return response.body().string(); }

在進行Post的時候,引數是包含在請求體中的;所以我們通過FormBody。新增多個String鍵值對,然後去構造RequestBody,最後完成我們Request的構造。後面的就和Get一樣。

這裡上傳檔案和下載檔案 無非就是把資料提交到伺服器(後臺介面)、獲取資料並  在這裡沒有必要再進行封裝。下面會有Demo作為解釋說明。 

注意上傳圖片是採用流的形式進行上傳並後臺一般是攜帶引數的 當時在這塊遇到很多坑。下面貼出我封裝的上傳圖片以及攜帶引數。

public static String postString(String url, Map<String, String> params, Map<String, File> files)
        throws IOException {
    String BOUNDARY = java.util.UUID.randomUUID().toString();
String PREFIX = "--", LINEND = "\r\n";
String MULTIPART_FROM_DATA = "multipart/form-data";
String CHARSET = "UTF-8";
URL uri = new URL(url);
HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
conn.setReadTimeout(10 * 1000); // 快取的最長時間
conn.setDoInput(true);// 允許輸入
conn.setDoOutput(true);// 允許輸出
conn.setUseCaches(false); // 不允許使用快取
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("Charsert", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY);
// 首先組拼文字型別的引數
StringBuilder sb = new StringBuilder();
    for (Map.Entry<String, String> entry : params.entrySet()) {
        sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINEND);
sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND);
sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND);
sb.append("Content-Transfer-Encoding: 8bit" + LINEND);
sb.append(LINEND);
sb.append(entry.getValue());
sb.append(LINEND);
}
    DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
outStream.write(sb.toString().getBytes());
// 傳送檔案資料
if (files != null)
        for (Map.Entry<String, File> file : files.entrySet()) {
            StringBuilder sb1 = new StringBuilder();
sb1.append(PREFIX);
sb1.append(BOUNDARY);
sb1.append(LINEND);
sb1.append("Content-Disposition: form-data; name=\"upfile\"; filename=\""
+ file.getValue().getName() + "\"" + LINEND);
sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINEND);
sb1.append(LINEND);
outStream.write(sb1.toString().getBytes());
InputStream is = new FileInputStream(file.getValue());
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
}
            is.close();
outStream.write(LINEND.getBytes());
}
    // 請求結束標誌
byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
outStream.write(end_data);
outStream.flush();
// 得到響應碼
int res = conn.getResponseCode();
InputStream in = conn.getInputStream();
StringBuilder sb2 = new StringBuilder();
    if (res == 200) {
        int ch;
        while ((ch = in.read()) != -1) {
            sb2.append((char) ch);
}
    }
    outStream.close();
conn.disconnect();
    return sb2.toString();
}

  URL是上傳到伺服器所需的介面,

  Params是上傳到伺服器攜帶的引數

  File就是我們的獲取圖片

通過拼接的方式構造請求的資料內容,實現引數之間的傳輸和檔案傳輸

有些知識點是百度的 但很實用,圖片上傳過大,可能會導致上傳失敗,出現一些問題,所以咱們前端還是要進行圖片的壓縮上傳。程式碼如下:
public static File scal(Uri fileUri){
   String path = fileUri.getPath();
File outputFile = new File(path);
   long fileSize = outputFile.length();
   final long fileMaxSize = 200 * 1024;
   if (fileSize >= fileMaxSize) {
      BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
      int height = options.outHeight;
      int width = options.outWidth;
      double scale = Math.sqrt((float) fileSize / fileMaxSize);
options.outHeight = (int) (height / scale);
options.outWidth = (int) (width / scale);
options.inSampleSize = (int) (scale + 0.5);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
outputFile = new File(path);
FileOutputStream fos = null;
      try {
         fos = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);
fos.close();
} catch (IOException e) {
         // TODO Auto-generated catch block
e.printStackTrace();
}
      Log.d("", "sss ok " + outputFile.length());
      if (!bitmap.isRecycled()) {
         bitmap.recycle();
}else{
         File tempFile = outputFile;
outputFile = new File(PhotoUtil.createImageFile().getPath());
PhotoUtil.copyFileUsingFileChannels(tempFile, outputFile);
}

   }
   return outputFile;
}

下面我們講下如何使用我們封裝好的okhttp3進行與伺服器互動

  1 . Get請求使用方法

        final String url="http://app.1nuantong.com/api/app.php?act=systime";
//        請求資料是耗時操作 故放在工作執行緒中
ThreadPool pool=new ThreadPool();
pool.submit(new Runnable() {
            @Override
public void run() {
                try {
                    String  jsonString= OkHttpUtils.getInstance().Get(url);
                    long systime=JSONObject.parseObject(jsonString).getLong("systime");
//                    通過handler 從其它執行緒來操作介面的 有很多方法
//                    比如Activity.runOnUiThread(Runnable)  View.post(Runnable) View.postDelayed(Runnable,long) 看個人喜好
Message message=Message.obtain();
message.what=mEssAge;
message.obj=systime;
//                  Handler(子執行緒呼叫Handler的handle.sendMessage(msg);
mHandler.sendMessage(message);
} catch (IOException e) {
                    e.printStackTrace();
}
            }
        });
}

注意事項:不要阻塞介面執行緒   不要在介面執行緒之外操作介面否則出現未定義的異常,難以進行除錯處理。

在通過handlerMessage得到資料來更新Ui效果

private Handler mHandler=new Handler(){
    @Override
public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case mEssAge:
                long systime= (long) msg.obj;
getTextView.setText(DateUtils.getDateToString(systime*1000));
                break;
}
    }
};

這裡的DateUtils是進行時間戳的轉換。

public class DateUtils {
    /*時間戳轉換成字元竄*/
public static String getDateToString(long time) {
        Date d = new Date(time);
SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日HH時mm分ss秒");
        return sf.format(d);
}
}

Post請求資料

/**
 * Post請求,引數是包含在請求體中的;
 所以我們通過FormBody。新增多個String鍵值對。
 */
final String url="http://app.1nuantong.com/api/app.php";
ThreadPool pool=new ThreadPool();
final FormBody body=new FormBody.Builder()
        .add("act","systime")
        .build();
pool.submit(new Runnable() {
    @Override
public void run() {
        try {
            String  jsonString= OkHttpUtils.getInstance().Post(url,body);
            long systime= JSONObject.parseObject(jsonString).getLong("systime");
Message message=Message.obtain();
message.what=mEssAge;
message.obj=systime;
mHandler.sendMessage(message);
} catch (IOException e) {
            e.printStackTrace();
}
    }
});

效果也是和Get請求一樣 通過HandlerMessage來進行展示效果。

下載檔案

我們這裡下載一個圖片 並儲存到本地上去。如後期需求 可以上傳到伺服器  我們也可以拿到圖片的路徑轉化為流

壓縮上傳。在下載之前我們需要存放圖片的路徑和檔名。如需要上傳伺服器,還可以建立一個File來進行操作檔案

因為下載 需要進行網路訪問(耗時操作)所以避免造成ANR我們開闢一個執行緒來進行資料訪問

private Runnable connectNet = new Runnable(){
        @Override
public void run() {
            try {
                String filePath = ImageUrl;
// 準備拼接新的檔名(儲存在儲存卡後的檔名)
               //  UUID.randomUUID().toString()是javaJDK提供的一個自動生成主鍵的方法
mFileName = UUID.randomUUID().toString() + ".jpg";
//                通過Bitmap decodeStream 解碼獲取圖片
mBitmap = BitmapFactory.decodeStream(getImageStream(filePath));
// 傳送訊息,通知handler在主執行緒中更新UI
connectHanlder.sendEmptyMessage(0);
} catch (Exception e) {
                e.printStackTrace();
}
        }
    };
在這裡我們已經從一個圖片的地址 轉化為bitmap 通過Handler來更新Ui顯示到imageView這個控制元件上面。(非主執行緒不能操作Ui介面)
private Handler connectHanlder = new Handler() {
    @Override
public void handleMessage(Message msg) {
        // 更新UI,顯示圖片
if (mBitmap != null) {
            image.setImageBitmap(mBitmap);
}
    }
};
getImageStream(圖片地址);將圖片地址轉化為流的方法。
 public static InputStream getImageStream(String path) throws Exception{
        // 構造URL
URL url = new URL(path);
// 開啟連線
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//        設定連結超出時間
conn.setConnectTimeout(5 * 1000);
//        設定請求方式
conn.setRequestMethod("GET");
//        得到響應碼與200(HTTP_OK)比對 成功則返回輸入流
if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
            return conn.getInputStream();
}
        return null;
}

接著下面我們將進行下載圖片儲存到本地

public static void saveFile(Bitmap bm, String fileName) throws IOException {
    // 獲得儲存卡路徑,構成 儲存檔案的目標路徑
File dirFile = new File(ALBUM_PATH);
    if(!dirFile.exists()){
        dirFile.mkdir();
}
    File myCaptureFile = new File(ALBUM_PATH + fileName);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
}

這樣下載圖片到本地 我們就完成了。

上傳檔案到伺服器

需要後臺給你一個上傳的介面以及上傳引數


Demo下載地址

http://download.csdn.net/download/sqj199567/9957065

這樣我們就把okhttp的使用方法和與伺服器間進行互動完成了。有不明白的,可以留言。