在开发过程中我们很多地方都要和服务器进行交互以及请求数据,本篇博客简单的介绍下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的使用方法和与服务器间进行交互完成了。有不明白的,可以留言。