Retrofit2快速入门使用及文件上传(单上传、多上传)

前言

Retrofit2快速入门使用及文件上传(单上传、多上传)_第1张图片

在开发项目中经常会遇到上传头像的问题,那我们如果使用Retrofit做网络请求时,如何进行使用,在文章的最后有最清晰的使用方法

Retrofit可以认为是Okhttp的 “升级版”,为什么这么说?那是因为其内部默认是基于OkHttp来进行封装的,它们属于同一家公司Square


介绍

Retrofit2快速入门使用及文件上传(单上传、多上传)_第2张图片

常用的网络请求方法

@GET

 使用@Query单个参数   @QueryMap多个参数

@POST

使用@Field 单个参数   @FieldMap 多个参数   @Part 上传文件 @PartMap 上传多个文件

总体使用步骤:

1.添加Retrofit依赖库
2.创建接受服务器返回数据的类
3.创建用于描述网络请求的接口
4.创建Rerofit实例
5.创建网络请求接口实例
6.发送网络请求(异步和同步)
7.处理返回数据 
8.进阶理解从复杂到精简的过程
9.上传文件使用

使用

当你想要做任何网络请求的操作时,一定要提前首先加上网络权限,这是很多新手容易忘记的通病,以前我也老忘哈哈。。。。。

下面来看具体使用方法:

1.导入依赖包

    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.google.code.gson:gson:2.2.4'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'

2.创建Bean类

http://v.juhe.cn/toutiao/index?key=d05b58fa6901ad9bed77a1ef08bd6ccb 为了方便给你们提供了一下url地址,仅供学习使用

用gson 快捷方式,生成一个数据类,这个大家都会把,如果不会的话百度搜gosn 插件即可

3.创建存放网络请求的接口

//{name}是一个替换块,搭配@Path("name")动态传参数 
public interface PostService{
  @GET("{name}/index?key=d05b58fa6901ad9bed77a1ef08bd6ccb")
  Call getString(@Path("name") String name);
}

4..创建并初始化Retrofit实例

       Retrofit retrofit = new Retrofit.Builder()
               .baseUrl("http://v.juhe.cn/")//设置网络请求的Url地址
               .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
               .build();

5.连接网络请求接口调用其方法

GetService service = retrofit.create(GetService.class);
Call call = service.getString3("toutiao");

6.同步和异步请求方式

//同步操作,必须开启子线程
     new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response execute = call.execute();
                    GetBean bean = execute.body();
                    Message msg=hand.obtainMessage();
                    msg.obj=bean.toString();
                    msg.what=102;
                    hand.sendMessage(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
//异步操作
  call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                GetBean bean = response.body();
                Log.e("zhoukang", "" + bean.toString());
            }
            @Override
            public void onFailure(Call call, Throwable t) {
            }
        });

7.处理返回数据

 Handler hand=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //TODO 处理逻辑
        }
    };

8.进阶理解从复杂到精简的过程

  • GET 请求方式
 //直接拼接,记得加问号
    @GET("toutiao/index?type=shehui&key=d05b58fa6901ad9bed77a1ef08bd6ccb")
    Call getString();

 //{name}可以最简单的将其理解为路径替换块,用”{}”表示,与注解@path配合使用 ,为了解耦,参数name==toutiao
    @GET("{name}/index?type=shehui&key=d05b58fa6901ad9bed77a1ef08bd6ccb")
    Call getString2(@Path("name") String name);

 //对于@GET来说,参数信息是可以直接放在url中上传的。那么你马上就反应过来了,这一样也存在严重的耦合!
 //于是,就有了@query
    @GET("{name}/index")
    Call getString3(@Path("name")String name,@Query("type") String type 
    ,@Query("key") String key);

 //假设我要在参数中上传10个参数呢?这意味着我要在方法中声明10个@Query参数?当然不是!
    //Retrofit也考虑到了这点,所以针对于复杂的参数上传,为我们准备了@QueryMap
    @GET("{name}/index")
    Call getString4(@Path("name") String name, @QueryMap HashMap hashMap);
  • Post方式
    //注意:千万别忘了标记 @FormUrlEncoded
    @FormUrlEncoded
    @POST("toutiao/index")
    Call postString(@Field("type") String type, @Field("key") String key);

   // Post表单提交-多个参数-@FieldMa
    @FormUrlEncoded
    @POST("toutiao/index")
    Call postString2(@FieldMap HashMap params);
  • MainActivity文件
/**
 *   https://blog.csdn.net/carson_ho/article/details/73732076
 */
public class MainActivity extends AppCompatActivity {

    private TextView mTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv = findViewById(R.id.tv);
        //        initGet();
        try {
            initPost();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    private void initPost() throws UnsupportedEncodingException {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://v.juhe.cn/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        PostService service = retrofit.create(PostService.class);
        //解决中文乱码,服务器后台不认识造成数据为响应
        String name = URLEncoder.encode("社会", "UTF-8");
        HashMap map = new HashMap<>();
        map.put("type", name);
        map.put("key", "d05b58fa6901ad9bed77a1ef08bd6ccb");
        Call call = service.postString2(map);

        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                if (response.isSuccessful()) {
                    PostBean bean = response.body();
                    Message msg = hand.obtainMessage();
                    msg.obj = bean.toString();
                    msg.what = 102;
                    hand.sendMessage(msg);
                    Log.e("zhoukang", "" + bean.toString());
                }
            }
            @Override
            public void onFailure(Call call, Throwable t) {
                Log.e("zhoukang", "R1++ 失败" + t.getMessage());
            }
        });


    }


    private void initGet() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://v.juhe.cn/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        GetService service = retrofit.create(GetService.class);
        final Call call = service.getString3("toutiao", "shehui", "d05b58fa6901ad9bed77a1ef08bd6ccb");
        //异步请求操作
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response execute = call.execute();
                    GetBean bean = execute.body();
                    Message msg = hand.obtainMessage();
                    msg.obj = bean.toString();
                    msg.what = 102;
                    hand.sendMessage(msg);
                    Log.e("zhoukang", "" + bean.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    Handler hand = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //TODO 处理逻辑
            if (msg.what == 102) {
                String result = (String) msg.obj;
                mTv.setText(result);
            }
        }
    };

}

9.图片文件上传

无聊自己写了一个工具类,可以进行扩展使用

public class RetrofitHelper {

    Retrofit retrofit = null;
    String   BASEURL  = "接口地址";
    private final PostService mService;
    public static RetrofitHelper retrofitHelper = new RetrofitHelper();

    private RetrofitHelper() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASEURL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        //通过retrofit类去把我们的网络请求service实例化出来
        mService = retrofit.create(PostService.class);
    }


    public static RetrofitHelper getInstance() {
        return retrofitHelper;
    }

        //提供一些方法去调用service实体类的方法,RequestBody上传单个文件
    public void uploadFile(RequestBody body, final OnSuccessListener listener) {
        Call call = mService.postFile(body, "");
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                listener.onSuccess(response);
            }

            @Override
            public void onFailure(Call call, Throwable t) {
                listener.onFaile();
            }
        });
    }

    //提供一些方法去调用service实体类的方法,HashMap上传多个文件
    public void uploadFile2(HashMap map, final OnSuccessListener listener) {
        Call call = mService.postFile2(map, "");
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                listener.onSuccess(response);
            }

            @Override
            public void onFailure(Call call, Throwable t) {
                listener.onFaile();
            }
        });
    }
    //当我获取数据成功后要做什么处理
    public interface OnSuccessListener {
        void onSuccess(Object o);

        void onFaile();
    }
}

MainAtivity.java

    /**
     * 单张图片上传
     *
     * @throws IOException
     */
    private void initUpateBitmap() {

        //获取图片路径,这只是个简单的例子,项目开发中会有很多图片需要上传,一般从相册和相机里获取,并且保存到后台服务器时必须自己定义名字
        // ,这样就不会发生图片替换(原因名字重复)
        File file = new File(Environment.getExternalStorageDirectory() + "/" + "retrofit/" + "ceshi.jpg");
        RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        RetrofitHelper.getInstance().uploadFile(body, new RetrofitHelper.OnSuccessListener() {
            @Override
            public void onSuccess(Object o) {
                Log.e("", "成功");
            }

            @Override
            public void onFaile() {
                Log.e("", "失败");

            }
        });
    }
 /**
     * 多张图片上传
     */
    private void initUpateBitmap2() {

        //获取图片路径,这只是个简单的例子,项目开发中会有很多图片需要上传,一般从相册和相机里获取,并且保存到后台服务器时必须自己定义名字
        // ,这样就不会发生图片替换(原因名字重复)
        File file = new File(Environment.getExternalStorageDirectory() + "/" + "retrofit/" + "ceshi.jpg");
        File file2 = new File(Environment.getExternalStorageDirectory() + "/" + "retrofit/" + "ceshi2.jpg");
        File file3 = new File(Environment.getExternalStorageDirectory() + "/" + "retrofit/" + "ceshi3.jpg");
        File file4 = new File(Environment.getExternalStorageDirectory() + "/" + "retrofit/" + "ceshi4.jpg");

        RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
        RequestBody requestBody3 = RequestBody.create(MediaType.parse("multipart/form-data"), file3);
        RequestBody requestBody4 = RequestBody.create(MediaType.parse("multipart/form-data"), file4);
        RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        //传一张图片就要增加一个参数
        String name = "photo\"; filename=\"ceshi.jpg\"";
        String name2 = "photo\"; filename=\"ceshi2.jpg\"";
        String name3 = "photo\"; filename=\"ceshi3.jpg\"";
        String name4 = "photo\"; filename=\"ceshi4.jpg\"";
        HashMap map = new HashMap<>();
        map.put(name, requestBody);
        map.put(name2, requestBody2);
        map.put(name3, requestBody3);
        map.put(name4, requestBody4);

        RetrofitHelper.getInstance().uploadFile2(map, new RetrofitHelper.OnSuccessListener() {
            @Override
            public void onSuccess(Object o) {
                Log.e("", "成功");
            }

            @Override
            public void onFaile() {
                Log.e("", "失败");

            }
        });
    }

接口

    //Post文件提交 ,每个键值对都需要用@Part注解键名字
    //Multipart 支持文件上传
    @Multipart
    @POST("拼接参数")

    @Multipart
    @POST("拼接参数")
    Call postFile2(@PartMap HashMap bodyMap, @Field("token") String token);

总结

Retrofit2 的.baseUrl( xxxxxxx / )方法必须以 /(斜线) 结束,
不然会抛出一个IllegalArgumentException,所以如果你看到别的教程没有以 / 结束,
那么多半是直接从Retrofit 1.X 照搬过来的。

这其实都是简单的使用方式,希望你们能看懂,谷歌推荐搭配Rxjava+Rxandroid+gson 去使用,效率快,逻辑也更加简单

Github:https://github.com/github5210zk/Retrofit

你可能感兴趣的:(Android,我不是程序员)