Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

starTranslationについて

このプロジェクトは実は去年から書かれていましたが、その時は基底クラスを使用せず、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 の生動感が不足しています。

とりあえずこれで、今後何か問題があればまた続けて補足します。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。