2013/09/17

Android:ActionBar下部にProgressBarを表示


上図のようなActionBarの直下にプログレスバーを表示するUIがあります。
ActionBarの機能かと思ったのですが、どうもそうではなさそうなので自作しました。
# 類似のPJにPullToRefreshがあります

まずはActionBar下部に表示される影を消します。
これがあると、ActionBarとプログレスバーの間に隙間ができてしまいます。
<activity
    android:name="yuki312.android.actionbarprogress.MainActivity"
    android:label="@string/app_name"
    android:windowContentOverlay="@null" >

次にプログレスバーを配置するためのレイアウトを定義。
画面最上部にプログレスバーを配置します。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="0dp" >
    <ProgressBar
        android:id="@+id/view_actionbar_progress"
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:indeterminateDrawable="@drawable/ic_progress_indeterminate" />
</RelativeLayout>

indeterminateDrawableにプログレスバーの画像を指定します。
プログレスバーの画像はアニメーションさせるのが一般的です。
1コマ毎の画像を用意してアニメーションリソースを用意しても良いのですが、
リソース節約のため、ここではShapeで描画します。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false" >
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="1.0"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.8"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.6"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.4"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.2"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="70">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.0"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
   
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.2"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.4"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.6"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.8"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="1.0"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>

</animation-list>
これで、ActionBar下部にプログレスバーが表示されます。

ソース+apkをgithubにアップしています。
https://github.com/YukiMatsumura/ActionBarProgress

以上です。

2013/05/18

Android:AlermManagerとネットワークアクセスを組み合わせる際のマナー


AlermManagerを使用すれば、任意の時間に処理を実行することができます。
Android Developers : AlermManager.set (int, long, PendingIntent)

時間指定の方法には次のタイプがあります。
  • 絶対時間で指定するRTCタイプ
  • 相対時間で指定するELAPSED_REALTIMEタイプ
○○時○○分に処理したい場合はRTC、今から○○分後に処理したい場合はELAPSED_REALTIMEといった具合です。

どちらのタイプを使用するかはアプリ要件に左右されますが、もしあなたのアプリケーションが
 タイマー発火を契機にネットワークアクセスする仕様、かつRTCタイプを採用しようとしている
のであれば一度次のことを検討してみましょう。
この処理/仕様は、相対時間指定(○○分後)で実現可能か。あるいはそのように処理/仕様を変更できないか。
もし、この問いに"YES"であるならRTCタイプではなくELAPSED_REALTIMEタイプを採用するのがよい選択です。

これには次の理由があります。
絶対時間指定の場合、アプリからのネットワークアクセスが集中する
数百万(あるいは数千万!)DLされたアプリが、特定の時間に一斉にネットワークアクセスを開始すればどうなるかは容易に想像できますね。

ネットワークアクセスのタイミングをRTCタイプでしか実現できないのであれば、
「端末によって絶対時間指定の時刻をずらせないか」
を検討するのも良い案です。
ネットワークアクセス時刻を設定/初期化する際に、分散の大きい乱数でも加えてあげればネットワークアクセスも分散されます。

重要なのは"ネットワークアクセスを集中させないこと"です。
ELAPSED_REALTIMEタイプを採用したからといって"AM8:00"までの時間差分を指定しては問題の解決にはなりません。

この手の話題は"アプリのマナー"に関わる部分です。
マナーを守るためにはソースコードの修正が必要かもしれません。
もしかすると、あなたのアプリのパフォーマンスがほんのちょっぴり低下するかもしれません。
適用したからといって、ユーザレビューの評価点にはそれほど影響しないでしょう。
しかし、こういったマナーを守るアプリが増えれば、きっとその反対よりは良い世の中になりそうです。
プロとして"気の利いたアプリ"を作っていきたいものですね。

以上です。