欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Retrofit的简单实用(get post 下载文件)

程序员文章站 2022-07-12 18:52:53
...

       最近工作用到 Retrofit,以前的知识有些忘记了,又去网上查,觉得挺麻烦的,就自己写篇博客记录一下,方便自己以后查看。这里主要写Retrofit的使用。

 Retrofit的使用步骤。
 1.添加Retrofit库的依赖和网络权限:
        compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit库
        compile 'com.squareup.retrofit2:converter-gson:2.3.0'
        <uses-permission android:name="android.permission.INTERNET" />

 2.创建 用于描述网络请求 的接口
         Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数

 3.创建Retrofit实例(这里可以设置回调代码运行的线程,默认回调代码运行在主线程,可以自己设置运行在主线程或者子线程。)

 4.将服务器返回的数据封装成一个bean类,用于接收服务器返回的数据。

 5.发送请求
 请求分为同步请求和异步请求

主要就分为这几部,下面来具体介绍:

1.添加Retrofit库的依赖和网络权限(只需要网络权限,本文中用到了本地存储下载的文件,所以加的存储读写权限):

    compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit库
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'//返回的数据是json的,用到了gson解析

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2.创建 用于描述网络请求 的接口,Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
import retrofit2.http.Streaming;
import retrofit2.http.Url;
/**
 *   创建 用于描述网络请求 的接口
 *   Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数
 */
public interface ApiService {
    //测试 get
    @GET("ajax.php?a=fy&f=auto&t=auto&w=hello")
    Call<ResponseInfo> testGet();

    //测试 post
    @POST("ajax.php?a=fy&f=auto&t=auto")
    Call<ResponseInfo> testPost(@Query("w") String w);

    //测试 下载文件
    @Streaming
    @GET
    Call<ResponseBody> testDownload(@Url String fileUrl);
    
}

3.创建Retrofit实例(这里可以设置回调代码运行的线程,默认回调代码运行在主线程,可以自己设置运行在主线程或者子线程。)

get 请求和 post请求 创建的 Retrofit实例(不指定回调运行的线程,默认运行在主线程)

// 创建Retrofit实例时需要通过Retrofit.Builder,并调用baseUrl方法设置URL。
//Retrofit2的baseUlr 必须以 /(斜线)结束,不然会抛出一个IllegalArgumentException
        retrofit = new Retrofit.Builder()
                .baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
                .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                .build();

文件下载 的 Retrofit 实例  (指定回调运行的线程,指定运行在子线程中,因为受到文件之后要做io流的操作)

 Retrofit retrofitLoaddown = new Retrofit.Builder()
                .baseUrl("http://imtt.dd.qq.com/")
                //通过线程池获取一个线程,指定callback在子线程中运行。
                .callbackExecutor(Executors.newSingleThreadExecutor())
                .build();
4.将服务器返回的数据封装成一个bean类,用于接收服务器返回的数据。
/**
 * 讲服务器返回的数据封装成一个bean类
 */
public class ResponseInfo {
    public Content content;
    public int status;

    public ResponseInfo() {

    }

    public ResponseInfo(Content content, int status) {
        this.content = content;
        this.status = status;
    }

    @Override
    public String toString() {
        return "ResponseInfo{" +
                "content=" + content +
                ", status=" + status +
                '}';
    }

    class Content {
        public String ph_am;
        public String ph_am_mp3;
        public String ph_en_mp3;
        public String ph_tts_mp3;
        public List<String> word_mean;

        public Content() {
        }

        public Content(String ph_am, String ph_am_mp3, String ph_en_mp3, String ph_tts_mp3, List<String> word_mean) {
            this.ph_am = ph_am;
            this.ph_am_mp3 = ph_am_mp3;
            this.ph_en_mp3 = ph_en_mp3;
            this.ph_tts_mp3 = ph_tts_mp3;
            this.word_mean = word_mean;
        }

        @Override
        public String toString() {
            return "Content{" +
                    "ph_am='" + ph_am + '\'' +
                    ", ph_am_mp3='" + ph_am_mp3 + '\'' +
                    ", ph_en_mp3='" + ph_en_mp3 + '\'' +
                    ", ph_tts_mp3='" + ph_tts_mp3 + '\'' +
                    ", word_mean=" + word_mean +
                    '}';
        }
    }
    
}

5.发送请求 。请求分为同步请求和异步请求

          同步请求的代码

 ApiService request = retrofit.create(ApiService.class);
        Call<ResponseInfo> call = request.testGet();// 封装请求
        try {
            Response<ResponseInfo> execute = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

       同步请求比较简单,我这里主要讲异步请求。

              下面分别是get请求post请求和下载文件的代码

 public void testGet() {
        ApiService request = retrofit.create(ApiService.class);
        Call<ResponseInfo> call = request.testGet();// 封装请求
        try {
            Response<ResponseInfo> execute = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
            @Override
            public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {//主线程中调用
                ResponseInfo body = response.body();
                Log.i("gao", "测试  get body = " + body + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "测试GET= " + body.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<ResponseInfo> call, Throwable t) {//主线程中调用
                Log.i("gao", " testGet onFailure " + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void testPost(String string) {
        ApiService request = retrofit.create(ApiService.class);
        Call<ResponseInfo> call = request.testPost(string);// 封装请求
        call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
            @Override
            public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {
                ResponseInfo body = response.body();
                Log.i("gao", "测试  post body = " + body + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "测试  post body = " + body, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<ResponseInfo> call, Throwable t) {
                Log.i("gao", "testPost onFailure " + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "testPost onFailure ", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void testLoaddown(final String path, String url) {
        Retrofit retrofitLoaddown = new Retrofit.Builder()
                .baseUrl("http://imtt.dd.qq.com/")
                //通过线程池获取一个线程,指定callback在子线程中运行。
                .callbackExecutor(Executors.newSingleThreadExecutor())
                .build();

        ApiService request = retrofitLoaddown.create(ApiService.class);
        Call<ResponseBody> call = request.testDownload(url);//当你填进去的url是完整url的时候,设置的baseurl是无效的
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call, @NonNull final Response<ResponseBody> response) {
                Log.i("gao", "测试    线程名字 = " + Thread.currentThread().getName());
                //将Response写入到从磁盘中,详见下面分析   注意,这个方法是运行在子线程中的
                writeResponseToDisk(path, response);
            }

            @Override
            public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
                Log.i("gao", "testLoaddown 网络错误~ " + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "testLoaddown 网络错误~ ", Toast.LENGTH_SHORT).show();
            }
        });
    }

好了,主要就是这几部,下面在发一下代码中的MainActivity的代码。

import android.app.Activity;
import android.os.Environment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Executors;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Retrofit的使用步骤。
 * 1.添加Retrofit库的依赖和网络权限:
 *        compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit库
 *        compile 'com.squareup.retrofit2:converter-gson:2.3.0'
 *        <uses-permission android:name="android.permission.INTERNET" />
 *
 * 2.创建 用于描述网络请求 的接口
 *         Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数
 *
 * 3.创建Retrofit实例(回调默认的线程是主线程,可以自己设置运行在主线程或者子线程。)
 *
 * 4.将服务器返回的数据封装成一个bean类,用于接收服务器返回的数据。
 *
 * 5.发送请求
 * 请求分为同步请求和异步请求
 *
 *
 */
public class MainActivity extends Activity implements View.OnClickListener {
    Retrofit retrofit;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.testGet).setOnClickListener(this);
        findViewById(R.id.testPost).setOnClickListener(this);
        findViewById(R.id.testLoaddown).setOnClickListener(this);

        // 创建Retrofit实例时需要通过Retrofit.Builder,并调用baseUrl方法设置URL。Retrofit2的baseUlr 必须以 /(斜线)结束,不然会抛出一个IllegalArgumentException
        retrofit = new Retrofit.Builder()
                .baseUrl("http://fy.iciba.com/") // 设置 网络请求 Url
                .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                .build();

        //动态获取权限
        AppPermission.isGrantExternalRW(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.testGet:
                testGet();

                break;
            case R.id.testPost:
                testPost("hello");
                break;

            case R.id.testLoaddown:
                if (AppPermission.isGrantExternalRW(this)) {
                    String url = "http://imtt.dd.qq.com/16891/89E1C87A75EB3E1221F2CDE47A60824A.apk?fsname=com.snda.wifilocating_4.2.62_3192.apk&csr=1bbd";
                   testLoaddown(Environment.getExternalStorageDirectory() + "/ceshi.apk", url);
                }
                break;

        }

    }

    public void testGet() {
        ApiService request = retrofit.create(ApiService.class);
        Call<ResponseInfo> call = request.testGet();// 封装请求
        try {
            Response<ResponseInfo> execute = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
            @Override
            public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {//主线程中调用
                ResponseInfo body = response.body();
                Log.i("gao", "测试  get body = " + body + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "测试GET= " + body.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<ResponseInfo> call, Throwable t) {//主线程中调用
                Log.i("gao", " testGet onFailure " + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void testPost(String string) {
        ApiService request = retrofit.create(ApiService.class);
        Call<ResponseInfo> call = request.testPost(string);// 封装请求
        call.enqueue(new Callback<ResponseInfo>() {// 发送网络请求(异步)
            @Override
            public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {
                ResponseInfo body = response.body();
                Log.i("gao", "测试  post body = " + body + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "测试  post body = " + body, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<ResponseInfo> call, Throwable t) {
                Log.i("gao", "testPost onFailure " + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "testPost onFailure ", Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void testLoaddown(final String path, String url) {
        Retrofit retrofitLoaddown = new Retrofit.Builder()
                .baseUrl("http://imtt.dd.qq.com/")
                //通过线程池获取一个线程,指定callback在子线程中运行。
                .callbackExecutor(Executors.newSingleThreadExecutor())
                .build();

        ApiService request = retrofitLoaddown.create(ApiService.class);
        Call<ResponseBody> call = request.testDownload(url);//当你填进去的url是完整url的时候,设置的baseurl是无效的
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call, @NonNull final Response<ResponseBody> response) {
                Log.i("gao", "测试    线程名字 = " + Thread.currentThread().getName());
                //将Response写入到从磁盘中,详见下面分析   注意,这个方法是运行在子线程中的
                writeResponseToDisk(path, response);
            }

            @Override
            public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable throwable) {
                Log.i("gao", "testLoaddown 网络错误~ " + "  线程名字 = " + Thread.currentThread().getName());
                Toast.makeText(MainActivity.this, "testLoaddown 网络错误~ ", Toast.LENGTH_SHORT).show();
            }
        });
    }


    private void writeResponseToDisk(String path, Response<ResponseBody> response) {
        //从response获取输入流以及总大小
        writeFileFromIS(new File(path), response.body().byteStream(), response.body().contentLength());
    }

    private static int sBufferSize = 8192;

    //将输入流写入文件
    private void writeFileFromIS(File file, InputStream is, long totalLength) {

        //创建文件
        if (!file.exists()) {
            if (!file.getParentFile().exists())
                file.getParentFile().mkdir();
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
                Log.i("gao", "创建文件错误~ " + "  线程名字 = " + Thread.currentThread().getName());
            }
        }

        OutputStream os = null;
        long currentLength = 0;
        try {
            os = new BufferedOutputStream(new FileOutputStream(file));
            byte data[] = new byte[sBufferSize];
            int len;
            while ((len = is.read(data, 0, sBufferSize)) != -1) {
                os.write(data, 0, len);
                currentLength += len;
                //计算当前下载进度
                Log.i("gao", "下载 进度 = " + (int) (100 * currentLength / totalLength));
            }
            //下载完成,并返回保存的文件路径
            Log.i("gao","下载完成 file.getAbsolutePath() = "+file.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
            Log.i("gao","下载失败");
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

主要的内容就是这些,需要源代码的朋友可以下载  文中例子的   源码

下一篇我们将  Retrofit 和Rxjava的结合。

如果对 Rxjava 不懂的朋友可以看一下上篇博客: Rxjava的使用_1