Retrofit2.0基础使用(一)

关于retrofit也是一个有点老掉牙的话题了,百度各种文章都有,不过本人项目中使用的很少,使用的时候也是简单的copy使用一下,有点尴尬。写此文整理一下实际使用中得一些基本操作,加深一下自己的印象,更方便以后使用的时候借鉴。

本文章基于retrofit2.0+okhttp3,也欢迎看到此文章的朋友,不足之处和有问题的地方可以随便喷~~~哈哈,正所谓不骂不进步嘛!

使用步骤:

一、在根build.gradle中配置


allprojects {
    repositories {
        google()
        jcenter()
        mavenCentral()
        maven { url "https://jitpack.io" }
    }
}

 在主工程可以引用的build.gradle中依赖


        api 'com.google.code.gson:gson:2.2.4'
        api 'com.squareup.okhttp3:okhttp:3.12.1'
        api 'com.squareup.okhttp3:logging-interceptor:3.6.0'
        api 'com.squareup.retrofit2:retrofit:2.4.0'
        api('com.squareup.retrofit2:converter-gson:2.4.0') {
            exclude group: 'com.google.code.gson'
        }

注意:1、retrofit本身和volley类似是一个网路请求框架,默认请求方式使用okhttp,本文使用okhttp3

           2、 api 'com.squareup.okhttp3:logging-interceptor:3.6.0'是打印日志需要的,不需要不集成,一般是要log的!

           3、 { exclude group: 'com.google.code.gson' } 防止冲突,很有必要!

           4、权限配置文件的网络请求权限、6.0版本的动态申请文件读写权限不再啰嗦,自己注意!

 

二、单例的Retrofit和Okhttp管理类



import android.content.Context;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.File;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Function : <br/>
 * Date:      2017-03-10 10:54<br>
 *
 * @author ReiChin_
 */
public class HttpsClientUtil {

    private static final String BASE_API = Constants.API_BASE;

    // timeout for seconds
    private static long TIMEOUT_DEFAULT = 3 * 60L;

    private Context mAppContext;

    private static HttpsClientUtil mInstance = null;

    private HttpsClientUtil() {
    }

    public static HttpsClientUtil newInstance() {
        if (null == mInstance) {
            synchronized (HttpsClientUtil.class) {
                if (null == mInstance) {
                    mInstance = new HttpsClientUtil();
                }
            }
        }
        return mInstance;
    }

    public void init(Context appContext) {
        this.mAppContext = appContext;
    }

    /**
     * 通过默认的OkHttpClient构建Retrofit实例
     *
     * @return
     */
    public Retrofit buildRetrofit() {
        OkHttpClient okHttpClient = buildOkHttpClient();
        return buildRetrofit(okHttpClient);
    }

    /**
     * 通过自定义的OkHttpClient构建Retrofit实例
     *
     * @param okHttpClient
     * @return
     */
    public Retrofit buildRetrofit(OkHttpClient okHttpClient) {
        Gson gson = new GsonBuilder()
//                .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                .setDateFormat("yyyy-MM-dd")
                .create();

        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(okHttpClient)
                .baseUrl(BASE_API)
                .build();
        return retrofit;
    }

    /**
     * 构建一个Https请求的OkHttpClient实例
     *
     * @return
     */
    public OkHttpClient buildOkHttpClient()/* throws CertificateException,
            NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException */ {
        if (null == mAppContext) {
            throw new NullPointerException("Context 没有初始化");
        }

//        SSLParser.SSLParams sslParams = SSLParser.getSSLParams(mAppContext);

        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .addNetworkInterceptor(httpLoggingInterceptor)
                .connectTimeout(TIMEOUT_DEFAULT, TimeUnit.SECONDS)
                .readTimeout(TIMEOUT_DEFAULT, TimeUnit.SECONDS)
                .writeTimeout(TIMEOUT_DEFAULT, TimeUnit.SECONDS)
                .addInterceptor(new HeaderInterceptor())  //添加header

//                .retryOnConnectionFailure(true)  //失败重连
//                .addInterceptor(new NetCacheInterceptor());  //添加网络缓存

//                .sslSocketFactory(sslParams.sslSocketFactory, sslParams.trustManager)
                /*  .hostnameVerifier(new HostnameVerifier() {
                      @Override
                      public boolean verify(String hostname, SSLSession session) {
                          return true;
                      }
                  })*/;

//        addLogIntercepter(builder);  //日志拦截器
//        setCacheFile(builder);//网络缓存

        OkHttpClient okHttpClient = builder.build();
        return okHttpClient;
    }

    /**
     * 设置缓存文件路径
     */
    private void setCacheFile(OkHttpClient.Builder builder) {
        //设置缓存文件
        File cacheFile = new File(FileHelper.LOG_PATH);
        //缓存大小为10M
        int cacheSize = 10 * 1024 * 1024;
        Cache cache = new Cache(cacheFile,cacheSize);
        builder.cache(cache);
    }

    /**
     * 调试模式下加入日志拦截器
     * @param builder
     */
    private void addLogIntercepter(OkHttpClient.Builder builder) {
        if (Constants.isDebug) {
            builder.addInterceptor(new LoggingInterceptor());
        }
    }

    /**
     * 获取对应的Service
     * @param service
     * @param <T>
     * @return
     */
    public <T> T create(Class<T> service){
        return buildRetrofit().create(service);
    }


    /**
     *统一添加header的拦截器
     */
    public class HeaderInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request.Builder builder = chain.request().newBuilder();
            builder.addHeader("token", MyApplication.getInstance().getToken());
            return chain.proceed(builder.build());
        }
    }

    /**
     * 网络拦截器进行网络缓存:
     */
    public class NetCacheInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            int onlineCacheTime = 60;

            return response.newBuilder()
                    .header("Cache-Control", "public, max-age="+onlineCacheTime)
                    .removeHeader("Pragma")
                    .build();
        }
    }

    /**
     * Okhttp返回数据日志拦截器
     */
    public class LoggingInterceptor implements Interceptor {
        private final int byteCount = 1024*1024;

        @Override
        public Response intercept(Chain chain) throws IOException {
            //chain里面包含了request和response,按需获取
            Request request = chain.request();
            Response response = chain.proceed(request);

            LogUtils.d(String.format("发送请求  %s",request.url()));

            ResponseBody responseBody = response.peekBody(byteCount);

            LogUtils.d(String.format("接收响应  %s", responseBody.string()));

            return response;
        }
    }
}
  1. https对应的ssl证书代码已注释
  2. GsonConverterFactory可以自行定义,比如下载文件的时候(文末引用文章链接中有)
  3. createRemoteRealService可以定义多个或者不定义

三、创建 Callback的过滤类,为了适应各种网络状态和事件的统一处理,比如处理统一的错误状态、单点登录等等


import android.support.annotation.NonNull;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;


public abstract class NetworkCallback<T> implements Callback<T> {

    @Override
    public void onResponse(@NonNull Call<T> call, @NonNull Response<T> response) {
        int code = response.code();
        if (code >= 200 && code < 300) {
            onSucceed(response.body());
        } else if (code >= 500 && code < 600) {
            onFailed(ExceptionCode.SERVER_ERROR);
        } else {
            onFailed(ExceptionCode.UNKNOWN_ERROR);
        }
    }

    @Override
    public void onFailure(@NonNull Call call, @NonNull Throwable t) {
        int code = ExceptionCode.UNKNOWN_ERROR;
        if (t instanceof IOException) {
            code = ExceptionCode.NETWORK_ERROR;
        }
        onFailed(code);
    }

    public abstract void onSucceed(T response);

    public abstract void onFailed(int errorCode);

}

   其中错误状态使用接口(或者枚举类型更显得有学问,,,)统一定义


public interface ExceptionCode {

    int NETWORK_ERROR = 1;

    int SERVER_ERROR = 2;

    int UNKNOWN_ERROR = 3;

}

 

四、请求声明



import java.util.Map;

import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.PartMap;
import retrofit2.http.Query;
import retrofit2.http.Url;


public interface RemoteRealService {

    /**
     * 登录
     * @param username
     * @param password
     * @param clientType
     * @return
     */
    @POST("login")
    Call<BobyBean<UserBean>> login(@Query("username") String username, @Query("password") String password, @Query("clientType") String clientType);

    /**
     * 单个文件上传
     * @param tableName
     * @param file
     * @return
     */
    @Multipart
    @POST("fjwj/fileUpload")
    Call<BobyBean<FileBean>> fjwj_fileUpload_only_retrofit(@Part("tableName") RequestBody tableName, @Part MultipartBody.Part file);

    /**
     * 多文件上传
     * @param tableName
     * @param params
     * @return
     */
    @Multipart
    @POST("fjwj/fileUpload")
    Call<BobyBean<FileBean>> fjwj_fileUpload_retrofit(@Part("tableName") RequestBody tableName, @PartMap Map<String, RequestBody> params);

    /**
     * 文件下载 
     * @param url
     * @return
     */
    @GET
    Call<ResponseBody> loadFile(@Url String url);
}
  1. 请求声明举例典型类型,各种参数标识不一一列举,可以需要的时候再百度或者意会-----程序猿的意会是件好事情
  2. post和get传递参数有很多类似的地方,快速开发可能只用一个post类型就可以了,其他get、delelte、put基本不用的,你懂得
  3. 单文件上传和多文件上传、文件下载还是必须要知道的呀
  4. 里面的bean类,请自行脑补,根据实际情况自己定义
  5. 更多请求方式和参数,参考博客: https://blog.csdn.net/guohaosir/article/details/78942485

五、请求实体类


import android.content.Context;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

/**
 * @author hahaliu
 * @Description 所有接口统一
 */
public class Http implements IRemoteService {



    /**
     * 登录
     *
     * @param activity
     * @param account
     * @param pwd
     * @param callback
     */
    public static void doLogin(String username, String password, NetworkCallback<BobyBean<UserBean>> callback) {
        RemoteRealService momentRealService = HttpsClientUtil.newInstance().create(RemoteRealService.class);
        Call<BobyBean<UserBean>> call = momentRealService.login(username, password, "app");
        call.enqueue(callback);
    }



    /**
     * 单文件上传  retrofit
     * @param tableName
     * @param file
     * @param callback

        注意:
 MultipartBody.Part.createFormData("file", file.getName(), photoRequestBody);的file是根据后台参数定义的
     */
    public static void fjwj_fileUpload_only_retrofit(String tableName, File file, NetworkCallback<BobyBean<FileBean>> callback) {
        RemoteRealService service = HttpsClientUtil.newInstance().create(RemoteRealService.class);

        RequestBody tableBoay = RequestBody.create(MediaType.parse("text/plain"), tableName);

        RequestBody photoRequestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
        MultipartBody.Part photo = MultipartBody.Part.createFormData("file", file.getName(), photoRequestBody);

        Call<BobyBean<FileBean>> call = service.fjwj_fileUpload_only_retrofit(tableBoay, photo);
        call.enqueue(callback);
    }



    /**
     * 多文件统一上传 retrofit
     * @param tableName
     * @param files
     * @param callback
        注意:
 params.put("file\"; filename=\"" + file.getName(), photoRequestBody);中得file是根据后台定义的
     */
    public static void fjwj_fileUpload_retrofit(String tableName, List<File> files, NetworkCallback<BobyBean<FileBean>> callback) {
        RemoteRealService service = HttpsClientUtil.newInstance().create(RemoteRealService.class);

        RequestBody tableBoay = RequestBody.create(MediaType.parse("text/plain"), tableName);

        Map<String, RequestBody> params = new HashMap<>();
        for (File file : files) {
            RequestBody photoRequestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
            params.put("file\"; filename=\"" + file.getName(), photoRequestBody);

        }
        Call<BobyBean<FileBean>> call = service.fjwj_fileUpload_retrofit(tableBoay, params);
        call.enqueue(callback);
    }



    /**
     * 文件下载 
     * @param context
     * @param url 
     * @param fileDes  文件夹存储的命名
     * @param position  回调状态--本方法中为文件列表的下表
     * @param listener  自定义的回调监听 方法onItemClickListener的两个int类型参数 type事件类型 position回调状态

注意:
AppConfig.getAppCacheFilePath自定义文件应用缓存路径 的公共方法
 AppConfig.openFile自定义使用手机自带应用打开文件的 公共方法
     */
    public static void loadFile(final Context context, String url, final String fileDes, final int position, final BaseRecyclerBottomSpaceAdapter.OnItemCommonClickListener listener) {
        RemoteRealService service = HttpsClientUtil.newInstance().create(RemoteRealService.class);
        Call<ResponseBody> call = service.loadFile(url);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful()) {
                    boolean writeToDisk = Http.writeFileToSDCard(context, fileDes, response.body());
                    if (writeToDisk) {
                        AppConfig.openFile(context, new File(AppConfig.getAppCacheFilePath(context), fileDes));
                        listener.onItemClickListener(1, position);
                    } else {
                        listener.onItemClickListener(-1, -1);
                    }
                } else {
                    listener.onItemClickListener(-1, -1);
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                listener.onItemClickListener(-1, -1);
            }
        });
    }



    /**
     * 下载文件
     * @param context
     * @param fileDes 文件路径
     * @param body
     * @return
     */
    private static boolean writeFileToSDCard(Context context, String fileDes, ResponseBody body) {
        try {
            File futureStudioIconFile = new File(AppConfig.getAppCacheFilePath(context), fileDes);
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                byte[] fileReader = new byte[4096];
                long fileSize = body.contentLength();
                long fileSizeDownloaded = 0;
                inputStream = body.byteStream();
                outputStream = new FileOutputStream(futureStudioIconFile);
                while (true) {
                    int read = inputStream.read(fileReader);
                    if (read == -1) {
                        break;
                    }
                    outputStream.write(fileReader, 0, read);
                    fileSizeDownloaded += read;
                    Log.d("", "file download: " + fileSizeDownloaded + " of " + fileSize);
                }
                outputStream.flush();
                return true;
            } catch (IOException e) {
                return false;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            return false;
        }
    }

}

基本上大工高成,可以满足基本快速开发使用了,,,,优化的话,请各位多多指教

 

另外附录问件路径和打开文件公共方法


public final class AppConfig {


    /**
     * 应用缓存路径 文件
     */
    public static String getAppCacheFilePath(Context context) {
        File filePath = new File(context.getApplicationContext().getExternalCacheDir().getPath() + File.separator + "file" + File.separator);
        if (!filePath.exists()) {
            filePath.mkdirs();
        }
        return filePath.getPath();
    }


    /**
     * 打开文件
     *
     * @param context
     * @param f

        注意:FileProvider适配不再详述,不理解的可以使用https://github.com/hongyangAndroid/FitAndroid7 文件权限框架
     */
    public static void openFile(Context context, File f) {
        try {
            Intent myIntent = new Intent(Intent.ACTION_VIEW);
            Uri fileUri = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //区别于 FLAG_GRANT_READ_URI_PERMISSION 跟 FLAG_GRANT_WRITE_URI_PERMISSION, URI权限会持久存在即使重启,直到明确的用 revokeUriPermission(Uri, int) 撤销。 这个flag只提供可能持久授权。但是接收的应用必须调用ContentResolver的takePersistableUriPermission(Uri, int)方法实现
                myIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
                fileUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".FileProvider", f);
            } else {
                fileUri = Uri.fromFile(f);
            }
            String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(fileUri.toString());
            String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            LogUtils.e("extension--->" + extension + "  mimetype--->" + mimetype);
            myIntent.setDataAndType(fileUri, mimetype);
            myIntent.addCategory(Intent.CATEGORY_DEFAULT);
            myIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(myIntent);
        } catch (Exception e) {
            ToastUtils.showToast(context, e.toString());
            Toast.makeText(context, "手机没有支持打开此文件的应用!", Toast.LENGTH_SHORT).show();
        }
    }

}

 

最后谢谢几个同事的代码,做了很多参考

参考文章地址

https://blog.csdn.net/qq_34161388/article/details/78403171

https://www.jianshu.com/p/251b91efb6c9

https://mp.weixin.qq.com/s/-PWoVxd8SSvJzRPQ8mpktA

参数详解:https://blog.csdn.net/xieluoxixi/article/details/80092582

                 https://blog.csdn.net/guohaosir/article/details/78942485

文件下载做的比较粗糙,上面链接还说明了大文件下载注意事项,如果GsonConverterFactory转换器进行配置下载文件可能更显得高大上,参考以下文章

https://blog.csdn.net/xinlangren88/article/details/79561504

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Android 中使用 Retrofit 上传图片可以通过 `@Multipart` 和 `@Part` 注解实现。以下是 Retrofit 2.0 实现图文上传的方法总结: 1. 添加依赖库 在项目的 `build.gradle` 文件中添加以下依赖库: ```groovy implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' ``` 2. 创建 Retrofit 实例 ```java Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); ``` 3. 创建 API 接口 ```java public interface ApiService { @Multipart @POST("upload") Call<ResponseBody> upload( @Part("description") RequestBody description, @Part MultipartBody.Part file); } ``` 其中,`@Multipart` 注解表示这是一个包含文本和文件的表单;`@POST("upload")` 表示上传的 URL 地址;`@Part("description") RequestBody description` 表示上传的文本参数,`description` 是参数名,可以自己定义;`@Part MultipartBody.Part file` 表示上传的文件参数。 4. 创建请求参数 ```java File file = new File(filePath); RequestBody requestFile = RequestBody.create(MediaType.parse("image/*"), file); MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile); RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), "description"); ``` 5. 发送网络请求 ```java ApiService apiService = retrofit.create(ApiService.class); Call<ResponseBody> call = apiService.upload(description, body); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { // 成功上传后的处理 } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { // 上传失败后的处理 } }); ``` 以上就是 Retrofit 2.0 实现图文上传的方法总结。注意,在 `AndroidManifest.xml` 文件中需要添加网络权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值