【android】canvasでアニメーション

scheduleAtFixedRateで周期管理して、
invalidateかpostInvalidateで画面更新するのが一般的のよう。

参考:


GraphicView.java

package com.example.myapp_sample_11_canvas_animattion;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;

public class GraphicView extends View {

    private int x = 0;
    private ScheduledExecutorService ses = null;
    
    //再描画のメソッド
    private final Runnable task = new Runnable(){
        @Override
        public void run() {
            // 移動処理
            x += 1;
 
            // 画面を更新
            postInvalidate();
            
            //アニメーションを停止する
            if (x > 600) {
                onPause();
            }
        }
    };
    
    //コンストラクタ
    public GraphicView(Context context) {
        super(context);
    }
    
    public void onResume(){
        // タイマーの作成
        ses = Executors.newSingleThreadScheduledExecutor();
 
        // 一定時間ごとにRunnableの処理を実行
        //   => scheduleAtFixedRate(Runnableオブジェクト , 最初の実行時間 , 実行の周期 , 値の単位(列挙型TimeUnitの値) )
        ses.scheduleAtFixedRate(task, 0L, 5L, TimeUnit.MILLISECONDS);
    }
 
    public void onPause(){
        if (ses != null) {
			// タイマーを停止する
        	ses.shutdown();
        	ses = null;
		}
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        
        //Paint , Rectオブジェクトの生成
        Paint paint = new Paint();
        Rect rect = new Rect(100 + x, 200 , 300 + x , 400);

        //描画色の指定
        paint.setColor(Color.parseColor("#ace3d2"));
        //四角形の描画
        canvas.drawRect(rect, paint);
    }
}

追記:
onPauseを修正。アプリ終了時などにsesがnullpointerexceptionでエラーがでてしまうので、
if文にて制御した。

MainActivity.java

package com.example.myapp_sample_11_canvas_animattion;

import com.example.myapp_sample_11_canvas_animattion.R;

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

public class MainActivity extends Activity {
    
    private GraphicView graphicView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //GraphicViewのオブジェクト生成
        graphicView = new GraphicView(this);
        setContentView(graphicView);
    }

    @Override
    protected void onPause() {
        // TODO 自動生成されたメソッド・スタブ
        super.onPause();
        
        graphicView.onPause();
    }

    @Override
    protected void onResume() {
        // TODO 自動生成されたメソッド・スタブ
        super.onResume();
        
        graphicView.onResume();
    }
}

Screenshot_2013-10-28-06-12-43


【android】Log出力を簡単に行う

公式を見る通り、
例えばLog.vなどは下のような構造になっていて、

Log.v (String tag, String msg);
第一引数、第二引数、ともにString型を引数として渡す必要が有る。

ただ、場面に寄っては第二引数にString型以外のものを渡したい時がでてくると思う。
そんなとき、簡易的にLog出力を行う方法がある。
for (int i = 0; i < 100; i++) {
    //ランダムオブジェクトの生成
    Random rnd = new Random();
    //ランダム値
    int ran = rnd.nextInt(i * i + 1);
    
    Log.v("ランダム値" , "" + ran);
}
7行目のLog.vでは、int型のranを出力しようとしているので、
本来はキャストしなければならない。
が、空の文字列「””」を付加することで、
簡易的にString型として渡すことが出来る。
byte   byteEx   = 127;
short  shortEx  = 32767;
int    intEx    = 3;
double doubleEx = 2.3;
float  floatEx  = 1.40282347F;
long   longEx   = 1223372036854775807L;

Log.v("byte型"   , "" + byteEx);     //byte型: 127
Log.v("short型"  , "" + shortEx);    //short型: 32767
Log.v("int型"    , "" + intEx);      //int型: 3
Log.v("double型" , "" + doubleEx);   //double型: 2.3
Log.v("float型"  , "" + floatEx);    //float型: 1.4028234
Log.v("long型"   , "" + longEx);     //long型: 1223372036854775807
int型以外もこの方法は有効。


【android】EditTextの入力制限(1)

数値のみ入力させたい場合、xmlだけで簡単に設定できるのだけど
忘れがちなのでメモ。

android:inputType="number"
android:digits="0123456789"

一行目で数値入力のみ対応させる。
この状態だと_(アンダーバー)や-(ハイフン)も入力できてしまうので、
二行目で使用できる数を更に制限している。

入力制限については近々まとめます。。


【android】【sqlite】できるだけsql文を利用してselectする

androidのsqlite周りを最近はよく触っている。
select文を利用するときは.query()か.rawQuery()を使うのだけど、
前者は引数が大分長いのが個人的に使いづらそう…

Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) 

ここに詳しくあるけど、
要は引数でsql文のORDER BY句やGROUP BY句など指定できるというもの。
慣れたら便利かもしれないけど、可読性に難がある気が….!

なので、SQL文に慣れている人は.rawQuery()の方が直感的かもしれない。
こちらは文字通り生のSQLを扱えるよ、というメソッド。(こことか詳しいです)

.rawQuery( SQL文 , SQL文内の「?」を任意の値にかえる );

実際に指定したらこんな感じか

//DB(読出用)のオブジェクト生成
SQLiteDatabase dbRead = helper.getReadableDatabase();

//SQL文
String sql    = "SELECT `_id` FROM user_tag WHERE `tag_name` = ?";
           
//SQL文の実行
Cursor cursor = dbRead.rawQuery(sql , new String[]{tag_name});

ちなみに第二引数で指定している「?」はnullにすることもできる。
その場合は直接sqlに書いてしまえばよい。(こっちの方が分かりやすいかも)
やってることは上記のものと同じです。

//DB(読出用)のオブジェクト生成
SQLiteDatabase dbRead = helper.getReadableDatabase();

//SQL文
String sql    = "SELECT `_id` FROM user_tag WHERE `tag_name` = '" + tag_name + "'";
            
//SQL文の実行
Cursor cursor = dbRead.rawQuery(sql , null);

あとはcursorで_idの値を取得すればOK

//カーソル開始位置を先頭にする
cursor.moveToFirst();

//(.moveToFirstの部分はとばして)for文を回す
for (int i = 1; i <= cursor.getCount(); i++) {
    //SQL文の結果から、必要な値を取り出す
    id = cursor.getInt(0);
    cursor.moveToNext();
}

ただ、上記は単に「_id」というカラムだけを取り出すためにcursorを使っていることになる。
無駄な気がするし、もっとスマートな方法がありそうなので、もう少し調べてみる、、