Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

關於starTranslation

這個項目其實去年就有寫了,但是那時候沒有用到基類,然後用的是網易雲有道翻譯的 sdk,耦合方面也不是做得很好,在寒假這段時間便把它重構了一遍,同時用上了 rxjava2 和 retorfit 來進行網絡的請求以及用上了 ButterKnife。這個項目就當作自己的學習吧,後面還有什麼可以優化的地方再逐步更新。

附上項目地址:starTranslation

部分知識點#

Retorfit 和 RxJava2 搭配的使用#

1. 創建 Service 類

因為要結合使用 RxJava,所以返回值就不再是一個 Call 了,而是一個 Observable。

public interface networkApi {
    @GET("api?")
    Observable<TranslationBean> translateYouDao(
            @Query("q") String q,
            @Query("from") String from,
            @Query("to") String to,
            @Query("appKey") String appKey, //應用ID
            @Query("salt") String salt,  //UUID
            @Query("sign") String sign,  //應用ID+input+salt+curtime+應用密鑰 。 input= q前10個字符+q長度+q後10個字符(q的長度>=20) 或input = 字符串
            @Query("signType") String signType, //簽名類型
            @Query("curtime") String curtime //時間戳
    );
}
2. 創建請求的過程
public class netWork {
    private static networkApi sContactsApi;
    private static OkHttpClient okHttpClient = new OkHttpClient();
    private static Converter.Factory gsonConverterFactory = GsonConverterFactory.create();
    private static CallAdapter.Factory rxJavaCallAdapterFactory = RxJava2CallAdapterFactory.create();

    private static class ApiClientHolder {
        public static final netWork INSTANCE = new netWork();
    }
    public static netWork getInstance() {
        return ApiClientHolder.INSTANCE;
    }
    public networkApi getDataService() {
        if (sContactsApi == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .client(okHttpClient)
                    .baseUrl(Constants.BASE_URL)
                    .addConverterFactory(gsonConverterFactory)
                    .addCallAdapterFactory(rxJavaCallAdapterFactory)
                    .build();
            sContactsApi = retrofit.create(networkApi.class);
        }
        return sContactsApi;
    }

}
3. 發出請求以及處理數據
@SuppressLint("CheckResult")
    public void netConnection(String q,String from,String to,String salt,String sign,String curtime){
        netWork.getInstance().getDataService()
                .translateYouDao(q,from,to,appID,salt,sign,signType,curtime)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<TranslationBean>() {
                    @Override
                    public void accept(TranslationBean translationBean) throws Exception {
                        List<TranslationBean> list_word = new ArrayList<>();
                        list_word.add(translationBean);
                        mView.showResult(list_word);
                    }
                });
    }
4. 拓展

上面的寫法是通過之前師兄的源碼學到的,在封裝方面做得不是很好,在搜索別人的使用方法的時候找到了別人的封裝方法,有時間的話需要再好好梳理下

這裡是別人的寫法:Android 優雅的讓 RxJava2.0+Retrofit2.0 結合使用

關於 Toolbar#

Toolbar 是一個很強大的控件,同時基本上每一個 Activtiy 都是需要它,在以前我是每個 Layout 都寫上一個 toolbar 的,然後用 ButterKnife 初始化 view,但是這樣寫非常麻煩…… 於是我將 toolbar 封裝到了 BaseActivity 裡,佈局方面的話是先按自己的需求寫一個 toolbar 的佈局,然後在需要的地方 include(viewpager 的切換界面按鈕我也是這樣寫的)。

具體的使用

首先寫一個 toolbar 的佈局

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="##1B6FB3"
    android:layout_alignParentTop="true"
    android:id="@+id/mtoolbar"
    android:layout_height="?attr/actionBarSize"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
</androidx.appcompat.widget.Toolbar>

接著在需要的地方 include 進去就好了

<include
        layout="@layout/view_toolbar"/>

同樣的方法還可以用來寫 tab 欄等

room 的使用#

由於之前用 room 的時候都沒有升級過數據庫,所以這個坑還真是第一次踩到,在我修改了表以後根據我拙劣的英語我看懂了它需要我升級 version,但在我升級 version 後

java.lang.IllegalStateException: A migration from 1 to 2 is necessary. Please provide a Migration in the builder or call fallbackToDestructiveMigration in the builder in which case Room will re-create all of the tables.

這是什麼玩意啊???複製粘貼去 google 了一下,有兩種辦法

增加 version,使用 fallback migration 數據被清除
private static wordDatabase buildDatabase(Context context) {
        return Room.databaseBuilder(context.getApplicationContext(), wordDatabase.class, "StarWord.db")
                .allowMainThreadQueries()
                .fallbackToDestructiveMigration() //升級倉庫的時候會重建,數據會清空
                .build();
    }

這時候 room 啟動時會檢測版本是否有增加,如果有,那麼數據庫的內容會給清空,重新建表。

version 增加,提供 Migration 數據正常

我沒有使用這種方法,因為我後面應該不會再修改數據庫,不過還是要學習下

//添加一個version:1->2的migration
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        // 這裡寫表的修改
        //database.execSQL("ALTER TABLE Starword " + " ADD COLUMN test INTEGER"); 給表添加一列字段,列名為test
    }
};

接著把這個 migration 添加到 databaseBuilder 中

private static wordDatabase buildDatabase(Context context) {
        return Room.databaseBuilder(context.getApplicationContext(), wordDatabase.class, "StarWord.db")
                .allowMainThreadQueries()
                .addMigrations(MIGRATION_1_2)
                .build();
    }

這時候數據庫的表就更新了,同時舊數據也保存了下來。

自我反思#

  • 在一開始,點擊收藏列表的單詞的時候我是準備讓 viewpager 跳轉回第一頁,然後重新進行一次搜索,但是在適配器中返回的 view 是每個 item 的 view,暫時沒想到怎麼跳轉,於是才有了彈出一個 Dialog 的替代方法。依然還沒找到解決的辦法……
  • 雖然有 Retorfit 的數據實體類,但是我還是寫了一個 Room 的數據類來存儲數據,可以的話想寫成一個類,減少代碼量。
  • 一些細節沒有做好,在整體上 APP 的生動性依然不足

先這樣吧,後面還遇到什麼坑的話再繼續補充。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。