SurfaceViewの描画処理入門

基本

キャンバスをロックして描画してキャンバスを返答することで描画するのが1セット

        // キャンバスを取得
        Canvas canvas = getHolder().lockCanvas();
        
        // 取得したCanvasで色々な描画処理
        
        // ロックを開放して描画
        getHolder().unlockCanvasAndPost(canvas);

描画の仕組み

SurfaceViewはViewと言いつつもWindowを作る。透明にする場合はWindowのTopに持ってくる必要があるため、SurfaceViewの上にViewを重ねることはできない。SurfaceViewの仕組みで上にViewを重ねたい場合はTextureViewを使えば良いらしい。詳しくは以下のリンクを参照のこと。

http://www.slideshare.net/eaglesakura/abc2014spring-final

背景を透明にする

Formatを透明にするとできる。半透明でもよい

    getHolder().setFormat(PixelFormat.TRANSLUCENT);

アニメーション

Threadを作ってあげて頑張る

        Thread animThread = new Thread(new Runnable() {
            @Override
            public void run() {
                boolean isAnimation
                while(isAnimation) {
                    // ここで基本通りcanvasLockして描画処理を書く
                    // アニメーション終わったらwhileループを抜ける
                }
            }
        });
        animThread.start();

ハードキーで音量を変更する

ハードキーで音量を変更しようとすると音を流していない状態だと着信音量が変更されてしまう。

メディアプレイヤーを作った場合、アプリが起動してる時はメディアの音量を変更したいのに着信音量が変更されてしまうのでそれでは使いにくい。

そういった場合は以下のコードを入れるだけでメディア音量を変更することができる。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // こいついれるだけでメディア音量に変わる
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
    }

android studio V1.0でメモリ使用量を変更する

macだと以下に設定ファイルがあるからココを変更する

/Applications/Android\ Studio.app/Contents/bin/studio.vmoptions

ちなみに中身はこんな感じ

-Xms1024m
-Xmx2048m
-XX:MaxPermSize=1024m
-XX:ReservedCodeCacheSize=512m
-XX:+UseCompressedOops

場所は変わってるけど、各内容は以下のURLに記載されている内容と変わらない。

http://dev.classmethod.jp/smartphone/android/android-studio-vm-options/

android studioをupdateをしたらandroidannotationが動かない場合の対処

0.9.9に上げたら動かなくなったのでちょっと修正

runProguardは使えない

minifyEnalbedを使いましょう。

// こっちに変える
// runProguard: false;
minifyEnalbed: false;

aptがビルドを通らない

androidManifestを取る時の変数が違う。aptの問題ぽい

apt {
    arguments {
        androidManifestFile variant.outputs[0].processResources.manifestFile
        resourcePackageName 'jp.co.matchingagent.cocotsure'
    }
}

英語学習ソフト「mikan」のandroid版を作ってみた

カードをフリック(スワイプ)して英単語を覚えるアプリとして「mikan」というアプリがある。

http://gigazine.net/news/20141028-mikan-1000-word-a-day/

英単語を学習するいい感じのアプリを探していたので、早速インストールしようと思ったらAndroid版がない・・・。サイトを見てみると来年の春頃実装される予定らしいのだが、こんな単純なアプリを移植するだけに時間がかかりすぎだろ。。。

来年4月まで待ちたくもないので、無ければ自分で作るしか無いと新しく「SwipeCard」というアプリを作ってみた

https://play.google.com/store/apps/details?id=com.choilabo.android.englishstudycard

「SwipeCard」と「mikan」の違いは以下

  • 10単語ごとに区切ると使いにくいのでエンドレスでカードをめくれるようにした
  • エンドレスでめくれる代わりに忘却曲線を元に効率よく記憶できる仕組みを作った
  • シェアしないと次単語がみれないとかだるいから、全部の単語を最初から見えるようにした。
  • 学習できる単語の種類を増やしてみた
    • 中学生レベル
    • 高校生レベル
    • TOEIC頻出単語

個人的には「mikan」より使いやすいアプリとして完成したんではなかろうかと思っているので宜しければ使ってみてくださいm(_ _)m

アプリ内でAndroidのテキスト読み上げ機能を使う

英語学習ソフトを作ったのだけど、どう読むのかわからなかったのでテキスト読み上げ機能を追加してみた。

使い方

テキストの読み上げにはTextToSpeechを使う

public class MainActivity extends BaseActivity {

    private TextToSpeech textToSpeech;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flick_card);

        // 第2引数はTextToSpeech.OnInitListener
        // 初期化が終わるとonInitが呼ばれる
        textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (TextToSpeech.SUCCESS == status) {
                    // 今回は英語読み上げだから英語が使えるかを確認
                    if (textToSpeech.isLanguageAvailable(Locale.ENGLISH) >= TextToSpeech.LANG_AVAILABLE) {
                        // 英語が使えるなら読み上げ言語を英語にする
                        textToSpeech.setLanguage(Locale.ENGLISH);

                        // speakで読み上げ
                        textToSpeech.speak("word", textToSpeech.QUEUE_FLUSH, null);
                    }
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        // 終了時はtextToSpeechを終了させる
        // これやらないとエラーがでる
        if (textToSpeech != null) {
            textToSpeech.stop();
            textToSpeech.shutdown();
        }
        super.onDestroy();
    }
}

まとめ

非常に簡単。ただ読み上げる声が電子音で怖い・・・。端末ごとに読み上げに使用する音声ファイルが違うので問題ない端末は人がしゃべっているように聞こえるから端末依存でしょうがないんだろうなぁ。単語の読み上げ機能が追加された「Swipe Card」。良かったら使ってね。

https://play.google.com/store/apps/details?id=com.choilabo.android.englishstudycard

PCで作成したsqliteをAndroidのアプリ内にコピーする

読み込んで値を入れていくと遅いのでコピーしてDBファイルを作ったほうよい。isImportDatabase()でfalseが返答された場合dbが作成されてないので、importDatabaseでコピーする。この例の場合はassetsにフォルダにsqliteを入れているsqliteをコピーしている。

    private class DbHelper extends SQLiteOpenHelper {
        private static final String DB_FILE_NAME = "old_db.sqlite3";
        private static final String DB_NAME = "new_db.db";
        private static final int DB_VERSION = 1;

        private Context context;
        private File newDb;

        public DbHelper(Context context) {
            super(context, DB_NAME, null, DB_VERSION);
            this.context = context;
            this.newDb = context.getDatabasePath(DB_NAME);
        }

        public boolean isImportDatabase() {
            return newDb.exists();
        }

        public boolean importDatabase() {
            if (!newDb.exists()) {
                getWritableDatabase().close();
                try {
                    copy(context.getAssets().open(DB_FILE_NAME), new FileOutputStream(newDb));
                    getWritableDatabase().close();
                    return true;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }

        private int copy(InputStream input, OutputStream output) throws IOException {
            byte[] buffer = new byte[1024 * 4];
            int count = 0;
            int n = 0;
            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, n);
                count += n;
            }
            return count;
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            super.onOpen(db);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }