Android开发学习(网络编程和多媒体)

网络编程

安卓网路编程-http协议

https://www.sunofbeach.net/a/1197731399965200384

网络配置

https://developer.android.google.cn/training/articles/security-config?hl=zh-cn#manifest

一.URL使用Http的方式

示例:

package com.atian;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void loadJson(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL("http://10.0.2.2:9102/get/text");
                    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                    //设置请求头的参数
                    connection.setConnectTimeout(10000);
                    connection.setRequestMethod("GET");
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
                    connection.setRequestProperty("Accept","*/*");
                    connection.connect();

                    int responseCode = connection.getResponseCode();
                    if(responseCode == 200){
                        Log.d(TAG, "loadJson: 请求成功!!");
                        //获取到响应头的参数
                        Map<String, List<String>> headerFields = connection.getHeaderFields();
                        Set<Map.Entry<String, List<String>>> entries = headerFields.entrySet();
                        for (Map.Entry<String,List<String>> entry : entries) {
                            Log.d(TAG, entry.getKey()+"==="+entry.getValue());
                        }
                        //读取到返回的信息
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String s = bufferedReader.readLine();
                        Log.d(TAG, "读出的信息为: "+s);
                    }

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

    }
}

1.Gson的使用

//读取到返回的信息
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
Log.d(TAG, "读出的信息为: "+s);
Gson gson = new Gson();
GetTextItem getTextItem = gson.fromJson(s, GetTextItem.class);
Log.d(TAG, "getTextItem: "+getTextItem.toString());

2.异步更新ui(runOnUiThread)

 private void initView() {
        result_list = (RecyclerView)this.findViewById(R.id.result_list);
        result_list.setLayoutManager(new LinearLayoutManager(this));
        this.resultAdapter = new ResultAdapter();
        result_list.setAdapter(this.resultAdapter);
    }
------------------------------------------------------------------------
private void updateUI(GetTextItem getTextItem) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                resultAdapter.setData(getTextItem);
            }
        });

    }
-----------------------------------------------------------------------
public void setData(GetTextItem getTextItem) {
        mData.clear();
        mData.addAll(getTextItem.getData());
        //更新ui界面
        notifyDataSetChanged();
    }

二.Glide(图像加载框架)

Glide是一个快速高效的开源媒体管理和图像加载框架,适用于Android,可以包装媒体 解码、内存和磁盘缓存以及资源池化到一个简单易用的界面中。

Glide 支持获取、解码和显示视频静止图像、图像和动画 GIF。Glide包含一个灵活的API 这允许开发人员插入几乎任何网络堆栈。默认情况下,Glide 使用基于自定义的 堆栈,但也包括插入Google的Volley项目或Square的OkHttp库的实用程序库。HttpUrlConnection

Glide的主要重点是使滚动任何类型的图像列表尽可能流畅和快速,但Glide是 对于需要获取、调整大小和显示远程图像的几乎任何情况也有效。

Download

Gradle:

repositories {
  google()
  mavenCentral()
}

dependencies {
  implementation 'com.github.bumptech.glide:glide:4.14.2'
  annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
}

Maven:

<dependency>
  <groupId>com.github.bumptech.glide</groupId>
  <artifactId>glide</artifactId>
  <version>4.14.2</version>
</dependency>
<dependency>
  <groupId>com.github.bumptech.glide</groupId>
  <artifactId>compiler</artifactId>
  <version>4.14.2</version>
  <optional>true</optional>
</dependency>

1.Glide的使用

//找到控件
ImageView image_view = (ImageView)itemView.findViewById(R.id.image_view);
Glide.with(image_view.getContext()).load("http://10.0.2.2:9102"+mData.get(position).getCover()).into(image_view);

mData.get(position).getCover()返回的是 /imgs/12.png

2.处理大图片的操作(计算采样率)

package com.atian;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class ImagesActivity extends AppCompatActivity {

    private static final String TAG = "ImagesActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.activity_images);
    }

    public void loadPic(View view){
        //创建一個options
        BitmapFactory.Options options = new BitmapFactory.Options();
        //设置这個不存进内存
        options.inJustDecodeBounds = true;
        //拿到图片的大小
        BitmapFactory.decodeResource(getResources(),R.mipmap.b13fae0d47bf1c9214b7d1aa5bb80f82,options);
//        int outHeight = options.outHeight;
//        int outWidth = options.outWidth;
//        Log.d(TAG, "outHeight: "+outHeight);
//        Log.d(TAG, "outWidth: "+outWidth);
        //拿到控件尺寸
        ImageView image_pic = this.findViewById(R.id.image_pic);
        int measuredHeight = image_pic.getMeasuredHeight();
        int measuredWidth = image_pic.getMeasuredWidth();
        Log.d(TAG, "measuredHeight: "+measuredHeight);
        Log.d(TAG, "measuredWidth: "+measuredWidth);
        //计算采样率
        options.inSampleSize = calculateInSampleSize(options,measuredWidth,measuredHeight);
        //第二次读取,就需要写进内存了。
        options.inJustDecodeBounds = false;

        Log.d(TAG, "options.inSampleSize: "+options.inSampleSize);
        //获取到计算采样率后的图片资源
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.b13fae0d47bf1c9214b7d1aa5bb80f82, options);
        image_pic.setImageBitmap(bitmap);
        
    }

    public static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {

        //这里其实是获取到默认的高度和宽度,也就是图片的实际高度和宽度
        final int height = options.outHeight;
        final int width = options.outWidth;

        //默认采样率为1,也就是不变嘛。
        int inSampleSize = 1;


        //===============核心算法啦====================
        if (width > maxWidth || height > maxHeight) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) maxHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) maxWidth);
            }

            final float totalPixels = width * height;

            final float maxTotalPixels = maxWidth * maxHeight * 2;

            while (totalPixels / (inSampleSize * inSampleSize) > maxTotalPixels) {
                inSampleSize++;
            }
        }
        //=============核心算法end================
        return inSampleSize;
    }

}

三.基本操作

1.post提交文本内容

package com.atian;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.atian.domain.CommentItem;
import com.google.gson.Gson;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class PostActivity extends AppCompatActivity {


    private static final String TAG = "PostActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_post);
    }

    public void post_message(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                OutputStream outputStream = null;
                InputStream inputStream = null;
                try {
                    URL url = new URL("http://10.0.2.2:9102/post/comment");
                    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                    connection.setRequestMethod("POST");
                    connection.setConnectTimeout(10000);
                    connection.setRequestProperty("Content-Type","application/json");
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
                    connection.setRequestProperty("Accept","*/*");
                    CommentItem commentItem = new CommentItem("1234", "您已经评论了!!");
                    Gson gson = new Gson();
                    String s = gson.toJson(commentItem);
                    byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
                    //获取传输的长度
                    String len = String.valueOf(bytes.length);
                    //设置请求头中带内容长度
                    connection.setRequestProperty("Content-Length",len);
                    //连接
                    connection.connect();
                    //把数据给到服务
                    outputStream = connection.getOutputStream();
                    //写出数据
                    outputStream.write(bytes);
                    //刷出缓存
                    outputStream.flush();

                    //拿结果
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "返回的状态码为: "+responseCode);
                    if(responseCode == 200){
                        inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String out_text = bufferedReader.readLine();
                        Log.d(TAG, "接收到的数据是: "+out_text);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    //关闭资源流
                    if(outputStream != null){
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(inputStream != null){
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }


            }
        }).start();

    }
}

2.url带参数的请求

    public void get_message(View view){
        //组装数据
        HashMap<String, String> params = new HashMap<>();
        params.put("keyword","这是我的关键字!!");
        params.put("page","12");
        params.put("order","0");
        startRequest(params,"GET","/get/param");
    }

    private void startRequest(HashMap<String, String> params, String method, String api) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                //组装参数
                StringBuilder sb = new StringBuilder();
                if(params != null && params.size() > 0){
                    sb.append("?");
                    Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
                    while (iterator.hasNext()){
                        Map.Entry<String, String> next = iterator.next();
                        sb.append(next.getKey());
                        sb.append("=");
                        sb.append(next.getValue());
                        if(iterator.hasNext()){
                            sb.append("&");
                        }
                    }
                    Log.d(TAG, "sb-->: "+sb.toString());
                }
                String params = sb.toString();
                URL url = null;
                if(params!=null&& params.length()>0){
                        url = new URL(BASE_URL+api+params);
                }else{
                        url = new URL(BASE_URL+api);
                }
                Log.d(TAG, "URL-->: "+url.toString());
                //新建连接
                HttpURLConnection connection = null;
                connection = (HttpURLConnection)url.openConnection();
                connection.setRequestMethod(method);
                connection.setConnectTimeout(10000);
                connection.setRequestProperty("Content-Type","application/json");
                connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
                connection.setRequestProperty("Accept","*/*");
                connection.connect();
                Log.d(TAG, "connection.getResponseCode(): "+connection.getResponseCode());
                if(connection.getResponseCode() == 200){
                    InputStream inputStream = connection.getInputStream();
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    String s = bufferedReader.readLine();
                    Log.d(TAG, "输出的结果为:————>: "+s);
                }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

3.单文件上传

换行:sb.append(“\r\n”)

https://www.bilibili.com/video/BV1ua4y1J7VV?p=11&vd_source=c6adc8d97c23aa879ed362864838ee07

4.多文件上传

https://www.bilibili.com/video/BV1ua4y1J7VV?p=12&vd_source=c6adc8d97c23aa879ed362864838ee07

5.文件下载

https://www.bilibili.com/video/BV1ua4y1J7VV?p=13&spm_id_from=pageDriver&vd_source=c6adc8d97c23aa879ed362864838ee07

文件下载的大概流程:

				 FileOutputStream fileOutputStream = null;
                InputStream inputStreams = null;
                try {
                    //从传来的源获取到图片名称
                    String filename = new String("001.jpg");
                    //获取存放图片的文件地址(重要)
                    File externalFilesDir = PostActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
                    //路径不存在则,创建路径。
                    if(!externalFilesDir.exists()){
                        externalFilesDir.mkdirs();
                    }
                    //File.separator相当于”\“
                    File new_file = new File(externalFilesDir + File.separator + filename);
                    //文件不存在,则创建文件。
                    if(!new_file.exists()){
                        new_file.createNewFile();
                    }
                    //获取文件输出流
                    fileOutputStream = new FileOutputStream(new_file);
                    //获取连接输入流
                    inputStreams = connection.getInputStream();
                    //定义缓存数组
                    byte[] buffer = new byte[1024];
                    int len;
                    //读写操作
                    while ((len = inputStreams.read(buffer,0,buffer.length))!=-1){
                        fileOutputStream.write(buffer,0,len);
                    }
                    //刷新缓存区
                    fileOutputStream.flush();

                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(fileOutputStream!=null){
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(inputStreams!=null){
                        try {
                            inputStreams.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

四.OKHTTP框架

https://github.com/square/okhttp
https://www.sunofbeach.net/a/1196018104614813696

1.添加依赖

implementation("com.squareup.okhttp3:okhttp:4.10.0")

2.基本示例代码

package com.atian;

import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class okHttpActivity extends AppCompatActivity {


    public static final String BASE_URL = "http://10.0.2.2:9102";
    private static final String TAG = "okHttpActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.activity_okhttp);
    }

    public void get_message01(View view){
        //要有客户端,就类似于浏览器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                .build();

        //创建请求内容
        final Request request = new Request.Builder()
                .get()
                .url(BASE_URL + "/get/text")
                .build();
        //用client去创建请求任务
        Call task = okHttpClient.newCall(request);
        //异步请求
        task.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                int code = response.code();
                if(code == HttpURLConnection.HTTP_OK){
                    ResponseBody body = response.body();
                    Log.d(TAG, "body: "+body.string());
                }
            }
        });
    }
}

3.post方式提交字符串

public void post_message01(View view){
        //1.要有客户端,就类似于浏览器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                .build();
        //2.创建post提交的内容
        CommentItem commentItem = new CommentItem("1234", "您已经评论了!!");
        Gson gson = new Gson();
        String s = gson.toJson(commentItem);
        MediaType parse = MediaType.parse("application/json");
        RequestBody requestBody = RequestBody.create(s, parse);

        //3.创建请求内容
        final Request request = new Request.Builder()
                .post(requestBody)
                .url(BASE_URL + "/post/comment")
                .build();
        //4.客户端创建任务
        Call call = okHttpClient.newCall(request);

        //5.客户端异步执行任务
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                //如果出错,打印出错误信息!
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                int code = response.code();
                if(code == HttpURLConnection.HTTP_OK){
                    ResponseBody body = response.body();
                    Log.d(TAG, "body: "+body.string());
                }
            }
        });
    }

4.上传单个文件

1.引入相关的权限

静态声明权限
 	<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
动态获取权限
 private void checkPermission() {
        //先判断有没有权限
        int i = checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE");
        if(i != PackageManager.PERMISSION_GRANTED){
            //没有权限
            // 申请权限
            // 定义需要申请的权限数组
            String[] permission = new String[] {
                    Manifest.permission.READ_EXTERNAL_STORAGE
            };
            // 定义这次申请权限的唯一请求编码
            int requestCode = 2023;
            // 申请权限
            requestPermissions(permission, requestCode);
        }
    }


    /**
     * 申请权限的回调方法
     * @param requestCode 申请权限时的请求码
     * @param permissions   所有权限的数组
     * @param grantResults  返回获取权限的状态码数组(-1:获取失败----0:获取成功)
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == 2023){
            Log.d(TAG, "grantResults: "+grantResults[0]);
            Log.d(TAG, "grantResults: "+grantResults.length);
            if(grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                //有权限
                Toast.makeText(this, "已经获得所有权限!", Toast.LENGTH_SHORT).show();
            }else {
                //没有权限
                //根据交互数据
                Toast.makeText(this, "没有获得权限!,程序将退出!", Toast.LENGTH_SHORT).show();
            }
        }
    }

2.编写代码

	public void post_fileOne(View view){
        //新建客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000,TimeUnit.MILLISECONDS)
                .build();
        //新建要传输的文件,指定文件路径
        File file = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
        //定义解析文件类型
        MediaType parse = MediaType.parse("image/png");
        RequestBody fileBody = RequestBody.create(file, parse);
        //新建请求发送文件的body
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("file",file.getName(),fileBody)
                .build();

        //新建请求
        Request request = new Request.Builder()
                .url(BASE_URL+"/file/upload")
                .post(requestBody)
                .build();
        //新建任务
        Call call = okHttpClient.newCall(request);

        //异步执行任务
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                //打印错误信息!
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if(response.code() == HttpURLConnection.HTTP_OK){
                    ResponseBody body = response.body();
                    //打印返回的值
                    Log.d(TAG, "body: "+body.string());
                    // todo 需要动态申请权限
                }
            }
        });
    }

5.上传多个文件

 public void post_files(View view){
        //新建客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000,TimeUnit.MILLISECONDS)
                .build();
        //新建要传输的文件,指定文件路径
        File fileOne = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
        File fileTwo = new File("/storage/emulated/0/Download/75d1968dd23c9c74c2c702b5a5dbf874.jpeg");
        File fileThree = new File("/storage/emulated/0/Download/b9040d67938b047f0493e3c8c0f22ab6.jpeg");
        File fileFour = new File("/storage/emulated/0/Download/f67b5abd3aed142c74f070a60d320c7f.jpeg");
        //定义解析文件类型
        MediaType parse = MediaType.parse("image/png");
        RequestBody fileBodyOne = RequestBody.create(fileOne, parse);
        RequestBody fileBodyTwo = RequestBody.create(fileTwo, parse);
        RequestBody fileBodyThree = RequestBody.create(fileThree, parse);
        RequestBody fileBodyFour = RequestBody.create(fileFour, parse);
        //新建请求发送文件的body
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("files",fileOne.getName(),fileBodyOne)
                .addFormDataPart("files",fileTwo.getName(),fileBodyTwo)
                .addFormDataPart("files",fileThree.getName(),fileBodyThree)
                .addFormDataPart("files",fileFour.getName(),fileBodyFour)
                .build();

        //新建请求
        Request request = new Request.Builder()
                .url(BASE_URL + "/files/upload")
                .post(requestBody)
                .build();
        //新建任务
        Call call = okHttpClient.newCall(request);

        //异步执行任务
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                //打印错误信息!
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if(response.code() == HttpURLConnection.HTTP_OK){
                    ResponseBody body = response.body();
                    //打印返回的值
                    Log.d(TAG, "body: "+body.string());
                    // todo 需要动态申请权限
                }
            }
        });
    }

6.下载文件

 public void post_files(View view){
        //新建客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000,TimeUnit.MILLISECONDS)
                .build();
        //新建要传输的文件,指定文件路径
        File fileOne = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");
        File fileTwo = new File("/storage/emulated/0/Download/75d1968dd23c9c74c2c702b5a5dbf874.jpeg");
        File fileThree = new File("/storage/emulated/0/Download/b9040d67938b047f0493e3c8c0f22ab6.jpeg");
        File fileFour = new File("/storage/emulated/0/Download/f67b5abd3aed142c74f070a60d320c7f.jpeg");
        //定义解析文件类型
        MediaType parse = MediaType.parse("image/png");
        RequestBody fileBodyOne = RequestBody.create(fileOne, parse);
        RequestBody fileBodyTwo = RequestBody.create(fileTwo, parse);
        RequestBody fileBodyThree = RequestBody.create(fileThree, parse);
        RequestBody fileBodyFour = RequestBody.create(fileFour, parse);
        //新建请求发送文件的body
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("files",fileOne.getName(),fileBodyOne)
                .addFormDataPart("files",fileTwo.getName(),fileBodyTwo)
                .addFormDataPart("files",fileThree.getName(),fileBodyThree)
                .addFormDataPart("files",fileFour.getName(),fileBodyFour)
                .build();

        //新建请求
        Request request = new Request.Builder()
                .url(BASE_URL + "/files/upload")
                .post(requestBody)
                .build();
        //新建任务
        Call call = okHttpClient.newCall(request);

        //异步执行任务
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                //打印错误信息!
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if(response.code() == HttpURLConnection.HTTP_OK){
                    ResponseBody body = response.body();
                    //打印返回的值
                    Log.d(TAG, "body: "+body.string());
                    // todo 需要动态申请权限
                }
            }
        });
    }
    public void downFile(View view){
        //新建客户端
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000,TimeUnit.MILLISECONDS)
                .build();
        //新建请求
        Request request = new Request.Builder()
                .get()
                .url(BASE_URL + "/download/2")
                .build();
        //创建任务
        Call call = okHttpClient.newCall(request);
        //异步执行任务
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                FileOutputStream fileOutputStream = null;
                InputStream inputStreams = null;
                int code = response.code();
                try {
                if (code == HttpURLConnection.HTTP_OK) {
                    Iterator<Pair<String, String>> iterator = response.headers().iterator();
                    while (iterator.hasNext()) {
                        Pair<String, String> next = iterator.next();
                        String first = next.getFirst();
                        String second = next.getSecond();
                        Log.d(TAG, "key: " + first + "     value:  " + second);
                    }
                    String disposition = response.header("Content-disposition");
                    String fileName = disposition.replace("attachment; filename=", "");
                    //获取存放图片的文件地址(重要)
                    File externalFilesDir = okHttpActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);

                    //路径不存在则,创建路径。
                    if (!externalFilesDir.exists()) {
                        externalFilesDir.mkdirs();
                    }
                    //File.separator相当于”\“
                    File new_file = new File(externalFilesDir + File.separator + fileName);
                    Log.d(TAG, "new_file: "+new_file);
                    //文件不存在,则创建文件。
                    if (!new_file.exists()) {
                        new_file.createNewFile();
                    }
                    //获取文件输出流
                    fileOutputStream = new FileOutputStream(new_file);
                    //获取连接输入流
                    inputStreams = response.body().byteStream();
                    //定义缓存数组
                    byte[] buffer = new byte[1024];
                    int len;
                    //读写操作
                    while ((len = inputStreams.read(buffer, 0, buffer.length)) != -1) {
                        fileOutputStream.write(buffer, 0, len);
                    }
                    //刷新缓存区
                    fileOutputStream.flush();
                }

                } catch(Exception e){
                    e.printStackTrace();
                }finally{
                    if (fileOutputStream != null) {
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (inputStreams != null) {
                        try {
                            inputStreams.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }
        });
    }

五.Retrofit框架

github地址:https://github.com/square/retrofit
官网地址:https://square.github.io/retrofit/

1.例子

导入框架:

implementation 'com.squareup.retrofit2:retrofit:2.7.0'

创建接口

package com.atian;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;

public interface API {

    @GET("/get/text")
    Call<ResponseBody> getJson();
}

编写代码

 public void getAll(View view){
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://10.0.2.2:9102")
                .build();
        API api = retrofit.create(API.class);
		
        Call<ResponseBody> task = api.getJson();

        task.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                int code = response.code();
                if(code  == 200){
                    ResponseBody body = response.body();
                    try {
                        Log.d(TAG, "body: "+body.string());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.getMessage());
            }
        });

    }

2.请求数据并展示

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:text="get请求"
        android:textAllCaps="false"
        android:onClick="getAll"
        android:layout_height="wrap_content"/>


    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:id="@+id/resultList"
        android:layout_height="wrap_content">

    </androidx.recyclerview.widget.RecyclerView>
</LinearLayout>

MainActivity.java

package com.atian;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.atian.Adapters.ListViewAdapter;
import com.atian.domain.jsonResult;
import com.google.gson.Gson;

import java.io.IOException;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    RecyclerView resultList;
    ListViewAdapter listViewAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkPermission();
        initView();
    }

    private void initView() {
        resultList = this.findViewById(R.id.resultList);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //设置设置布局管理器到进去
        resultList.setLayoutManager(linearLayoutManager);
        //创建适配器,把数据通过构造方法存进去。
        listViewAdapter = new ListViewAdapter();
        //设置适配器到Recycler里头
        resultList.setAdapter(listViewAdapter);

        listViewAdapter.setRecyclerItemClickListener(new ListViewAdapter.OnRecyclerItemClickListener() {
            @Override
            public void onRecyclerItemClick(int position) {
                //这里会返回是哪条的信息,获取到哪条就,可以处理相应的逻辑了。
                //注意这里写逻辑
                Log.d(TAG, "点击了: "+position+"条信息");
            }
        });

    }


    private void checkPermission() {
        //先判断有没有权限
        int i = checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE");
        if(i != PackageManager.PERMISSION_GRANTED){
            //没有权限
            // 申请权限
            // 定义需要申请的权限数组
            String[] permission = new String[] {
                    Manifest.permission.READ_EXTERNAL_STORAGE
            };
            // 定义这次申请权限的唯一请求编码
            int requestCode = 2023;
            // 申请权限
            requestPermissions(permission, requestCode);
        }
    }


    /**
     * 申请权限的回调方法
     * @param requestCode 申请权限时的请求码
     * @param permissions   所有权限的数组
     * @param grantResults  返回获取权限的状态码数组(-1:获取失败----0:获取成功)
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == 2023){
            Log.d(TAG, "grantResults: "+grantResults[0]);
            Log.d(TAG, "grantResults: "+grantResults.length);
            if(grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                //有权限
                Toast.makeText(this, "已经获得所有权限!", Toast.LENGTH_SHORT).show();
            }else {
                //没有权限
                //根据交互数据
                Toast.makeText(this, "没有获得权限!,程序将退出!", Toast.LENGTH_SHORT).show();
            }
        }
    }


    public void getAll(View view){
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://10.0.2.2:9102")
                .build();
        API api = retrofit.create(API.class);

        Call<ResponseBody> task = api.getJson();

        task.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                int code = response.code();
                if(code  == 200){
                    ResponseBody body = response.body();
                    try {
                        String result = body.string();//只能调用一次,相当于是从箱子里拿东西出来,只能拿一次。拿出来之后再调用就拿不到了。
                        Gson gson = new Gson();
                        Log.d(TAG, "result: "+result);
                        jsonResult jsonResult = gson.fromJson(result,com.atian.domain.jsonResult.class);
                        if(jsonResult==null){
                            return;
                        }
                        String s = jsonResult.getData().toString();
                        Log.d(TAG, "s: "+s);
                        //更新界面
                        updateList(jsonResult);


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

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.getMessage());
            }
        });

    }

    private void updateList(jsonResult jsonResult) {
        listViewAdapter.setData(jsonResult);

    }

}

API.java

package com.atian;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;

public interface API {

    @GET("/get/text")
    Call<ResponseBody> getJson();
}

jsonResult.java

package com.atian.domain;


import java.util.List;

public class jsonResult {


    private boolean success;
    private int code;
    private String message;
    private List<DataDTO> data;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public List<DataDTO> getData() {
        return data;
    }

    public void setData(List<DataDTO> data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "jsonResult{" +
                "success=" + success +
                ", code=" + code +
                ", message='" + message + '\'' +
                ", data=" + data +
                '}';
    }

    public static class DataDTO {
        private String id;
        private String title;
        private int viewCount;
        private int commentCount;
        private String publishTime;
        private String userName;
        private String cover;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public int getViewCount() {
            return viewCount;
        }

        public void setViewCount(int viewCount) {
            this.viewCount = viewCount;
        }

        public int getCommentCount() {
            return commentCount;
        }

        public void setCommentCount(int commentCount) {
            this.commentCount = commentCount;
        }

        public String getPublishTime() {
            return publishTime;
        }

        public void setPublishTime(String publishTime) {
            this.publishTime = publishTime;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getCover() {
            return cover;
        }

        public void setCover(String cover) {
            this.cover = cover;
        }

        @Override
        public String toString() {
            return "DataDTO{" +
                    "id='" + id + '\'' +
                    ", title='" + title + '\'' +
                    ", viewCount=" + viewCount +
                    ", commentCount=" + commentCount +
                    ", publishTime='" + publishTime + '\'' +
                    ", userName='" + userName + '\'' +
                    ", cover='" + cover + '\'' +
                    '}';
        }
    }
}

ListViewAdapter.java

package com.atian.Adapters;

import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.atian.R;
import com.atian.domain.jsonResult;
import com.bumptech.glide.Glide;

import java.util.ArrayList;
import java.util.List;

public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.Holder> {

    private List<com.atian.domain.jsonResult.DataDTO> data = new ArrayList<com.atian.domain.jsonResult.DataDTO>();
    @NonNull
    @Override
    public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = View.inflate(parent.getContext(), R.layout.item_json_result, null);

        return new Holder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull Holder holder, int position) {
        //在这里设置数据
        holder.setData(data.get(position));
        //设置条目监听
        holder.setListener(position);
    }

    @Override
    public int getItemCount() {

        return data.size();
    }

    public void setData(jsonResult jsonResult) {
        //先清除掉数组里的元素
        data.clear();
        //设置元素
        data = jsonResult.getData();
        //刷新ui
        notifyDataSetChanged();
    }

    public class Holder extends RecyclerView.ViewHolder{
        ImageView image_name;
        TextView author_name;
        TextView book_name;
        TextView count ;
        public Holder(@NonNull View itemView) {
            super(itemView);
            image_name = (ImageView)itemView.findViewById(R.id.image_name);
            author_name = (TextView)itemView.findViewById(R.id.author_name);
            book_name = (TextView)itemView.findViewById(R.id.book_name);
            count = (TextView)itemView.findViewById(R.id.count);
        }

        public void setData(jsonResult.DataDTO dataDTO) {
            //处理图像的工具
            Glide.with(image_name.getContext()).load("http://10.0.2.2:9102"+dataDTO.getCover()).into(image_name);
            author_name.setText("作者名:"+dataDTO.getUserName());
            book_name.setText("书名:"+dataDTO.getTitle());
            count.setText("访问数:"+dataDTO.getViewCount());
        }

        /**
         * 这个方法用于设置监听事件
         * position 哪个条目
         */
        public void setListener(int position){
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO 这里回调自定义的点击事件
                    if (itemClickListener != null) {
                        // getAdapterPosition()方法已经过时了,建议我们去调用
                        // itemClickListener.onRecyclerItemClick(getAdapterPosition());
                        //----------------------------------------------------------------------------------------------
                        // itemClickListener.onRecyclerItemClick(getAbsoluteAdapterPosition());

                        itemClickListener.onRecyclerItemClick(position);
                    }
                }
            });
        }
    }

    /** 创建自定义监听接口 */
    public interface OnRecyclerItemClickListener {
        void onRecyclerItemClick(int position);
    }

    /** 创建自定义的监听对象 */
    private OnRecyclerItemClickListener itemClickListener;

    /** 这个就是提供给外部进行设置监听对象的 */
    public void setRecyclerItemClickListener(OnRecyclerItemClickListener listener) {
        this.itemClickListener = listener;
    }
}

item_json_result.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:layout_width="80dp"
        android:layout_margin="10dp"
        android:id="@+id/image_name"
        android:src="@mipmap/ic_launcher"
        android:scaleType="centerInside"
        android:layout_height="80dp">
    </ImageView>

    <LinearLayout
        android:layout_width="wrap_content"
        android:orientation="vertical"
        android:layout_marginTop="10dp"
        android:layout_height="wrap_content">
    <TextView
        android:layout_width="match_parent"
        android:text="书名:"
        android:id="@+id/book_name"
        android:textSize="20sp"
        android:ellipsize="end"
        android:lines="1"
        android:layout_height="wrap_content">
    </TextView>
    <TextView
        android:layout_width="match_parent"
        android:text="作者:"
        android:id="@+id/author_name"
        android:textSize="20sp"
        android:layout_height="wrap_content">
    </TextView>
    <TextView
        android:layout_width="match_parent"
        android:text="访问数:"
        android:id="@+id/count"
        android:textSize="20sp"
        android:layout_height="wrap_content">
    </TextView>
    </LinearLayout>
</LinearLayout>

3.转换器(请求回来的信息直接转成bean类)

1.添加相关的依赖
在这里插入图片描述

implementation 'com.squareup.retrofit2:converter-gson:2.7.0'

2.修改接口返回对象

package com.atian;

import com.atian.domain.jsonResult;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;

public interface API {

    @GET("/get/text")
    Call<jsonResult> getJson();
}

3.使用代码
添加.addConverterFactory(GsonConverterFactory.create())
在这里插入图片描述

public void getAll(View view){
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://10.0.2.2:9102")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        API api = retrofit.create(API.class);

        Call<jsonResult> task = api.getJson();

        task.enqueue(new Callback<jsonResult>() {
            @Override
            public void onResponse(Call<jsonResult> call, Response<jsonResult> response) {
                int code = response.code();
                if(code  == 200){
                    jsonResult jsonResult = response.body();
                    updateList(jsonResult);
                }
            }

            @Override
            public void onFailure(Call<jsonResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.getMessage());
            }
        });
    }
新建RetrofitUtil工具类
package com.atian.utils;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitUtil {


    private static Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://10.0.2.2:9102")
            .addConverterFactory(GsonConverterFactory.create())
            .build();


    public static Retrofit getRetrofit(){
        return retrofit;
    }

}

4.–@Query注解

相当于在url路径后拼接参数进行传递

@GET("/get/param")//相当于url路径上拼接了key value的值
Call<GetWithParamsResult> getWithParams(@Query("keyword")String keyword,
                                            @Query("page")int page,
                                            @Query("order")int order);

5.–@QueryMap注解

相当于url路径上拼接了key value的值(使用的是map集合的方法)

@GET("/get/param")//相当于url路径上拼接了key value的值(使用的是map集合的方法)
Call<GetWithParamsResult> getWithParamsMap(@QueryMap HashMap<String,String> params);

使用:

 public void getParamsMap(View view){
        Retrofit retrofit = RetrofitUtil.getRetrofit();
        API api = retrofit.create(API.class);
        HashMap<String, String> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("keyword","你好啊!");
        objectObjectHashMap.put("page","10");
        objectObjectHashMap.put("order","1");
        Call<GetWithParamsResult> call = api.getWithParamsMap(objectObjectHashMap);
        call.enqueue(new Callback<GetWithParamsResult>() {
            @Override
            public void onResponse(Call<GetWithParamsResult> call, Response<GetWithParamsResult> response) {
                int code = response.code();
                if(code == 200){
                    GetWithParamsResult body = response.body();
                    String s = body.toString();
                    Log.d(TAG, "s: "+s);

                }
            }

            @Override
            public void onFailure(Call<GetWithParamsResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.toString());
            }
        });
    }

6.–@Post注解

相当于url路径上拼接了key value的值,post的url上也可以传值。

@POST("/post/string")//相当于url路径上拼接了key value的值
Call<GetWithParamsResult> postWithParams(@Query("string")String string);

7.–@Url注解

可以连请求路径和参数一起传过去

@POST
Call<GetWithParamsResult> postWithUrl(@Url String url);

使用:

public void postWithUrl(View view){
        API api = RetrofitUtil.getRetrofit().create(API.class);
        Call<GetWithParamsResult> call = api.postWithUrl("/post/string?string=内容测试内容");
        call.enqueue(new Callback<GetWithParamsResult>() {
            @Override
            public void onResponse(Call<GetWithParamsResult> call, Response<GetWithParamsResult> response) {
                int code = response.code();
                if(code == HttpsURLConnection.HTTP_OK){
                    GetWithParamsResult body = response.body();
                    Log.d(TAG, "body: "+body.toString());
                }
            }

            @Override
            public void onFailure(Call<GetWithParamsResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.toString());
            }
        });
    }

8.–@Body注解

Body中请求参数(自定义对象)

@POST("/post/comment")
Call<GetWithParamsResult> postWithBody(@Body CommentItem commentItem);

代码:

public void postWithBody(View view){
        API api = RetrofitUtil.getRetrofit().create(API.class);
        CommentItem commentItem = new CommentItem();
        commentItem.setArticleId("12345");
        commentItem.setCommentContent("xasjdkdhas");
        Call<GetWithParamsResult> call = api.postWithBody(commentItem);

        call.enqueue(new Callback<GetWithParamsResult>() {
            @Override
            public void onResponse(Call<GetWithParamsResult> call, Response<GetWithParamsResult> response) {
                int code = response.code();
                if(code == HttpsURLConnection.HTTP_OK){
                    GetWithParamsResult body = response.body();
                    Log.d(TAG, "body: "+body.toString());
                }
            }

            @Override
            public void onFailure(Call<GetWithParamsResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.toString());
            }
        });
    }

9.–@Part注解和@Multipart注解

@Multipart
@POST("/file/upload")//上传单个文件
Call<PostFileResult> postWithUpload(@Part MultipartBody.Part part);

代码:

 public void postWithUpload(View view){

        API api = RetrofitUtil.getRetrofit().create(API.class);

        File file = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");

        RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"),file);

        MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);

        Call<PostFileResult> call = api.postWithUpload(part);

        call.enqueue(new Callback<PostFileResult>() {
            @Override
            public void onResponse(Call<PostFileResult> call, Response<PostFileResult> response) {
                int code = response.code();
                if(code == HttpsURLConnection.HTTP_OK){
                    PostFileResult body = response.body();
                    Log.d(TAG, "body: "+body.toString());
                }
            }

            @Override
            public void onFailure(Call<PostFileResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.toString());
            }
        });
    }

10.–上传多文件

@Multipart
@POST("/files/upload")//上传单个文件
Call<PostFileResult> postWithUploads(@Part List<MultipartBody.Part> parts);

代码:

/**
     * 提取公共方法
     * @param filename
     * @param files
     * @return
     */
    private MultipartBody.Part createPartByPathAndKey(String filename, String files){
        File file = new File(filename);
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"),file);
        MultipartBody.Part part = MultipartBody.Part.createFormData(files, file.getName(), requestBody);
        return part;
    }

    /**
     * 上传多个文件
     * @param view
     */
    public void postWithUploads(View view){
        API api = RetrofitUtil.getRetrofit().create(API.class);
        ArrayList<MultipartBody.Part> parts = new ArrayList<>();
        MultipartBody.Part files0 = createPartByPathAndKey("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg", "files");
        MultipartBody.Part files1 = createPartByPathAndKey("/storage/emulated/0/Download/75d1968dd23c9c74c2c702b5a5dbf874.jpeg", "files");
        MultipartBody.Part files2 = createPartByPathAndKey("/storage/emulated/0/Download/b9040d67938b047f0493e3c8c0f22ab6.jpeg", "files");
        MultipartBody.Part files3 = createPartByPathAndKey("/storage/emulated/0/Download/f67b5abd3aed142c74f070a60d320c7f.jpeg", "files");
        parts.add(files0);
        parts.add(files1);
        parts.add(files2);
        parts.add(files3);
        Call<PostFileResult> postFileResultCall = api.postWithUploads(parts);

        postFileResultCall.enqueue(new Callback<PostFileResult>() {
            @Override
            public void onResponse(Call<PostFileResult> call, Response<PostFileResult> response) {
                int code = response.code();
                if(code == 200){
                    PostFileResult body = response.body();
                    String s = body.toString();
                    Log.d(TAG, "s: "+s);
                }
            }

            @Override
            public void onFailure(Call<PostFileResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.toString());
            }
        });
    }

11.–上传文件并传参

@Multipart
@POST("/file/params/upload")//上传单个文件,并携带参数
Call<PostFileResult> postWithUploadParams(@Part MultipartBody.Part part, @PartMap Map<String,String> map);
 /**
     * 上传文件带参数
     * @param view
     */
    public void postWithUploadParams(View view){
        API api = RetrofitUtil.getRetrofit().create(API.class);
        File file = new File("/storage/emulated/0/Download/3abc27abc474cdd4ebd7b2f3e83d05ef.jpeg");

        RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"),file);

        MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("description","这是一张头像文件");
        hashMap.put("isFree","true");
        Call<PostFileResult> postFileResultCall = api.postWithUploadParams(part, hashMap);

        postFileResultCall.enqueue(new Callback<PostFileResult>() {
            @Override
            public void onResponse(Call<PostFileResult> call, Response<PostFileResult> response) {
                int code = response.code();
                if(code == 200){
                    PostFileResult body = response.body();
                    Log.d(TAG, "body: "+body);
                }
            }
            @Override
            public void onFailure(Call<PostFileResult> call, Throwable t) {
                Log.d(TAG, "onFailure: "+t.toString());
            }
        });
    }

12.–表单提交(@Field和@FieldMap)

@FormUrlEncoded//提交表单
@POST("/login")
Call<loginResult> login(@Field("userName")String username,@Field("password")String password);

代码:

 public void login(View view){
        API api = RetrofitUtil.getRetrofit().create(API.class);
        Call<loginResult> login = api.login("123", "123");
        login.enqueue(new Callback<loginResult>() {
            @Override
            public void onResponse(Call<loginResult> call, Response<loginResult> response) {
                int code = response.code();
                if(code == 200){
                    loginResult body = response.body();
                    Log.d(TAG, "body: "+body);
                }
            }

            @Override
            public void onFailure(Call<loginResult> call, Throwable t) {
                Log.e(TAG, "onFailure: "+t.toString());
            }
        });
    }

13.–文件下载(@Streaming)

@Streaming
@GET
Call<ResponseBody> downFile(@Url String url);

代码:

ailure(Call<ResponseBody> call,Throwable t) {
                    Log.d(TAG,"onFailure -- > " + t.toString());
                }
            });
    }

    /**
     * 文件操作不能在主线程里操作,所以创建了一个新的线程。
     * @param response
     * @param headers
     */
    private void writeFile2Sd(Response<ResponseBody> response, Headers headers) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                String disposition = headers.get("Content-disposition");
                if(disposition != null) {
                    int fileNameIndex = disposition.indexOf("filename=");
                    Log.d(TAG,"fileNameIndex -- > " + fileNameIndex);
                    String fileName = disposition.substring(fileNameIndex + "filename=".length());
                    Log.d(TAG,"fileName -- > " + fileName);
                    File picFilePath = GetParamsActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
                    Log.d(TAG,"picFilePath --> " + picFilePath);
                    File file = new File(picFilePath + File.separator + fileName);
                    Log.d(TAG,"file -- > " + file);
                    FileOutputStream fos = null;
                    try {
                        if(!file.getParentFile().exists()) {
                            file.getParentFile().mkdirs();
                        }
                        if(!file.exists()) {
                            file.createNewFile();
                        }
                        fos = new FileOutputStream(file);
                        InputStream inputStream = response.body().byteStream();
                        byte[] buf = new byte[1024];
                        int len;
                        while((len = inputStream.read(buf,0,buf.length)) != -1) {
                            fos.write(buf,0,len);
                        }
                    } catch(Exception e) {
                        e.printStackTrace();
                    } finally {
                        if(fos != null) {
                            try {
                                fos.close();
                            } catch(IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }).start();
    }

14.–@header注解

	@Multipart
    @POST("/file/upload")
    Call<FileUploadResult> postFile(@Part MultipartBody.Part file,@Header("token") String token);

    @Multipart
    @POST("/files/upload")
    Call<FileUploadResult> postFiles(@Part List<MultipartBody.Part> files,@HeaderMap Map<String,String> headers);

    @Headers({"token:231231","version:1.0","client:android"})
    @Multipart
    @POST("/file/params/upload")
    Call<FileUploadResult> postFileWithParams(@PartMap Map<String,Object> params,@Part MultipartBody.Part file);

想要在用户验证,携带token的话,每个类上加会很麻烦。
Okhttp是支持拦截器的,我们直接在每次请求的时候,在头部加上token就可以了。

private void createRetrofit() {
        //设置一下okHttp的参数
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(CONNECT_TIME_OUT,TimeUnit.MILLISECONDS)
                .addInterceptor(mHeaderInterceptor)
                .build();
        mRetrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)//设置BaseUrl
                .client(okHttpClient)//设置请求的client
                .addConverterFactory(GsonConverterFactory.create())//设置转换器
                .build();
    }

    private Interceptor mHeaderInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request().newBuilder()
                    .addHeader("token","204391jawslejqowejqwi")
                    .addHeader("version","1.2.0")
                    .addHeader("client","android铂金版")
                    .build();
            return chain.proceed(request);
        }
    };

注解里写的可以覆盖拦截器的内容。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值