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的使用方法和與伺服器間進行互動完成了。有不明白的,可以留言。