fc2ブログ

戌印-INUJIRUSHI- (Androidあれこれ)

Androidのプログラミングをメインにしてます。記事に貼られたソースコードはダブルクリックすることで行番号をはずしてコピーすることができます。

 
2
3
4
5
6
7
8
9
10
11
13
14
16
17
18
19
20
21
22
23
24
26
27
28
29
30
10

非同期処理:AsyncTask

AsyncTask はAndroidで用意された非同期処理に特化したスレッドクラスです。

API Reference: AsyncTask
ソフトウェア技術ドキュメントを勝手に翻訳 - 5. プロセスとスレッド スレッド

■ 注意事項 ---------------------------------------------------
AsyncTaskクラスは変数で保持せずに使い捨てしてください
 再利用した場合、 java.lang.IllegalStateException が発生します。
・AsyncTask#cancel() は呼んだだけでは AsyncTask#doInBackground() は終了しません。
 AsyncTask#cancel() を呼ぶと AsyncTask#isCancelled() が true を返すようになります。
 AsyncTask#doInBackground() 内で AsyncTask#isCancelled() を呼び出して終了してください。
 (サンプルは無くても終了する、というツッコミはなしでお願いします)
・AsyncTask#cancel() が呼ばれた時 AsyncTask#onPostExecute() は呼ばれません。
 代わりに AsyncTask#onCancelled() が呼ばれます。

以下のサンプルでキャンセルを行った場合、LogCatで警告メッセージ出ています。
原因はちょっと不明です…調べないと…

■ ソースコードで定義 -----------------------------------------
package jp.inujirushi.sample.activity;

import jp.inujirushi.sample.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class AsyncTaskActivity extends Activity {

/** アクティビティを生成したときに呼ばれます。 */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_dialog);

// ボタンのクリックイベントに非同期の開始処理を追加する
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// タスクを生成する
SampleAsyncTask mAsyncTask = new SampleAsyncTask();
// タスクを実行する
mAsyncTask.execute("非同期処理を開始します");
}
});
}

class SampleAsyncTask extends AsyncTask<String, Integer, String> {
/** プログレスダイアログ */
ProgressDialog mDialog;

/** 非同期実行前の処理を行います。 */
@Override
protected void onPreExecute() {
// ダイアログを作成する
mDialog = new ProgressDialog(AsyncTaskActivity.this);
mDialog.setTitle("非同期処理");
mDialog.setMessage("処理中...");
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setMax(100);
mDialog.setProgress(0);
mDialog.setButton("キャンセル", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 非同期処理をキャンセルする
cancel(true);
}
});

// ダイアログを表示する
mDialog.show();
}

/** 非同期処理を行います */
@Override
protected String doInBackground(String... arg0) {
// 受け取ったパラメータをログに表示する
Log.d("execute()の引数", arg0[0]);

// 進捗率が100まで繰り返す
while (mDialog.getProgress() < 100) {
// 一定時間停止する
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// プログレスバーを更新する
publishProgress(mDialog.getProgress() + 1);

// キャンセルが押された場合
if (isCancelled()) {
// 処理を終了する
return null;
}
}

return "処理が正常に終了しました";
}

/** プログレスバーの更新を行います */
@Override
protected void onProgressUpdate(Integer... values) {
// 受け取った値をプログレスバーに反映する
mDialog.setProgress(values[0]);
}

/** 非同期実行後の処理を行います。 */
@Override
protected void onPostExecute(String result) {
// プログレスダイアログを閉じる
mDialog.dismiss();

// 受け取ったパラメータを通知メッセージで表示する
Toast.makeText(AsyncTaskActivity.this, result, Toast.LENGTH_SHORT)
.show();
}

/** 非同期キャンセル時の処理を行います */
@Override
protected void onCancelled() {
Toast.makeText(AsyncTaskActivity.this, "キャンセルされました",
Toast.LENGTH_SHORT).show();
}
}
}

スポンサーサイト



Android 4.0 (API 14) インストールでエラー発生

Android 4.0 (API 14) が公開されたということで早速インストールしました。
が、翌日起動するとエラーが出てエミュレータが起動しないという事態に・・・

This Android SDK requires Android Developer Toolkit version 14.0.0 or above.
Current version is 11.0.0.v201105251008-128486.
Please update ADT to the latest version.


ADT のバージョンが古いからアップデートしろとのこと。

Android SDK Manager から更新しようとするもエラーが出て実行されない。

仕方ないのでメニューの [ヘルプ(H) - 更新の確認] から更新。

以下の4つをバージョン 14.0.0.v201110171935-205994 に更新。
・Android DDMS
・Android 開発ツール
・Android Hierarchy Viewer
・Android Traceview

Eclipseを再起動したら直りました。

どうも新しいのを入れると何かしらエラーが発生しているような気がする…

※この記事は [Android トラブルシューティング] に追加しました。

オプションメニュー:Menu

Menu はメニューボタン押下時に画面下部に表示されるメニューです。
(プログラムから呼び出すことも可能です)

Reference: Menu, MenuItem
ソフトウェア技術ドキュメントを勝手に翻訳 - 6.2 メニューの作成

■ 画面イメージ -----------------------------------------------
android_Menu.png

■ ソースコードで定義 -----------------------------------------
package jp.inujirushi.sample.activity;

import jp.inujirushi.sample.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MenuActivity extends Activity {
/** メニューID */
private static final int MENU_1 = 1;
private static final int MENU_2 = 2;

/** アクティビティを生成した時に呼ばれます。 */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// オプションメニューを呼び出すボタンを追加
setContentView(R.layout.sample_button);
Button btnMenu = (Button) findViewById(R.id.button1);
btnMenu.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// オプションメニューをプログラム側から開きます
openOptionsMenu();
}
});
}

/** オプションメニューが生成された時に呼ばれます。 */
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// メニューを追加します
// 引数は左からグループID、アイテムID、表示順、表示文字列
menu.add(Menu.NONE, MENU_1, 0, "メニュー1");
menu.add(Menu.NONE, MENU_2, 1, "メニュー2");

return super.onCreateOptionsMenu(menu);
}

/** オプションメニューが表示される時に呼ばれます。 */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// メニューアイテムを取得する
MenuItem item = menu.findItem(MENU_1);
// メニューを呼ぶたびに表示・非表示が切り替わるように設定する
item.setVisible(!item.isVisible());

return super.onPrepareOptionsMenu(menu);
}

/** オプションメニューが選択された時に呼ばれます。 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case MENU_1:
// メニュー1が押された
Toast.makeText(this, "メニュー1が押されました", Toast.LENGTH_SHORT).show();
break;

case MENU_2:
// メニュー2が押された
Toast.makeText(this, "メニュー2が押されました", Toast.LENGTH_SHORT).show();
break;
}
return super.onOptionsItemSelected(item);
}

/** オプションメニューを閉じる時に呼ばれます。 */
@Override
public void onOptionsMenuClosed(Menu menu) {
super.onOptionsMenuClosed(menu);
// 終了時に何か処理を行いたい時はここに記述します
}
}

進捗ダイアログ:ProgressDialog

ProgressDialog は画面に進捗状態を示すダイアログを表示します。

API Reference: ProgressDialog

■ 画面イメージ -----------------------------------------------
android_ProgressDialog_spinner.png android_ProgressDialog_horizontal.png
プログレスはスタイルの設定 ProgressDialog#setProgressStyle(int) で変更できます。
スピナー(左):ProgressDialog.STYLE_SPINNER
ゲージ(右):ProgressDialog.STYLE_HORIZONTAL
※ 未指定もスピナーになります

■ ソースコードで定義 -----------------------------------------
package jp.inujirushi.sample.activity;

import jp.inujirushi.sample.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class ProgressDialogActivity extends Activity {
/** プログレスダイアログ */
ProgressDialog mDialog;

/** アクティビティを生成した時に呼ばれます。 */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_dialog);

// ボタンのクリックイベントにダイアログ表示を設定する
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// ダイアログ作成クラスを生成する
mDialog = new ProgressDialog(ProgressDialogActivity.this);
// ダイアログにタイトルを設定する
mDialog.setTitle("タイトル");
// ダイアログにメッセージを設定する
mDialog.setMessage("ロード中...");
// プログレスのスタイルを設定する(ゲージ)
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// プログレスの最大値を設定する
mDialog.setMax(100);
// プログレスの現在値を設定する
mDialog.setProgress(0);
// ダイアログを表示する
mDialog.show();

// スレッドを開始する
new Thread(mRunnable).start();
}
});
}

/** スレッド */
Runnable mRunnable = new Runnable() {
@Override
public void run() {
// 進捗率が100まで繰り返す
while (mDialog.getProgress() < 100) {
// 一定時間停止する
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// ゲージを +1 する
mDialog.setProgress(mDialog.getProgress() + 1);
}

// ダイアログを破棄する
mDialog.dismiss();
}
};
}

フラグメント:Fragment (Android 3.0~)

Fragment はタブレット向け(Android 3.0~)の機能です。
ホームページのフレームのように複数の画面を1つにまとめることができます。
(Activityがフレームで、Fragmentがページのイメージ)

API Reference: Fragment
ソフトウェア技術ドキュメントを勝手に翻訳 - 1.1 フラグメント

■ 画面イメージ -----------------------------------------------
android_Fragment.png

■ 静的に定義 --------------------------------------------------
まずはアクティビティを定義します。
XML側でFragmentを呼んでいるだけで、Java側では特に何もしていません(サンプルが表示のみのため)
<fragment>タグの android:name で対象のJavaファイルのクラスパスを指定します。

sample_fragment.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">
<fragment android:name="jp.inujirushi.Fragment1"
android:id="@+id/fragment1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment android:name="jp.inujirushi.Fragment2"
android:id="@+id/fragment2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>

FragmentActivity.java
package jp.inujirushi;

import android.app.Activity;
import android.os.Bundle;

public class FragmentActivity extends Activity {
/** アクティビティを生成した時に呼ばれます。 */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample_fragment);
}
}


次に、左右に表示するFragmentを定義します。
FragmentのXMLは通常のアクティビティと同様の設定をします。
まるでActivityですが、FragmentはAndroidManifest.xmlの設定は不要です。

fragment1.xml(左側)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000">
<TextView android:text="Fragment1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff" />
</LinearLayout>

fragment2.xml(右側)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<TextView android:text="Fragment2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000" />
</LinearLayout>


Fragment1.java(左側)
package jp.inujirushi;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment1 extends Fragment {
/** フラグメントを生成した時に呼ばれます。 */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
}

Fragment2.java(右側)
package jp.inujirushi;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment2 extends Fragment {
/** フラグメントを生成した時に呼ばれます。 */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment2, container, false);
}
}


■ 動的に定義 --------------------------------------------------
Fragment は直接レイアウトに追加することができません。
追加や変更を行う場合には、FragmentTransaction クラスを使用します。
package jp.inujirushi;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;

public class FragmentActivity extends Activity {
/** アクティビティを生成した時に呼ばれます。 */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// IDを定義する
final int ID_FRAGMENT1 = 1;
final int ID_FRAGMENT2 = 2;

// レイアウトを生成する
LinearLayout layout = new LinearLayout(this);
setContentView(layout);
// フラグメントに置換するレイアウトを生成する①
LinearLayout fragment1 = new LinearLayout(this);
fragment1.setId(ID_FRAGMENT1);
fragment1.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT,
1));
layout.addView(fragment1);
// フラグメントに置換するレイアウトを生成する②
LinearLayout fragment2 = new LinearLayout(this);
fragment2.setId(ID_FRAGMENT2);
fragment2.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT,
1));
layout.addView(fragment2);

// フラグメントマネージャを生成する
FragmentManager manager = getFragmentManager();
// フラグメントトランザクションを開始する
FragmentTransaction transaction = manager.beginTransaction();
// レイアウトをフラグメントに差し替える
transaction.replace(ID_FRAGMENT1, new Fragment1());
transaction.replace(ID_FRAGMENT2, new Fragment2());
// 設定をコミットする
transaction.commit();
}
}


Fragmentが1つの場合、置換用のレイアウトを生成せずに設定できます。
    @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// フラグメントトランザクションを開始する
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// ルートビューをフラグメントに差し替える
transaction.replace(android.R.id.content, new Fragment1());
// 設定をコミットする
transaction.commit();
}

プロフィール

とむ・やむくん

Author:とむ・やむくん
管理人について

Windows 7 / 64bit
Eclipse 4.2 Juno (日本語パッチ済)

スポンサーサイト
最新トラックバック
検索フォーム
ブロとも申請フォーム
QRコード
QR
Twitter
2013/01/04 19:00 カウント開始