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

       最近工作用到 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的结合:Retrofit 和 Rxjava 的简单实用

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值