トップ 追記

Ussy Diary

検索キーワード:

2010-01-27

Android 端末のディスプレイサイズを取得する

Activity#onCreate

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Log.d("display", "w:" + display.getWidth());
Log.d("display", "h:" + display.getHeight());

実行結果

w:320
h:480

onCreate 時には、まだレイアウトの初期化が行われないため View の width/height からは 0 が返ってきます。調べてみると WindowManager を経由して取得した Display クラスから onCreate 時に取得できました。

こちらは View の onSizeChanged イベントから取得する方法です。

throw Life - Viewの幅と高さを取得する方法を考える

Tags: Android

2010-01-23

Encoding::UndefinedConversionError

Ruby 1.9 上の Sequel で sqlite3 からマルチバイト文字列を含んだレコードを取得し to_json しようとすると

Encoding::UndefinedConversionError: "\xE2" from ASCII-8BIT to UTF-8

というエラーが出力されます。

String#force_encoding で、いちいち utf-8 しないといけないのかと思ったところ、きちんと Sequel の plugin にエンコーディングを変換できるものが提供されていました。

class User < Sequel::Model
  plugin :force_encoding, 'utf-8'
end
Tags: Ruby Sequel

Sequel で保存時にタイムスタンプをつける

カラム名を created_at, updated_at にしておくと、 save メソッドを呼び出したときに自動的に作成、更新時間を更新してくれるみたいです。カラム型は timestamp で確認しています。

さらに追加時にも更新時間を入れたい場合には timestamps プラグインを利用して、オプションを渡してあげるとよいです。

DB = Sequel.connect("sqlite://test.db")

class User < Sequel::Model
  plugin :timestamps, :update_on_create => true
end

DB.transaction do
  User.new(:name => 'aaa').save
  User.new(:name => 'bbb').save
end

既存システムで、すでに別のカラム名が使われている場合には下のオプションを渡してあげると変更できます。

plugin :timestamps, :create => 'created_on', :update => 'updated_on'

Module: Sequel::Plugins::Timestamps [Sequel: The Database Toolkit for Ruby]

モデルすべてに適用したい場合は Sequel::Model で定義してあげるとよいみたいです。

class Sequel::Model
   plugin :timestamps, :update_on_create => true, :create => 'created_on', :update => 'updated_on'
end

class User < Sequel::Model; end
Tags: Ruby Sequel

2010-01-21

Sinatra(Rack) のセッションを無効にする

まずサーバーセッションを有効にするには起動ファイルである config.ru で use します。

use Rack::Session::Pool

引数にオプションをつけてセッションの有効期限を変えたりします。

あとはクライアントから呼び出されたアクション(コントローラー)で session_options に :drop オプションを渡してあげると削除されます。

get '/' do
  (session[:count] = (session[:count] || 0) + 1).to_s
end

get '/clear' do
  request.session_options[:drop] = true
end

http://localhost:4567/ をたたくとリクエストした数だけカウント数が画面に表示され、 /clear を叩いてから再度 / を叩くと、セッション ID が新たに割り当てられ 1 に戻ります。 :renew を渡すと新たなセッション ID を割り振りつつ、前の情報をマージしてくれます。

session.clear は単純に中身の Hash オブジェクトをクリアするだけで、セッション ID はそのままでした。


2010-01-17

Sequel でマイグレーション

Ruby にある軽量 ORM Sequel を簡単に触ったことはあるのですが、マイグレーションもできるということで試してみました。

インストール

$ sudo gem install rake
$ sudo gem install sequel
$ sudo gem install sqlite3-ruby

構成

+app_root/
 +Rakefile
 +db/
  +migrate/
   +001_migrate.rb
   +002_migrate.rb

001_migrate.rb

#!/usr/bin/env ruby

Class.new(Sequel::Migration) do
  def up
    create_table :users do
      primary_key :id
      varchar :name, :size => 32, :unique => true
      varchar :salt, :size => 32, :null => false
      varchar :hashed_password, :size => 64, :null => false
      varchar :mail_address, :size => 128, :null => false
      timestamp :created_at
      timestamp :updated_at
    end

    add_index :users, :name
  end

  def down
    drop_index :users, :name
    drop_table :users
  end

end

002_migrate.rb

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

Class.new(Sequel::Migration) do
  def up
    create_table :tags do
      primary_key :id
      varchar :name, :size => 32
    end

    from(:tags).insert(:name => 'あとでやる')
    from(:tags).insert(:name => '明日から本気出す')
  end

  def down
    drop_table :tags
  end

end

クラスを匿名で生成していますが、意味づけを行う場合は名前をきちんとつけたほうが良いかもしれません。

Rake は引数を渡すと ENV 変数に書き込まれるので、これでバージョンを指定できます。

Rakefile

#!/usr/bin/env ruby

require 'rubygems'
require 'rake'
require 'sequel'
require 'sequel/extensions/migration'

namespace :db do
  desc "migrate database"
  task :migrate do
    target = target.to_i if (target = ENV['target'])
    current = current.to_i if (current = ENV['current'])

    DB = Sequel.connect("sqlite://db/app.sqlite3")
    Sequel::Migrator.apply(DB, './db/migrate', target, current)
  end
end

最新版 (version 2) にする

$ rake db:migrate

バージョンを 1 に戻す

$ rake db:migrate target=3

わざわざ rake しなくても、コマンドから migrate できます。 -m でマイグレーションファイルを格納しているディレクトリを指定、 -M でバージョンを指定します。

$ sequel -m ./db/migrate sqlite://db/keyself.db -M 1

マイグレーションとは関係ありませんが、 model をつくる場合は最低限なものであればこれだけです。

user.rb

class User < Sequel::Model; end

users テーブルと関連づけられ、様々な操作が行えます。手軽にデータベースを操作したい場合に使っていきたいと思う ORM です。

Tags: ORM Ruby

2010-01-10

AIDL インターフェース引数に Parcelable 実装クラスを指定する

Android で画面操作を行っているときに電話がかかってくると、処理が停止されてしまいます。しかし停止させず処理を継続させたい場合にはサービスという概念が用意されており、これを利用することで処理をバックエンドで続けてくれるとのこと。

実装方法はいくつかあるのですが、今回は AIDL ファイルに Java インターフェースを定義して、コールバックを受け取れるバインダという種類を選択してみました。なお AIDL ファイルに記述したインターフェースは ADT によって、インターフェースを実装したクラスが自動的に生成されます。

まず AIDL ファイルに定義するインターフェースの引数、戻り値に指定できるものとして以下の制約があるとのことです。

  • プリミティブ型
  • String, List, Map, CharSequence, AIDL ファイルに定義したインターフェース
  • Parcelable インターフェースを実装したクラス

新しく Parcelable インターフェースというものが出てきたのですが、すごく適当にいうと Serializable の Android 用みたいなものです。 Java の Serializable は冗長なので、 Android ではリモート通信間に使うものには Parcelable インターフェースを実装するルールのようです。

で、今回 Parcelable インターフェースを実装した ValueObject を渡そうとしたところ意外にハマってしまったのでメモしておきます。

example.dto.Hoge クラスが Parcelable インタフェースを実装しているものとします。(インターフェース実装は省略します)

Hoge クラスと同じ example.dto パッケージに Hoge.aidl ファイルを作成します。

Hoge.aidl

package example.dto;

parcelable Hoge;

ここでは Hoge クラスが parcelable であることを宣言します。

続いてコールバックを受け取るリスナを example.service パッケージに定義します。

HogeCallbackListener.aidl

package example.service;

import example.dto.Hoge;

interface HogeCallbackListener {

    void receive(in Hoge hoge);
}

ここでは先ほど Hoge.aidl で定義した Hoge クラスを import し、インターフェースの引数に in を指定しました。なお public をつけるとおこられます。これで利用するための準備は整いました。

この後に AndroidManifest ファイルに Service を定義したり、 Activity や Service にコードを記述したりと面倒な作業が待っています。

参考

http://developer.android.com/intl/ja/guide/developing/tools/aidl.html

Tags: Android

2005|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|