読者です 読者をやめる 読者になる 読者になる

Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Androidのダウンロードマネージャで柔軟なダウンロードを!

Android

こんばんは。kimukimuです。

前のContentProvider:AlarmClockに続いて、
Android2.3で追加された機能を試していきます。

今回紹介するのは、「ダウンロードマネージャ」です。

1.ダウンロードマネージャって?

ダウンロードマネージャが何かというと、大きなファイルのダウンロードなど、
時間のかかるHTTP処理を管理するためのシステムサービスです。

ダウンロードマネージャに登録しておけば、
時間のかかるダウンロードもバックグラウンドで気長にやってくれます。

加えて、ファイルが大きすぎて通信料が気になる場合は
WiFi接続でのみダウンロードしたり、
途中で接続が切断された場合にリトライしてくれたりと、何かと便利です。

では、実際に使ってみましょう。

2.アプリケーションマニフェストの記述

プロジェクトの作成はNFC(近距離通信)を使えるかを確認してみました参照。
プロジェクト作成後、「AndroidManifest.xml」に記述を追加し、下記の状態にします。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="jp.gr.t3.android.downloadmanager" android:versionCode="1"
  android:versionName="1.0">
  <uses-sdk android:minSdkVersion="9" />
  <!-- ★インターネットアクセスすることを宣言★ -->
  <uses-permission android:name="android.permission.INTERNET" />
  <!-- ★外部ストレージへの書き込みを行うことを宣言★ -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".DownloadCallActivity" android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <receiver android:name=".DownloadReceiver">
      <intent-filter>
        <!-- ▼ダウンロードマネージャのアイテムクリックを検知▼ -->
        <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
        <!-- ▼ダウンロードマネージャでのダウンロード完了を検知▼ -->
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
      </intent-filter>
    </receiver>
    <activity android:name=".ResultActivity" android:label="@string/app_name">
    </activity>

  </application>
</manifest>

uses-permissionタグでこのアプリが使う機能を宣言しています。(★)
#宣言していないとアプリからインターネットアクセス等が出来ません。
今回のアプリの場合、下記の2機能を使用するため、宣言しておきます。

  • インターネットアクセス
  • 外部ストレージへのアクセス

加えて、今回は
新たにブロードキャストレシーバを使うためのreceiverタグを追加しています。(▼)
ブロードキャストレシーバとは、
システムや他のアプリケーションにおいて特定のイベントが発生した際に
検知して処理を起動するための仕組みです。

今回の場合、下記の2タイミングで呼び出されるよう設定を行っています。

  • ダウンロード中のアイテムがクリックされたタイミング
  • ダウンロードが完了したタイミング

3.どんなコードで実現できるのか?

こんな感じで作ってみました。

コードは下記の通りです。
(ResultActivityは見てても長いだけなので省略します。DownloadManagerTest.zip 直より見てください。)

■ダウンロード画面アクティビティ

package jp.gr.t3.android.downloadmanager;

import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;


public class DownloadCallActivity extends Activity {

  private EditText urlEditText;
  private EditText titleEditText;
  private EditText descriptionEditText;
  private CheckBox wifiCheckBox;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    this.urlEditText = (EditText) findViewById(R.id.UrlText);
    this.titleEditText = (EditText) findViewById(R.id.TitleText);
    this.descriptionEditText = (EditText) findViewById(R.id.DescriptionText);
    this.wifiCheckBox = (CheckBox) findViewById(R.id.WifiOnlyCheckBox);

    Button startButton = (Button) findViewById(R.id.StartButton);
    startButton.setOnClickListener(this.setClickListener);
  }

  /**
   * ボタン押下時向けリスナー定義
   */
  private OnClickListener setClickListener = new OnClickListener() {
    public void onClick(View v) {
      DownloadCallActivity self = DownloadCallActivity.this;

      String urlStr = self.urlEditText.getText().toString();
      String titleStr = self.titleEditText.getText().toString();
      String desctiptionStr = self.descriptionEditText.getText().toString();
      boolean wifiOnly = self.wifiCheckBox.isChecked();

      pushDownloadTask(urlStr, titleStr, desctiptionStr, wifiOnly);
    }
  };

  /**
   * ダウンロードタスクをダウンロードマネージャに追加
   * 
   * @param url URL
   * @param title タイトル
   * @param description 詳細記述
   * @param wifiOnly WiFi回線のみを使用するか
   * @return ダウンロードアイテムID
   */
  private long pushDownloadTask(String url, String title, String description, boolean wifiOnly) {
    DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    Uri uri = Uri.parse(url);

    DownloadManager.Request request = new DownloadManager.Request(uri);

    // ダウンロード時のタイトルを設定
    if (title != null && title.length() > 0) {
      request.setTitle(title);
    } else {
      request.setTitle("Download");
    }

    // ダウンロードタスクの詳細記述を設定
    if (description != null && description.length() > 0) {
      request.setDescription(description);
    }

    if (wifiOnly == true) {
      // ダウンロード時、WiFi回線のみを使用
      request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
    } else {
      // 指定がない場合3G/WiFiを両方使用
      request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
          | DownloadManager.Request.NETWORK_WIFI);
    }

    // キューにダウンロードタスクを追加、タスクIDを同時に取得
    long id = manager.enqueue(request);

    return id;
  }
}

■ダウンロードレシーバ

package jp.gr.t3.android.downloadmanager;

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class DownloadReceiver extends BroadcastReceiver {

  /**
   * ダウンロード終了を検知
   */
  @Override
  public void onReceive(Context context, Intent intent) {
    // ダウンロードが完了したら結果用アクティビティを表示
    if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {

      long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
      Toast.makeText(context, "Download Complete ID : " + id, Toast.LENGTH_LONG).show();

      if (id != -1) {
        Intent resultIntent = new Intent(context, ResultActivity.class);
        resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        resultIntent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, id);
        context.startActivity(resultIntent);
      }
    } else {
      // ダウンロードマネージャの通知領域をクリックした場合はメッセージ表示のみ
      Toast.makeText(context, intent.getAction(), Toast.LENGTH_LONG).show();
    }
  }
}

4.実行してみる

では、実際に書いたコードを使ってダウンロードの確認をしてみましょう。
尚、今回はエミュレータで確認を行います。
え?前々回書いてたタブはどうしたんだって?

いえですね、今回画面がシンプルな関係上、
タブレットに表示するとイマイチ偏った画面になってしまったので・・・
とまぁ、それはさておき、アプリケーションを起動すると下記のような画面になります。

Urlが実際にダウンロードするUrl、
Titleがダウンロード時のタイトル、Descriptionがコメントになります。
WiFiOnlyにチェックを入れると3G回線は使わず、
WiFi接続エリアにいる場合にのみダウンロードを行います。

では、何かテストダウンロードをしてみましょう。
下記のようにアドレスを入力して、「Push Download Task」を押します。

すると、あっという間にダウンロードが完了して、結果画面が表示されます。
※ダウンロードが完了したので、ブロードキャストレシーバが受信し、
※結果画面を表示しています。

ただ、これだと何がダウンロードマネージャなのかわかりませんよね。
なので、次は更に大きなファイルをダウンロードしてみます。

大容量のダウンロードを行うと、通知ウィンドウ内で
プログレスバーが表示され、ダウンロードが管理される状態になります。

5.で、何がうれしいんだっけ?

実はこれだけ見るとパっとしないかもしれません(^^;

ただ、ダウンロードマネージャを使うことで、
ファイルのダウンロードをバックグラウンドで簡単に行うことが出来ます。

また、『ファイルのダウンロードが終わったら何かしたい!』という
アプリケーションもブロードキャストレシーバを設定することで、
他のアプリの動作を阻害することなく実現できます。

容量の大きい、長時間の通信を行うアプリが便利に使える機能、というわけですね。
あ、ただ何でもかんでもブロードキャストレシーブすると
わけがわからないことになりますので、そこだけはご注意を。