このプロジェクトは実際には昨年に書かれたものでしたが、その時は基底クラスを使用せず、NetEase Cloud Youdao 翻訳の SDK を使用していました。結合の面でもあまり良くできていなかったため、冬休みの間に再構築しました。同時に、rxjava2 と retrofit を使用してネットワークリクエストを行い、ButterKnife も使用しました。このプロジェクトは自分の学習の一環として考えています。今後、最適化できる点があれば、徐々に更新していきます。
プロジェクトのリンクを添付します:starTranslation
一部の知識点#
Retrofit と RxJava2 の組み合わせ使用#
1. サービスクラスの作成
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 で必要です。以前は各レイアウトに 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 であり、どうやってジャンプするか思いつかなかったため、代わりにダイアログを表示する方法にしました。未だに解決策を見つけていません……
- Retrofit のデータエンティティクラスがあるにもかかわらず、Room のデータクラスを作成してデータを保存しました。可能であれば、1 つのクラスにまとめてコード量を減らしたいです。
- 一部の詳細がうまくできておらず、全体的に APP の生動性が依然として不足しています。
とりあえずこれで、今後何か問題があれば、また続けて補足します。