このプロジェクトは実は去年から書かれていましたが、その時は基底クラスを使用せず、NetEase Cloud Youdao 翻訳の SDK を使っていました。カップリングの面でもあまり良くできていなかったので、冬休みの間に再構築しました。同時に、rxjava2 と retrofit を使ってネットワークリクエストを行い、ButterKnife も使用しました。このプロジェクトは自分の学びとして捉え、今後さらに最適化できる部分があれば徐々に更新していきます。
プロジェクトのリンクを添付します:starTranslation
一部の知識ポイント#
Retrofit と 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 は非常に強力なウィジェットで、ほとんどすべての Activity で必要です。以前は各 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"/>
同様の方法でタブバーなども作成できます。
Room の使用#
以前 Room を使用したときにデータベースをアップグレードしていなかったため、この問題は本当に初めての経験でした。テーブルを変更した後、私の拙い英語で理解したのは、バージョンをアップグレードする必要があるということでしたが、バージョンをアップグレードした後に
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 で調べたところ、2 つの方法がありました。
バージョンを増やし、fallback migration を使用するとデータが消去される
private static wordDatabase buildDatabase(Context context) {
return Room.databaseBuilder(context.getApplicationContext(), wordDatabase.class, "StarWord.db")
.allowMainThreadQueries()
.fallbackToDestructiveMigration() //アップグレード時に再作成され、データが消去される
.build();
}
この時、Room は起動時にバージョンが増加したかどうかを検出し、増加していればデータベースの内容が消去され、新たにテーブルが作成されます。
バージョンを増やし、Migration を提供するとデータが正常に保存される
私はこの方法を使用しませんでした。なぜなら、今後データベースを変更することはないと思ったからですが、やはり学ぶ必要があります。
//バージョン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 は各アイテムの view で、どうやってジャンプするか思いつかなかったため、代わりに Dialog を表示する方法になりました。依然として解決策を見つけられていません……
- Retrofit のデータエンティティクラスがあるにもかかわらず、データを保存するために Room のデータクラスを作成しました。可能であれば、1 つのクラスにまとめてコード量を減らしたいです。
- 一部の詳細がうまくいっておらず、全体的に APP の生動感が不足しています。
とりあえずこれで、今後何か問題があればまた続けて補足します。