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

發佈了15 篇原創文章 · 獲贊 1 · 訪問量 6637
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章