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的使用方法和与服务器间进行交互完成了。有不明白的,可以留言。




猜你喜欢

转载自blog.csdn.net/sqj199567/article/details/75695926
今日推荐