妄想プログラマのらくがき帳 : 11月 2012

2012年11月20日火曜日

[Android]文字列の外部化

アプリで使用する文字列をハードコーディングせずに外部リソース化すると、以下のような利点が得られます。
  • アプリ内の文字列を一元管理できる(変更が容易になる)
  • 複数の言語に対応できる(多言語化)
文字列を変更することはよくあることので、多言語対応の予定が無くても外部リソース化しといた方が後々便利です。

文字列をリソースファイルに追加する

Androidのプロジェクトを新規作成すると、すでに文字列リソースファイルがプロジェクトに含まれています。res/values/strings.xmlがそのファイルになります。



ファイルを開くと「リソース」タブの画面(上の画像の画面)が表示されます。
この画面でも文字列をリソースファイルに追加できるのですが、文字列を追加するだけなら直接xmlファイルをいじった方が簡単なので、今回はxmlファイルを編集することにします。

「string.xml」タブを選択すると、次の画面が表示されます。



<resource></resource>の間に<string name="[string_name]">[文字列]</string>を追加します。
[string_name]にはプログラム中から文字列を参照するときの名前、[文字列]には表示する文字列を指定します。
Hello android!
↑のような要素を追加すると、プログラム中で getString(R.string.display_message) とすることで、"Hello android!"が取得できるようになります。

2012年11月15日木曜日

[VBA]VBAの実行速度を劇的にアップさせる。

最近VBAを使う機会があったので、そのときに使った実行速度向上手法を紹介します。

通常、セルの値を設定/取得する場合、以下のようなコードになります。
Sheets(1).Cells(1, 1).Value = "A"
tmp = Sheets(1).Cells(1, 1).Value
特定の列のデータを順に取得して…といった場合は、ループを使って以下のようなコードになると思います。
For i = 1 To 10
    tmp = Sheets(1).Cells(i, 1).Value
    
    'Do something
Next
この場合、ループ回数が10回なのでそれ程気になりませんが、100、200、…とループ回数が増えるに従って非常に時間が掛かるようになります。

当然、Application.ScreenUpdating = Falseにしたりしますが、それでも処理が重たい場合があります。
そのような場合、以下のようにするとループを使う箇所の処理が、ちょっぱや!になります。
'ループで処理する値を取得/設定する範囲のRangeを取得
With Sheets(1)
    Set targetRange = .Range(.Cells(1, 1), .Cells(10, 1))
End With

'Rangeのデータを配列で取得
Dim values()
values = targetRange.Value

'配列に取得したデータで処理を行う
For i = 1 To 10
 tmp = values(i, 1)

 'Do something
Next

'値を設定するときは配列をRangeに一括設定
targetRange.Value = values
たったこれだけですが、実行速度は劇的に向上します。
試しに適当な処理で処理時間を計測してみました。

以下のコードで計測した結果…
Const LoopCount = 10000

Private Sub CommandButton1_Click()
    Application.Cursor = xlWait
    Application.ScreenUpdating = False
    
    'ループ Ver
    t = Timer
    For i = 1 To LoopCount
        tmp = Sheets(1).Cells(i, 1).Value
        Sheets(1).Cells(i, 2).Value = tmp * 10
    Next
    Debug.Print ("ループで1セルずつ取得/設定 : " & (Timer - t))
    
    'Range Ver
    t = Timer
    With Sheets(1)
        Set srcRange = .Range(.Cells(1, 1), .Cells(LoopCount, 1))
        Set dstRange = .Range(.Cells(1, 3), .Cells(LoopCount, 1))
    End With
    
    Dim values()
    values = srcRange.Value
    For i = 1 To LoopCount
        values(i, 1) = values(i, 1) * 10
    Next
    dstRange.Value = values
    
    Debug.Print ("Rangeで一括取得/設定 : " & (Timer - t))
    
    Application.ScreenUpdating = True
    Application.Cursor = xlDefault
End Sub
Debug.Print の出力結果は、

ループで1セルずつ取得/設定 : 0.4609375
Rangeで一括取得/設定 : 0.015625

なんと約30倍もの実行時間差が出ました!
実際、今までかなり時間が掛かっていた箇所を上記の方法で修正したところ、驚くほど速くなりました。
VBAで「遅いなぁ…」「もう少し速くならないかぁ…」とお悩みのあなた、この方法をぜひ試してみてください!

2012年11月12日月曜日

[Android]画面遷移を実装する。

今回は画面遷移を実装してみます。

要求仕様は次の3点。
  • メイン画面のボタンを押下すると、サブ画面に遷移する
  • サブ画面は画面中央にメッセージを表示する
  • 画面遷移の際に、メイン画面からサブ画面に対して表示するメッセージを渡す
画面遷移と画面間のデータの受け渡しを勉強するのが目的です。

まずは、サブ画面を作成します。
メニューの[ファイル] - [新規] - [その他]から[Android] - [Android Activity]を選択すると、
新規アクティビティの作成ウィザードが表示されるので、画面に各項目を入力してサブ画面の
アクティビティを作成します。

作成するサブ画面はシンプルなものなので、BlankActivityを選択し、名前をSecondActivityとしました。



「完了」ボタンを押すと、srcフォルダ下のパッケージにSecondActivity.javaが追加されます。
この時点でSecondActivityにはTextViewが配置されているので、これを使ってメッセージを表示しようと思います。
とりあえず、レイアウトエディタ画面でTextViewにid="@+id/textView"を設定しておきます。

次は、メイン画面のボタンクリックハンドラに次画面を表示するコードを記述します。
public void onClickButton(View v)
{
 Intent intent = new Intent(this, SecondActivity.class);
     startActivity(intent);
}
Intentというのは各コンポーネントを結びつける役割をするものです。
上記のようにstartActivity()に渡すことで、Intentコンストラクタの第2引数に指定したActivityを開始させることができます。

最後に、メイン画面からサブ画面にメッセージを渡します。
メイン画面側は、先ほどのボタンクリックハンドラに1行追加します。
public void onClickButton(View v)
{
 Intent intent = new Intent(this, SecondActivity.class);
 intent.putExtra("message", "Hello SecondActivity.");
     startActivity(intent);
}
putExtra()は所謂key-valueペアです。上記の場合、keyを"message"としてメッセージを格納しています。

サブ画面側は、putExtra()で格納したメッセージを取得し、画面上のTextViewに表示します。
メッセージの取得と画面への表示は、画面表示と同時に行いたいので、サブ画面のOnCreate()の中に記述します。
public void onCreate(Bundle savedInstanceState)
{
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_second);
       
 Intent intent = getIntent();
 TextView textView = (TextView)findViewById(R.id.textView);
 textView.setText(intent.getStringExtra("message"));
}
メイン画面でstartActivity()に渡したIntentは、getIntent()で取得することができます。
また、Intent.putExtra()で格納したメッセージはIntent.getStringExtra(key)で取得することができます。
上記のコードでは、先にメッセージ表示先のTextViewをidを使って取得し、Intent.getStringExtra(key)で取得した
メッセージをTextView.setText()で画面に表示しています。

これで実装完了です。
アプリを起動し、メイン画面のボタンを押下すると…



サブ画面が表示され、メイン画面から渡したメッセージが表示されました。

2012年11月6日火曜日

[Android]ボタンのクリックイベントを実装する。

UIの基本パーツであるボタン。そのボタンにクリックイベントを実装する方法です。

まずはアクティビティにボタンを配置します。
[res] - [layout]から、ボタンを配置するアクティビティのxmlファイルを開きます。



xmlファイルを開くと、レイアウトのエディット画面が表示されます。
レイアウトのエディット方法はGUIを使う方法とxmlファイルを直接編集する方法があり、
エディット画面下側にある2つのタブ([Graphical Layout]タブと[xmlファイル名]タブ)で
切り替えられます。

今回はGUIを使ってボタンを配置しました。
配置方法は簡単で、エディット画面左側のPaletteから[Form Widgets]にある[Button]を、
エディット画面上のアクティビティにドラッグ&ドロップするだけです。
位置やサイズはドロップ後にマウスで調整します。

次にボタンにクリックイベントを設定します。
VisualStudioならエディット上のボタンをクリックするだけで、
イベントハンドラのスケルトンを作成し、それをボタンのイベントハンドラとして設定してくれますが、
Androidアプリを作る時は、自前でハンドラを作成し、ボタンに設定する必要があります。
(ちょっとメンドイですね。。。)

まずはハンドラを作成します。
アクティビティのコードに下記のクリックハンドラを追加します。

public void onClickButton(View v)
{
  AlertDialog.Builder alertDialog = new AlertDialog.Builder(MainActivity.this);
     alertDialog.setTitle("タイトル");
     alertDialog.setMessage("Hello android!");
     alertDialog.show();
}

ハンドラ内ではアラートダイアログを表示しています。
次にボタンに作成したハンドラを設定します。
レイアウトのエディット画面に戻り、ボタンを選択状態にし、ボタンのプロパティを表示します。
プロパティ内のViewグループの中に「On Click」の項目があるので、そこに先ほど作成したハンドラの
メソッド名を入力します。



これでハンドラをボタンに設定することが出来ました。
プログラムを起動し、ボタンをクリックすると、アラートダイアログが表示されます。