Androidウィジェットの開発

Habrには、Androidデバイス用の「hello world」ウィジェットを開発する方法についての十分な記事がすでにあります。 これについては、 開発者向けのGoogleサイト、 StackOverflow 、その他のリソースなど、ネットで詳細を読むことができます。 すべてが詳細にかみ砕かれているように見えます。何百もの例があります-十分な情報があるのに、なぜ別の記事を書くのですか?

しかし、ウィジェットの開発を開始したとき、数週間かけてニュアンスを整理し、当初考えていた方法でプロジェクトを実装する必要がありました。

私たちの経験が、ウィジェットの実装時間を節約するのに役立つことを願っています。



準備する



Android Stuidoは開発に選ばれました。この製品はまだ非常に粗雑で、すべての開発者がそれに切り替える準備ができているわけではありませんが、プレビューの優れた仕事とGradleビルドシステムの幅広い機能がすべての欠点に勝っています。 したがって、私たちは試してみましたが、結局は無駄ではありませんでした。



テストでは、テストスマートフォンでの直接デバッグに加えて、ソフトウェアエミュレーターも使用しました。 標準の使用はかなり問題が多いため、 Android-x86AndroVMGenymotion 、Manymoなどのさまざまな高性能エミュレータが検討されました。 その結果、Genymotionを選択しました。インストールが簡単でAndroid-x86の速度に優れているため、Android 4.0以前のデバイスでテストするにセットアップとインストールの詳細な手順が必要です。



これらのエミュレーターはさまざまなOSで正常に動作します。Linux、Mac、Windows、開発者の好みは異なります。それらを説得するのは間違っているため、クロスプラットフォームツールが役立ちます。



また、これらのプログラムは自動テストに役立ちます。テストはAndroid Instrumentation Framework、JUnit、Robotiumを使用して記述されます。 これについては、近々公開する次の記事で詳しく説明します:)



設計



そのため、ユーザーに検索フォーム、音声リクエストのボタン、およびウィジェットの利用可能なサイズの増加に伴い、現在のニュースのアナウンスが表示されるようにします。





Google Playによると、Androidをサポートする約4,500種類のさまざまなデバイスが世界で登録されています。





これらのデバイスは、画面解像度に加えて、対角線と単位面積あたりのピクセル密度(ppi)が異なる場合があります。 幸いなことに、タスクを簡素化し、デバイスに依存しないピクセル-dpを使用してウィジェット要素のサイズを決定できます。 ほとんどのスマートフォンは4x4グリッドを使用していますが、7インチタブレットの場合、グリッドは6x6になり、セルサイズ自体もランチャーとAndroid APIのバージョンに依存します。 表では、さまざまなデバイスの結果のサイズをdpで示しました。

サムスンGT-i9000 Nexus 4 サムスンタブ Nexus 7
1×1 64 x 58 64 x 58 74 x 74 80 x 71
2×2 144 x 132 152 x 132 148 x 148 176 x 159
4 x 3 304 x 206 328 x 206 296 x 222 368 x 247


次の式から開始できます。

14サイズ未満のAPIの場合=(74 xセル数)-2

最新バージョンのサイズ=(70 xセル数)-30

テスト中に画面の向きを変更するなど、特定のデバイスで問題が発生した場合は、パラメータを調整するよりも、別のレイアウトを追加したり、diameter.xmlで目的のサイズを指定したりする方が簡単です。 設計段階でも、再利用可能な要素に注意してください。そうすることで、開発時にそれらを個別のレイアウトに配置し、挿入を使用して目的の場所に挿入できます。 私たちのアプリケーションでは、このテクノロジーをニュースに使用し、home_news_row.xmlのいくつかの要素の影を実装しました。

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/news_row" android:layout_width="match_parent" android:layout_height="match_parent"> <include android:id="@+id/news_item1" layout="@layout/home_news_item"/> <include android:id="@+id/news_item2" layout="@layout/home_news_item"/> </LinearLayout>
      
      





home_news_item.xml:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/news_img" android:scaleType="centerCrop" android:layout_weight="1"/> <TextView android:id="@+id/news_text" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="13sp"/> </LinearLayout>
      
      





実装



サーバーからウィジェットのデータをJSONで取得します。すべてが非常に単純で、ドキュメントに詳細が記載されています。 ウィジェットが最小サイズ(検索バーと音声要求アイコン)に設定されている場合、最新のニュースアナウンスメントは要求されません。ウィジェットが拡大されると、まず現在のニュースがキャッシュされているかどうかを確認し、利用可能なデータを取得して、トラフィックとバッテリーを節約します。



Androidバージョンの現在の分布を分析した結果、バージョン2.2が引き続き関連しており、サポートする必要があることがわかりました。 残念ながら、ウィジェットのサイズ変更のサポートはバージョン3.0からのみ利用可能です。したがって、古いバージョンでは、拡張ウィジェットの静的バージョンを作成します。 現在、バージョン3.xのデバイスのシェアは重要ではないため、onAppWidgetOptionsChangedメソッドを使用して、Android 4.1以降のウィジェットのサイズ変更に対応することにしました。 しかし、彼にとってすべてがスムーズというわけではありません。修正されたファームウェアでは動作しません。 私は別の解決策を探す必要があり、それが見つかりました:onReceive()メソッドでcom.sec.android.widgetapp.APPWIDGET_RESIZEイベントを使用しました:

 public void onReceive(Context context, Intent intent) { if (intent.getAction().contentEquals("com.sec.android.widgetapp.APPWIDGET_RESIZE")) { handleResize(context, intent); } super.onReceive(context, intent); } private void handleResize(Context context, Intent intent) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); Bundle newOptions = getOptions(context, intent); int appWidgetId = intent.getIntExtra("widgetId", 0); if (!newOptions.isEmpty()) { onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions); } } public Bundle getOptions(Context context, Intent intent) { Bundle newOptions = new Bundle(); int appWidgetId = intent.getIntExtra("widgetId", 0); int widgetSpanX = intent.getIntExtra("widgetspanx", 0); int widgetSpanY = intent.getIntExtra("widgetspany", 0); if(appWidgetId > 0 && widgetSpanX > 0 && widgetSpanY > 0) { newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, widgetSpanY * 74); newOptions.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, widgetSpanX * 74); } return newOptions; } @Override public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { Log.d("height", newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)); Log.d("width", newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)); }
      
      





ホーム画面にウィジェットをインストールするとき、ユーザーは設定で色と透明度を選択できます。 この実装では複雑なことは何もありませんが、1つの注意点があります。選択した色に透明度レベルを追加する必要があります。 たとえば、次のように実装されています。

 int color = Color.parseColor(“#FFFFFF”); int transparent =150; color = Color.argb(transparent, Color.red(color), Color.green(color), Color.blue(color));
      
      





透明度レベルの結果の色がウィジェット要素に適用されます。 この場合、LinearLayoutでsetBackgroundColor()を設定するだけです。



また、ランドスケープモードでは、ウィジェットのセルサイズがポートレートモードよりも小さいため、指定された長さのテキストが収まらない状況もあります。 テキストのサイズを小さくすることはできますが、低解像度のデバイスでは読みにくくなります。 この点に関して、向きを変更するときは、横長モードのレイアウトで表示される行数text.setMaxLines(2)を単純に減らし、フォントサイズを変更しないままにします。

 android:maxLines="3" android:ellipsize="end"
      
      





最後のプロパティは、行末に省略記号を追加します。



インストールされたウィジェットのリストでウィジェットを見つけやすくするために、最後の仕上げが必要です。プレビュー画像を準備するか、previewImageです。 グラフィカルエディターで最終的なウィジェットを再現することもできますが、 ウィジェットプレビューアプリケーションを使用しました



結果は次のとおりです。







最終アプリケーションはこちらからダウンロードできます。



ご清聴ありがとうございました!



All Articles