十分に活用されていないAndroidライブラリへの過度に徹底的なガイド

公開: 2022-03-11

経験豊富な開発者なら誰でも、彼らの最高のコードは彼らが書いたコードではないと言うでしょう。 それは彼らが他の誰かの仕事から取ったコードです。

はい、私たち開発者は革新的な問題解決者ですが、私たちが遭遇する問題の多くはすでに解決されており、誰でも利用できるライブラリにパッケージ化された救済策があります。 フリーホイールがいたるところにあるのに、なぜホイールを再発明するのですか?

Androidも例外ではありません。 コードの再利用の究極のソースはAndroidSDK自体です。これには、多くの作業を行うための優れた構造とサービスが付属しています。

しかし、SDKが不足している場合、Androidコミュニティは、コーディング作業を大幅に節約できる最高級のライブラリを作成し、高度に調整され、精査され、テストされた実装に置き換えています。 明らかなライブラリ(Androidサポートライブラリ、Androidデザインサポートライブラリ、Gson)について話しているのではありません。 私はあなたが知らないかもしれないツールについて言及しています。 そして、たとえそうだとしても、おそらくまだそれらを使用していません。

標準開発者とマスター開発者の主な違いの1つは、サードパーティライブラリの正しい使用法です。 マスター開発者は、初心者よりもほぼ3倍速く、通常は短いコードで同じタスクを実行します。 これの多くは、使用するサードパーティのライブラリと、それらをプロジェクトに正しく埋め込む方法を知っていることから得られます。

私は何年にもわたってAndroidチームの開発、指導、指導を行ってきました。また、数十の外部ツールやライブラリを研究して使用してきました。 (私は彼らの実装コードを読んで開発者と彼らの内部について話し合うことさえ知られています。)多くは私が仕事を成し遂げるのを助けるのに非常に効果的でした、しかし真実はほとんどがそうではありませんでした。

そのため、このガイドをまとめました。 私の経験と他のモバイル開発者の経験に頼って、最高のライブラリを使用していることを確認してください。 私は7つ選びました。 彼らもすぐにあなたのお気に入りになると思います。

適切なAndroidライブラリの選択

ライブラリを選択するとき、私は4つの重要な機能を探します。

  • これは、実際の重要な問題に対して一貫性のある高品質のソリューションを提供します。
  • 可能な限りシンプルなAPIを使用します。
  • アーキテクチャ全体に変更を加える必要はありません。
  • 大規模なユーザーベースがあり、できればアクティブな開発者コミュニティがあります。

最初の3つの機能はディールブレーカーです。 それらが存在しない場合は、先に進むか、ハンドコーディングを開始します。

Androidライブラリ

以下で取り上げるライブラリは、4つのテストすべてに合格しています。 また、モバイル開発の最も困難な側面のいくつかを解決します。

  • 依存性注入、レイアウトからJavaへのバインディング、モックオブジェクト用の2つのライブラリ。
  • アプリ内のPub/Subメッセージングモデル。
  • 安全で効率的な自己回復型HTTP通信レイヤー。
  • 画像操作:ダウンロード、キャッシュ、サイズ変更、RAMへのロード。
  • リアルタイムビデオストリーミング。
  • メモリリークの検出。

ButterKnife:究極の依存性注入ツール

これは、Android用の究極の依存性注入ライブラリです。 シンプルで堅牢、超高速(反射なし!)で、アプリのボイラープレートコードの多くを排除できます。

そもそもButterKnifeがAndroidのJavaマッピングへのレイアウトであるはずだったと主張する人もいます。

Androidバターナイフ依存性注入

findViewById()の呼び出しを介して、各ビューを直接バインドする必要はなくなりました。 代わりに、コードに直接アクセスできる注釈付きのビューがあります。ButterKnifeは、 onClickonTouchなどの定型的なUIイベントの必要性を排除し、それらを自動挿入されたコードに置き換えます。

しかし、十分なチットチャット、コードを見てみましょう。

ビューフィールドバインディング:

 class MyButterKnifeActivity extends Activity { @BindView(R.id.name) TextView name; @BindView(R.id.address) TextView address; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.bind(this); // MUST BE CALLED BEFORE ACCESSING UI FIELDS name.setText(“etc etc”); } }

リソースバインディング:

 class ExampleActivity extends Activity { @BindString(R.string.username) String username; @BindDrawable(R.drawable.graphic) Drawable graphic; @BindColor(R.color.bg_color) int bgColor; @BindDimen(R.dimen.lower_padding) Float lowerPadding; // and no need for getResources().getString()/getDrawable/getColor() }

UIイベントバインディング:

 @OnClick(R.id.my_button) public void clickHandler(View view) { // onClick logic goes here }

AndroidAnnotations:依存性注入を次のレベルに引き上げる

依存性注入に関しては、ButterKnifeに次ぐAndroidAnnotationsは、わずかに異なるアプローチを使用します。自動生成されたクラスは、一度コツをつかめば非常にシンプルです。 さらに便利なのは、「名前ベース」の依存性注入が可能になることです。 たとえば、 @ViewById ListView myUserList; このフィールドに同じ名前のlayoutListViewを割り当てるようにライブラリに指示します。

AndroidAnnotationsも非常に高速ですが、ButterKnifeとは多少異なる方法でそれを実現します。 ランタイムバインディングの依存性注入の代わりに、AndroidAnnotationsは、影響を受けるすべてのアクティビティのビルド時の複製を作成し、その接続ロジックをそれらにプッシュします。これにより、手動でコーディングされたロジックと同じパフォーマンスを得ることができます。

しかし、AndroidAnnotationsのインジェクション機能はそれ以上のものです。 状態とレイアウトの両方をアクティビティに挿入できます。

AndroidAnnotationsの実装:

 @NoTitle @Fullscreen @EActivity(R.layout.my_layout) public class MyActivity extends Activity { @ViewById ListView customerList; // auto-binded to R.id.customerList @App MyApplication app; // auto-binded to app object @AminationRes Animation fadeoutAnimation; @UiThread void updateUI() { // main thread action } }

最後のアノテーションにはもう少し説明が必要です。マルチスレッドAndroidアプリの一般的なタスクは、バックグラウンド(またはワーカー)スレッドからフォワード(またはメインまたはUI)スレッドに切り替えることです。これは、UIコンポーネントへのアクセスを許可する唯一のスレッドです。 。 このタスクは複雑ではありませんが、多くの場合必要であり、面倒なコーディングが含まれます。

 new Handler(Looper.getMainLooper()).post(new Runnable() { logic goes here } ); // NO ANNOTATIONS

AndroidAnnotationsでは、@ UiThreadで関数に注釈を付けるだけで、常に実行されることが保証されます。

 @UiThread void updateUI() {..} // WITH ANNOTATIONS

このアノテーションは、標準のAndroidコンポーネントクラス(アクティビティ、サービスなど)に適用されることに注意してください。 しかし、自分のクラスにも注釈を付けたい場合はどうなりますか?

ここで、AndroidAnnotationsは、 EBeanの新しい概念を考え出します。 @EBeanを使用してクラスをそのようにマークするだけで、準備は完了です。

 @EBean public class MyNonComponentClass { @SystemService NotificationManager notifManager; @Bean MyOtherClass dependency; @UiThread void updateUI() { // main thread work goes here } }

EventBus:コンポーネント間の通信が容易になりました

EventBusライブラリは、Android開発者が長年悩まされてきた問題を公園の散歩に変えます。 コンポーネント間の通信がこれまでになく簡単になりました。単純なpub/subモデルを使用して、システムの任意の2つの部分間で通信します。

EventBusアニメーション

イベントバスを使用すると、コンポーネントを相互に分離する必要があるため、コードがより堅牢になります。

バックグラウンドポーリングサービスは、変更イベントをフィードするためにフラグメントを認識する必要がなくなりました。

EventBusの使用法は簡単です。

a。 イベントクラスを作成します。 ここでPOJOを操作するのが最適です。

 class NewUserEvent { String fullname; String address; String role; // add getters and setters }

b。 クラスにイベント処理メソッドを作成します。これらのイベントをサブスクライブするクラスは次のとおりです。

 class MySubscriber { @Subscribe public void newUserHandler(NewUserEvent event) { // handle NewUserEvent } @Subscribe public void newUserHandler(AnotherEvent event) { // handle AnotherEvent } }

しかし、ちょっと、経験の浅いAndroid開発者は、この時点で立ち止まって質問します。これらのハンドラーのスレッドモデルは何ですか? また、たとえばUIコンポーネントへのアクセスが含まれる場合、ハンドラーをメインスレッドから強制的に実行できますか? 良い質問…

デフォルトでは、すべてのハンドラーメソッドは、EventBus自体によって割り当てられ維持されるスレッドプールから取得されたワーカースレッドで実行されます。 メインスレッドで実行するハンドラーメソッドが必要な場合は、サブスクリプションアノテーションを次のように展開します。

 @Subscribe(threadMode = ThreadMode.MAIN) public void runOnMainThreadHandler(AnotherEvent event) { … }

警告:この機能を使いすぎないでください! 長時間実行される操作はメインスレッドで実行しないでください。迅速な操作であっても注意してください。 メインスレッドを圧倒することは、アプリを遅く、ジャンプさせ、基本的にユーザーにとって面白くないものにする最も確実な方法です。

c。 サブスクライバークラスのEventBus登録ライフサイクルを管理します。つまり、いつ接続し、いつバスから切断しますか? アクティビティの合理的な登録フローは次のとおりです。

 class MySubscriberActivity extends Activity { @Override public void onStart() { super.onStart(); EventBus.getDefault().register(this); // START RECEIVING EVENTS HERE } @Override public void onStop() { EventBus.getDefault().unregister(this); // NO MORE EVENTS super.onStop(); } }

もちろん、上記は単なる例です。 選択した場所で(非)登録を実行できます。

d。 そして最後に、実際にイベントを発生させます。

 EventBus.getDefault().post(new MyEvent(“I'm here”));

EventBusの使用については、イベントのマルチキャスト(デフォルトの動作)、スティッキーイベントの使用、配信スレッド、優先度など、さらに多くのことを知っておく必要があります。 しかし、このシンプルでありながら強力なテクノロジーを使い始めるには、上記で十分です。

OkHttp:ステロイド上のAndroidのHttpClient

これは、AndroidのHttpClientが作成されるべき方法です。 とてもシンプルでとてもスマートです。 OkHttpライブラリは、再試行ループ、ペイロードの自動圧縮、Http / 2サポート、接続プーリング、および応答キャッシュを内部的に処理するため、不要なネットワークアクセスを回避できます。

OkHttpライブラリアニメーション

OkHttpの使用法は簡単です。

Http POST:

 OkHttpClient client = new OkHttpClient(); MediaType JSON = MediaType.parse("application/json; charset=utf-8"); RequestBody body = RequestBody.create(JSON, json_str); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); return response.body().string();

Http GET:

 OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(urls[0]) .build(); Response responses = client.newCall(request).execute(); String jsonData = responses.body().string();

OkHttpは、非同期ネットワーク、リクエストリダイレクトルートクエリ、ローカルキャッシュクエリなどの便利な機能もサポートしています。 必要に応じてお気軽にご利用ください。 ほとんどの開発者は、AndroidのデフォルトのHTTPクライアントであるHttpURLConnectionのよりスマートな代替としてOkHttpを使用しています。 実際、このプロジェクト全体は、HttpURLConnectionのプライベートフォークとして開始されました。

その堅牢性が気に入っています。すぐにネットワーク層に追加されます。

ほんの数行のコードで、OkHttpは、ネットワーク層のデバッグと最適化に夜を費やしたようにアプリを動作させます。

ピカソ:グーグルがそれを使うのには十分な理由があります!

Picassoは、画像のダウンロード、キャッシュ、サイズ変更、およびトリミングを管理するための最も簡単で堅牢な方法です。

この文:

 Picasso.with(context).load(url).resize(50,50).centerCrop().into(imageView)

あなたのためにこれを行います:

  • リモートURLに接続します。
  • 画像をダウンロードします。
  • ローカルLRUキャッシュに保存し、これも管理します。
  • メモリにロードする前に、元の画像のサイズを変更してください。
  • Picassoが管理するスレッドプールで上記のすべてを実行します。
  • サイズ変更された画像を使用して、imageViewにデータを入力します。
  • 今後実行する前に、ローカルキャッシュをチェックして、ネットワークラウンドトリップが本当に必要であることを確認してください。

上記の一連のタスクを構築するには、マスター開発者であっても、何時間もの作業が必要になります。 そして、それはあなたがすべてを覚えていることを前提としています。 たとえば、サイズ変更の部分を忘れた場合はどうなりますか?

PicassoAndroidライブラリアニメーション

ええと、平均的なAndroidデバイスでは、アプリは50〜60メガバイトのRAMしか取得できず、ほとんどのAndroidデバイスのピクセル単位の係数は4です。これは、SDカードから13メガピクセルの画像を読み込もうとすることを意味します。 52メガバイトのRAMが必要になります。 つまり、アプリはすぐにクラッシュします。

これはピカソの強みの一例に過ぎません。 メディアを多用するレガシープロジェクトを最適化/デバッグするときに最初に行うことの1つは、すべての画像の読み込みをPicassoに切り替えることです。 この1つの簡単な手順がアプリの品質に与える影響に驚かれることでしょう。

このライブラリの威力を示す最も強力な証拠の1つ:過去2年間のGoogle独自のAndroidコードサンプルの多くは、画像の読み込みにPicassoを採用しています。

ActiveAndroid:ORMSansパフォーマンスオーバーヘッド

オブジェクトリレーショナルマッピングの略であるORMは、J2EEの時代に普及しました。 これにより、POJOを個別のフィールドに変換しなくても、データベースに格納したり、データベースから取得したりできます。

ActiveAndroid ORM

役に立ちましたか? SQLステートメントをコーディングせずにアプリの大部分を記述できるため、非常に重要です。

また、非常に効率的です。 昔は、ORMプラットフォームはリフレクションに大きく依存しており、遅いことで有名でした。 ActiveAndroidを含む最新のプラットフォームははるかに高速であり、ほとんどの実用的な要件では、生のSQLコーディングよりもパフォーマンスのオーバーヘッドに悩まされることはありません。

手作業でコーディングされたSQLステートメント、パフォーマンスのオーバーヘッドはありません。

使用法:

a。 カスタムApplicationクラスを拡張して、アプリケーションオブジェクトで初期化します。

 public class MyApplication extends extends com.activeandroid.app.Application { … }

b。 データベースに格納する予定の各レコードのクラスを使用して、モデルクラス用に派生したPOJOを作成します。 このような各POJOは、独自のテーブルに常駐できます。 注釈を使用して、格納されている各メンバーのDBフィールドの名前を指定する必要があります。

 @Table(name = "Categories") public class UserDetails extends Model { @Column(name = "Name") public String name; @Column(name = "Address") public String address; @Column(name = "Age") public int age; }

メンバーのインデックスを設定する場合は、次の注釈を使用します。

 @Column(name = "ID", index = true) public String userID;

c。 ライブラリが最もクラスの高い起動時間(デフォルトの動作)で繰り返されないようにするには、次のマニフェストセクションですべてのモデルクラスを指定することを強くお勧めします。

 <meta-data android:name="AA_MODELS" android:value=“com.myapp.MyModelA, com.myapp.MyModelB" />

注:このリストに表示されていないモデルクラスは、ActiveAndroidによって認識されません。

d。 データベースへの書き込み:

 UserDetails usr = new UserDetails(); usr.save(); // RUNS ON A BACKGROUND THREAD

複数の書き込みが必要な場合、より効率的な方法は、単一のトランザクションでそれらをバッチ処理することです。

 ActiveAndroid.beginTransaction(); try { for (UserDetails u: userList) item.save(); ActiveAndroid.setTransactionSuccessful(); } finally { ActiveAndroid.endTransaction(); }

e。 データベースからPOJOを読み取ります。

 new Select() .from(UserDetails.class) .where("name = ?", usr.getName()) .orderBy("Age") .executeSingle();

ORMは、サーバー側の開発者としての私の日々の中でなくてはならないツールでした。 Androidドメインへの参入がやや遅れました。 しかし、ついに、ここにあります:それが得るのと同じくらい簡単なデータベースプログラミング。 楽しめ。

LibStreaming:痛みのないビデオストリーミング

リアルタイムのビデオストリーミングは、ドキュメント化されていないAPI、SDK間のバージョンの違い、リフレクションの使用法などが原因で、以前は大きな問題でした。

libStreamingライブラリアニメーション

幸い、libStreamingは、ストリーミングの複雑さのほとんどをカプセル化し、基本的なストリーミングアプリを数時間で作成できるシンプルでフレンドリーなAPIを公開することで、これらすべてを変えました。

一言で言えば、それはビデオストリーミングを合理化します。

H.264およびAACで使用するには、次の手順を実行する必要があります。

a。 メインアクティビティのonCreateメソッドでセッションオブジェクトを初期化します。 セッションオブジェクトは、ピアへのメディアストリーミングを表します。

 protected void onCreate(Bundle savedInstanceState) { mSession = SessionBuilder.getInstance() .setCallback(this) .setSurfaceView(mSurfaceView) .setPreviewOrientation(90) .setContext(getApplicationContext()) .setAudioEncoder(SessionBuilder.AUDIO_NONE) .setAudioQuality(new AudioQuality(16000, 32000)) .setVideoEncoder(SessionBuilder.VIDEO_H264) .setVideoQuality(new VideoQuality(320,240,20,500000)) .build(); mSurfaceView.getHolder().addCallback(this); }

b。 実際にセッションを開始します。

 mSession.setDestination(destination_server_url); mSession.start();

c。 完了したらセッションを停止します。

 mSession.stop();

さて、誤解しないでください。 リアルタイムストリーミングは本質的に厄介であり、libStreamingはこの複雑さを取り除きません。 しかし、それはほとんどの場合あなたからそれを隠す本当に良い仕事をします。 場合によっては、ピアシグナリングポリシーの選択、カメラエンコーディングの選択(通常はMediaCodec / surface-to-bufferを使用する)、パケット化の処理など、複雑さに対処する必要があります。

それでも、libStreamingの背後にいる善良な人々は、これらの複雑さを使いやすいAPIにスムーズにマージすることにさらに一歩進んだことがわかります。

LibStreamingは、H.264、H.263、AAC、AMRなど、Androidアプリで使用されるほとんどのエンコーダーをサポートしています。

このライブラリで素晴らしい結果を得ることができました。 最も人気のあるストリーミングアプリのいくつかは、インフラストラクチャの一部としてそれを使用しています。 このニーズに遭遇した場合は、メディアストリーミングエクスペリエンスがはるかにスムーズになると確信しています。

LeakCanary:コード行のメモリリークを検出する

このライブラリの背後にある動機から始めましょう:メモリリーク。 Androidアプリは、特にコーディングに注意しないと、それらの傾向があります。 実際、メモリリークの作成は非常に簡単です。 あなたがする必要があるのは、そのコンテキストの外にアクティビティ参照を保存することです。 実際、アクティビティのコンテキスト外に単一のビューオブジェクトへの参照を格納する場合でも、リークが発生します。

なんで? ビュー(実際にはすべてのビュー)は、それを含むアクティビティへのコンテキスト参照を内部に格納するためです。 ビューへの参照が保持されている限り、そのビュー内のアクティビティ(ドローアブル、ビュー階層、リソースなど)は、ガベージコレクターによって再利用できません。

リークしているアクティビティへの参照を保持することは、静的パラメータとして常に明白であるとは限りません。 内部クラスを作成するか、アクティビティ内にスレッドを生成するたびに、そのアクティビティへの参照が作成され、その内部クラスまたはスレッドが完了するまで、アクティビティは再利用されない場合があります。

リークはもちろんAndroidに固有のものではありませんが、メモリリソースが限られているモバイルシステムであるため、影響はより直接的です。

リソースを大量に消費する単一のアクティビティへの参照をリークすると、「メモリ不足」の例外でアプリがクラッシュするのに十分な場合があります。

LeakCanaryライブラリ

どうすればそれらから保護できますか? もちろん、厳密なコーディング手法から始めましょう。 しかし、私たち全員が経験豊富なAndroid開発者であるわけではなく、経験豊富な開発者でさえルールを忘れることがあります。

メモリリークに重点を置いた定期的なコードレビューは役立つ場合がありますが、時間がかかります。 また、一部のリークは実際に卑劣であり、単なるコードレビューでは検出が困難です。

DDMSのメモリツールを使用することは、アプリがリークしているかどうかを時間をかけて知るための優れた方法です。 あなたは間違いなくそれを使うべきです。 ただし、リークの原因はわかりません。

ここにleakCanaryが救いの手を差し伸べます。 これは、世の中で最高のメモリリーク検出器であり、1行または2行のコードのように、すべてのアクティビティに対して自動的にリーク検出を提供します。

これを使用するには、leakCanaryをアプリのオブジェクトonCreate()で初期化します。

 public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); // more initialisations } }

これで完了です。 LeakCanaryはメモリリークを監視し、メモリリークを検出すると通知を送信します。

LeakCanaryは、 ActivityRefWatcherというオブジェクトをすべてのアクティビティに自動注入し、 onDestroy()が呼び出された後、それらの参照カウントを監視することで、この魔法を実現します。 破壊されたアクティビティの参照カウントが0より大きい場合は、リークを意味するだけです。

重要:リーク検出は、デバッグモードのアプリケーションでのみ機能します。 リリースモードAPKでリークをテストしないでください(LeakCanaryではテストしないでください)。

しかし、システムの他の部分のリークをテストしたい場合はどうなりますか? ここで、LeakCanaryはrefWatcherと呼ばれるオブジェクトを提供します。これは、実際には初期化呼び出しの戻り値です。

 refWatcher = LeakCanary.install(this);

間もなく回収される値を監視するために使用できます。 もっと正確に言えば、私が思う価値観はすぐに取り戻されるでしょう。 これを行うには、次の電話番号に電話してください。

 refWatcher.watch(my_soon_to_be_reclaimed_obj);

ライブラリは、ウォッチコールの直後にこのオブジェクトがリリースされていないかどうかを通知します。

この「短時間」の価値はどこにも見つかりませんでしたが、それほど重要ではないでしょう。 LeakCanaryを使用すると、問題なく機能します。 貴重です。

概要

経験豊富な開発者は、これらのライブラリを使用してコーディングとデバッグのフェーズを数日から数週間短縮するため、同じことができない理由はありません。

要約すると、Androidライブラリの私の選択があなたのために何ができるかはここにあります:

  • ButterKnife –自動挿入されたコードは、アプリの定型コードの多くをなくすのに役立ちます。 これは、Android向けの究極のコードインジェクションです。 もっと言う必要がありますか?

  • AndroidAnnotations –非常に高速な自動生成クラスと名前ベースのコードインジェクションを使用して、手動でコーディングされたロジックよりもパフォーマンスを低下させることなく時間を節約します。

  • EventBus –コンポーネントを分離してより堅牢なコードを実現し、コンポーネント間の通信がこれまでになく簡単になりました。

  • OkHttp – HttpURLConnectionの巧妙な代替品であり、非同期ネットワーク、要求リダイレクトルートクエリ、ローカルキャッシュクエリなどをサポートします。

  • Picasso –合理化された画像操作。これは非常に優れており、現在Googleで使用されています。 これは、メディアを多用するプロジェクトや特定のレガシープロジェクトでの大幅な時間の節約になります。

  • ActiveAndroid – ORMは、パフォーマンスのオーバーヘッドなしで簡単になりました。

  • LibStreaming –主要なストリーミングアプリで使用されるリアルタイムビデオストリーミング。

これらはあなたの時間の価値がある唯一のAndroidライブラリですか? 確かに違います。 しかし、私はあなたにこれを約束します:あなたの次のプロジェクトでそれらのいずれかを使用することはあなたをはるかに優れた開発者にするでしょう。 それらの動作を確認したい場合は、私のGitHubをご覧ください。

すでにそれらの一部またはすべてを使用している場合、または代替ライブラリを使用している場合は、以下のコメントで経験を共有することをお勧めします。

関連: Android 7.0 for Developers:新機能、パフォーマンスのアップグレード、その他気にしないもの