android lecture #04 @pro&bsc inc

26
アニメーション / 各種テスト 2012/03/21()@PRO&BSC 樋口 祐紀 ([email protected])

Upload: yuki-higuchi

Post on 14-Jun-2015

6.076 views

Category:

Education


0 download

DESCRIPTION

2012/03/21 に株式会社 PRO&BSC にて行った Android 研修の資料 #4 です。

TRANSCRIPT

Page 1: Android Lecture #04 @PRO&BSC Inc

アニメーション / 各種テスト

2012/03/21(水)@PRO&BSC

樋口 祐紀

([email protected])

Page 2: Android Lecture #04 @PRO&BSC Inc

本日の内容

• アニメーション

–User eXperience を高めましょう

•楽しい感じに

•処理待ちのイライラを軽減

•各種テスト

–単体/結合/安定化試験を自動化し、アプリの品質を高めましょう

2

Page 3: Android Lecture #04 @PRO&BSC Inc

アニメーション

クラス名 概要

AlphaAnimation フェードイン/アウト

RotateAnimation 回転

ScaleAnimation 拡大/縮小

TranslateAnimation 移動

AnimationSet アニメーションの合成

Page 4: Android Lecture #04 @PRO&BSC Inc

4

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center"> <Button android:layout_width="wrap_content" android:padding="20dp" android:id="@+id/button" android:layout_height="wrap_content" android:text="Hello World !!" /> </LinearLayout>

main.xml

サンプルのレイアウト

Page 5: Android Lecture #04 @PRO&BSC Inc

AlphaAnimation: フェードイン/アウト

5

public class MainActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);

Button btn = (Button)findViewById(R.id.button); btn.setOnClickListener(new OnClickListener() { public void onClick(View v) {

AlphaAnimation alpha = new AlphaAnimation(1.0f, 0.0f); alpha.setDuration(3000); v.startAnimation(alpha);

} }); } }

Page 6: Android Lecture #04 @PRO&BSC Inc

6

RotateAnimation: 回転

RotateAnimation rotate = new RotateAnimation( 0, 360, v.getWidth() / 2, v.getHeight() / 2); rotate.setDuration(3000); v.startAnimation(rotate);

ScaleAnimation: 拡大/縮小

ScaleAnimation scale = new ScaleAnimation( 1, 2, 1, 2, v.getWidth() / 2, v.getHeight() / 2); scale.setDuration(3000); scale.setInterpolator(new CycleInterpolator(3)); v.startAnimation(scale);

Page 7: Android Lecture #04 @PRO&BSC Inc

7

TranslateAnimation: 移動

TranslateAnimation translate = new TranslateAnimation( -10, 10, -10, 10); translate.setDuration(3000); translate.setInterpolator(new CycleInterpolator(3)); v.startAnimation(translate);

AnimationSet: アニメーションの合成

AnimationSet set = new AnimationSet(true); set.addAnimation(alpha); set.addAnimation(rotate); set.addAnimation(scale); v.startAnimation(set);

これまでのアニメーションの定義部分( startAnimation以外)を残しておき、それらの定義の下に書いてみましょう

Page 8: Android Lecture #04 @PRO&BSC Inc

アニメーションを利用したビューア • APK

– http://goo.gl/LLYXP

• ソース – http://goo.gl/oWcyG

• ソースのインポート方法

– Eclipse の [ファイル(F)] – [インポート(I)...] から「インポート」ダイアログを開く

– [一般] - [既存プロジェクトをワークスペースへ] を選び、「ルート・ディレクトリーの選択」にてインポート対象フォルダを選択して取り込み完了 8

Page 9: Android Lecture #04 @PRO&BSC Inc

Tips: メニューの追加方法

9

/** メニューID (バージョン) */ static final int MENU_ID_MENU1 = (Menu.FIRST + 1);

public boolean onCreateOptionsMenu(Menu menu) { // メニュー (バージョン) の追加 MenuItem menuVersion = menu.add( Menu.NONE, MENU_ID_MENU1, Menu.NONE, "バージョン"); menuVersion.setIcon(android.R.drawable.ic_menu_info_details);

return super.onCreateOptionsMenu(menu); }

public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ID_MENU1: // バージョン表示 showDialog(DIALOG_ID_VERSION); break;

default: return super.onOptionsItemSelected(item); }

return true; }

Page 10: Android Lecture #04 @PRO&BSC Inc

Tips: ハードウェアキーの補足

10

public boolean onKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event);

switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_SPACE: case KeyEvent.KEYCODE_ENTER:

... (省略) ...

return true;

case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DEL:

... (省略) ...

return true; }

return false; }

Page 11: Android Lecture #04 @PRO&BSC Inc

Tips: 回転後も消えないダイアログ

11

/** ダイアログID (バージョン) */ static final int DIALOG_ID_VERSION = 0;

protected Dialog onCreateDialog(int id) { Dialog dialog;

switch (id) { case DIALOG_ID_VERSION: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setIcon(R.drawable.icon); builder.setTitle("イメージビューア"); builder.setMessage("version 3.0"); builder.setPositiveButton("OK", null); dialog = builder.create(); break;

default: dialog = null; }

return dialog; }

... (省略) ... showDialog(DIALOG_ID_VERSION);

onCreateDialogを経由して表示することでダイアログのライフサイクルをActivityに管理してもらうことになります。 このため、正確に書くと「(画面の)回転後も消えない」ではなく、「(画面の)回転後にActivityの再生成に伴ってダイアログも再生成される」が正しくなります。

Page 12: Android Lecture #04 @PRO&BSC Inc

Tips: FrameLayout の使い方

12

<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/white" android:padding="10dp" >

<ImageView android:id="@+id/imgView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/img01" />

<Button android:id="@+id/btnLeft" android:layout_width="100dp" android:layout_height="wrap_content"

android:layout_gravity="bottom|left"

android:text="←" android:textSize="24sp" />

... (省略) ...

どこにアンカーを置くかがポイントになります

アンカーを明示しないと左上に配置されます

Page 13: Android Lecture #04 @PRO&BSC Inc

各種テスト

ツール 概要

junit.framework.TestCase ①単体試験 (主な対象: ロジック)

android.test.ActivityInstrumentationTestCase2 ②結合試験 (主な対象: UI)

Monkey Runner ③安定化試験 (主な対象: メモリリーク)

Page 14: Android Lecture #04 @PRO&BSC Inc

テストプロジェクトの追加

• Androidプロジェクト作成時に追加できます

14

Page 15: Android Lecture #04 @PRO&BSC Inc

サンプル(SimpleCalc)の用意①

15

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="horizontal" > <EditText android:id="@+id/editNum1" android:layout_width="68dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center" android:inputType="number" /> <LinearLayout android:layout_width="48dp" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:id="@+id/btnAdd" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="+" android:textSize="22sp" /> <Button android:id="@+id/btnSub" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="-" android:textSize="22sp" />

<Button android:id="@+id/btnMul" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="×" android:textSize="22sp" /> <Button android:id="@+id/btnDiv" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="÷" android:textSize="22sp" /> </LinearLayout> <EditText android:id="@+id/editNum2" android:layout_width="68dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center" android:inputType="number" /> <TextView android:layout_width="48dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center" android:text="=" android:textSize="22sp" /> <EditText android:id="@+id/editAnswer" android:layout_width="68dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:editable="false" android:gravity="center" /> </LinearLayout> ・res/layout/main.xml

Page 16: Android Lecture #04 @PRO&BSC Inc

16

サンプル(SimpleCalc)の用意② package jp.probsc.simplecalc;

/** *計算クラス */ public class Calculator { /** 足し算 */ public static int Add(int a, int b) { return a + b; }

/** 引き算 */ public static int Sub(int a, int b) { return a - b; }

/** 掛け算 */ public static int Mul(int a, int b) { return a * b; }

/** 割り算 */ public static double Div(int a, int b) { return a / b; } }

・src/.../Calculator.java

Page 17: Android Lecture #04 @PRO&BSC Inc

package jp.probsc.simplecalc;

import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText;

/** * シンプル電卓クラス */ public class MainActivity extends Activity { /** * onCreate コールバックメソッド */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);

// ウィジェットの初期化 init(); }

/** * ウィジェットの初期化 */ private void init() { final EditText num1 = (EditText)findViewById(R.id.editNum1); num1.setSelectAllOnFocus(true);

final EditText num2 = (EditText)findViewById(R.id.editNum2); num2.setSelectAllOnFocus(true);

final EditText numAnswer = (EditText)findViewById(R.id.editAnswer);

Button btnAdd = (Button)findViewById(R.id.btnAdd); btnAdd.setOnClickListener(new OnClickListener() { public void onClick(View v) { int ret = Calculator.Add( escape(num1), escape(num2)); numAnswer.setText(String.valueOf(ret)); } }); }

/** * EditText をエスケープして整数値を返す * * @param target エスケープ対象の EditText ウィジェット * @return 整数値 */ public static int escape(EditText target) { try { return Integer.parseInt(target.getText().toString()); } catch (Exception ex) { target.setText("0"); return 0; } } } 17

サンプル(SimpleCalc)の用意③

・src/.../MainActivity.java

Page 18: Android Lecture #04 @PRO&BSC Inc

サンプル(SimpleCalc)の完成 • ソース

– サンプルプロジェクト

• http://goo.gl/SQ0LW

– テストプロジェクト

• http://goo.gl/KM1bW

• この四則演算を行うアプリのテストを行います。試験は下記の4種類です – ① 単体試験

– ② 結合試験

– ③ 安定化試験 18

Page 19: Android Lecture #04 @PRO&BSC Inc

単体試験の準備

• ロジックを試験します

– テストプロジェクトに「CalculatorTest.java」を追加

19

①単体試験

package jp.probsc.simplecalc.test; import jp.probsc.simplecalc.Calculator; import junit.framework.TestCase; public class CalculatorTest extends TestCase { public void testAdd() { assertEquals(0, Calculator.Add(0, 0)); assertEquals(1, Calculator.Add(1, 0)); assertEquals(2, Calculator.Add(2, 0)); assertEquals(1, Calculator.Add(0, 1)); assertEquals(2, Calculator.Add(0, 2)); assertEquals(2, Calculator.Add(1, 1)); assertEquals(4, Calculator.Add(2, 2)); } }

Page 20: Android Lecture #04 @PRO&BSC Inc

単体試験の実施 • クラスを右クリックし、[実行(R)]-[Android JUnit Test]を実行

①単体試験

20

1つでもパスしないテストケースがあると、バーが赤色になります

テスト実施はテストケース(メソッド)ごと、クラスごと、プロジェクトごとの単位にて実施できます。

Page 21: Android Lecture #04 @PRO&BSC Inc

結合試験の準備 • UIを試験します ※テストプロジェクトに「MainActivityTest.java」を追加

21

②結合試験

package jp.probsc.simplecalc.test; import android.test.ActivityInstrumentationTestCase2; import android.widget.Button; import android.widget.EditText; import jp.probsc.simplecalc.MainActivity; public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> { public MainActivityTest() { super(MainActivity.class); } public void testCalc() { final EditText num1 = (EditText)getActivity().findViewById( jp.probsc.simplecalc.R.id.editNum1); final EditText num2 = (EditText)getActivity().findViewById( jp.probsc.simplecalc.R.id.editNum2); final Button btnAdd = (Button)getActivity().findViewById( jp.probsc.simplecalc.R.id.btnAdd);

getInstrumentation() .waitForIdleSync(); getActivity().runOnUiThread( new Runnable() { public void run() { num1.setText("2"); num2.setText("4"); btnAdd.performClick(); } }); getInstrumentation() .waitForIdleSync(); EditText numAnswer = (EditText) getActivity().findViewById( jp.probsc.simplecalc.R.id.editAnswer); assertEquals("6", numAnswer.getText().toString()); } }

Page 22: Android Lecture #04 @PRO&BSC Inc

結合試験の実施

• テストプロジェクトを選択して [実行 (R)]-[Android JUnit Test] を実行することで、先ほどの単体試験と同時にテストを実施できます

22

②結合試験

UIのテストは実機、またはエミュレータ上で実行されます。

Page 23: Android Lecture #04 @PRO&BSC Inc

Monkey Runner の利用

23

#!/usr/bin/python # coding: UTF-8 from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice import datetime # 日時文字列の取得 def getDate(): d = datetime.datetime.today() return d.strftime('%Y%m%d_%H%M%S') # スナップショットの取得 # (monkeyrunner.bat と同階層に snapshot フォルダを準備のこと) def snapshot(device): MonkeyRunner.sleep(1) result = device.takeSnapshot() result.writeToFile( 'snapshot/%s.png' % getDate(), 'png') # テスト初期化 def init(): device = MonkeyRunner.waitForConnection() device.startActivity( component='jp.probsc.simplecalc/.MainActivity') return device # 標準出力へメッセージを出力 def printMsg(msg): print '[%s] %s' % (getDate(), msg)

# テストの実施 def doTest(): device = init() snapshot(device) for i in range(1, 1001): printMsg('cnt: %d' % i) # 1つめの数値を入力 MonkeyRunner.sleep(1) device.touch(65, 215, 'DOWN_AND_UP') device.type('%d' % i) # 2つめの数値を入力 MonkeyRunner.sleep(1) device.touch(240, 215, 'DOWN_AND_UP') num = i * 2 device.type('%d' % num) # 「+」ボタンを押下 MonkeyRunner.sleep(1) device.touch(155, 110, 'DOWN_AND_UP') snapshot(device) # テストの開始 printMsg('test start.') doTest() printMsg('test end.')

mr_simplecalc.py

③安定化試験

Pythonスクリプトです

Page 24: Android Lecture #04 @PRO&BSC Inc

Monkey Runner の実行結果

c:¥> c:¥>C:¥android¥android-sdk-windows¥tools¥monkeyrunner.bat C:¥mr_simplecalc.py [20120318_145102] test start. [20120318_145117] cnt: 1 [20120318_145132] cnt: 2 [20120318_145148] cnt: 3 [20120318_145201] cnt: 4 [20120318_145215] cnt: 5 ...

24

・コマンドプロンプトに下記コマンドを入力してMonkey Runnerを起動します

・monkeryrunner.bat と同階層の snapshot フォルダに下記が保存されます

③安定化試験

今回のスクリプトの場合、1000回の足し算が自動的に実行されます。別途、メモリ使用状況などを監視してアプリの安定化を図ります

Page 25: Android Lecture #04 @PRO&BSC Inc

よりテストを実施しやすくするために

• 今回ご紹介したUIテストとMonkey Runnerでは、ウィジェットのIDや画面上の座標を知っている必要があり、「OKボタンを押す」などの直観的なテストをかけない...

• これまでJavaのプロジェクトではもっくオブジェクトを使って試験を行えたが、AndroidはVMが異なるため、既存ツールを利用できない...

25

NativeDriver や Scirocco などのツールの利用が便利です!

EasyMock の知識を Android Mock に活かせます!

Page 26: Android Lecture #04 @PRO&BSC Inc

• イメージビューアの改善

–縦画面と横画面のそれぞれに異なる1つ以上のアニ

メーションを追加しましょう

– メニューに1つ以上の独自の機能を追加しましょう

• SimpleCalc とテストの改善

– SimpleCalc に足し算以外の機能を追加しましょう

– テストプロジェクトに足し算以外の機能のテストケース

を追加しましょう 26

本日の課題