ラベル 備忘録 の投稿を表示しています。 すべての投稿を表示
ラベル 備忘録 の投稿を表示しています。 すべての投稿を表示

2012年6月12日火曜日

JennkinsOnWindowsでAndroid #Jenkins









昨日に引き続きJenkinsの設定。Linuxの時と違う部分が割りとあって、案外キツイ。

まず、そもそもエミュレーターが起動しない。コレに関しては未だに原因不明。コンソールの出力を見るに


$ "F:\Program Files\Android\android-sdk/platform-tools/adb.exe" start-server
$ "F:\Program Files\Android\android-sdk/tools/emulator.exe" -snapshot-list -no-window -avd hudson_ja-JP_240_WVGA_android-10
[android] Starting Android emulator and creating initial snapshot
[android] Erasing existing emulator data...
$ "F:\Program Files\Android\android-sdk/tools/emulator.exe" -no-boot-anim -ports 57373,57374 -prop persist.sys.language=ja -prop persist.sys.country=JP -avd hudson_ja-JP_240_WVGA_android-10 -no-snapshot-load -no-snapshot-save -wipe-data -no-window
WARNING: Data partition already in use. Changes will not persist!
WARNING: SD Card image already in use: C:\Users\numanuma08\.android\avd\hudson_ja-JP_240_WVGA_android-10.avd/sdcard.img
ko:Snapshot storage already in use: C:\Users\numanuma08\.android\avd\hudson_ja-JP_240_WVGA_android-10.avd/snapshots.img
* daemon not running. starting it now on port 57206 *
* daemon started successfully

どうも、"emulator.exe"が二回呼び出されてエミュレーターが起動していなような?

とりあえず、エミュレーターの起動は置いておいて、apkファイルを吐き出すため、デバッグビルドとテストのビルドの設定を先に。


antの設定


どうやら、antの自動インストールはうまく起動しないみたい。公式サイト(http://ant.apache.org/) からant.1.8.3をダウンロードして、適当なフォルダに解凍。
Jenkinsの管理→システム設定→ant から、ANT_HOMEを設定。

バージョンがちょっと古いのは、開発機のantのバージョンに合わせているため。まあ、開発機のバージョン上げてもいいんだけども・・・。


JAVA_HOMEの設定


Windowsの環境変数%JAVA_HOME%を読みこんでくれるものと思っていたけど、どうやらそうでもないみたい。Linuxでは勝手に読み込んでくれたんだけどなぁ?

antと同じく
Jenkinsの管理→システム設定→JDK からJAVA_HOMEを設定

環境変数に注意


さて、各プロジェクトの設定に移るわけだけど、androidプロジェクトなので

android update project -p %WORKSPACE%\ProjectPath


の様に環境変数を使って、プロジェクトのパスを指定する必要がある。ただ、この時の環境変数けど

 バッチファイル:%WORKSPACE%

Jenkinsの設定:$WORKSPACE

と、Jenkinsの方はLinux,ライクな設定方法になっていた。だが、フォルダの区切り文字は\(バックスラッシュ)なので

ant でビルド の項目で、build.xml のパスを

$WORKSPACE\ProjectPath\build.xml

とする必要がある。面倒くさい...

Windowsバッチファイルのあれこれ


AndroidプロジェクトとAndroidTestプロジェクトを同じバッチファイル内でUpdateしようとするとなぜか失敗する。



これは落ちる


  • AndroidプロジェクトのUdate
  • 何か処理
  • AndroidTestプロジェクトのUpdate

としないと通らなかった。
これは通る



とは言え、まだまだ問題は残っていて、そもそもテストの実行ができないとかもう色々と・・・。

エミュレーターの実行ができない件に関しては、原因が分からない・・・。

環境完成の先は長いです・・・。

2012年6月10日日曜日

WordPressのパーマリンク

Wordpressでパーマリンク設定時に詰まったことをチョット。

どうも、.htaccessが無視されてるなー、と思ったらどうやらAllowOverrideが無効だった模様。

<Directory /var/www/html>
 AllowOverrited All
</Directory>

で解決。

メモ程度と言うことで。

2012年5月31日木曜日

[Jenkins]Androidのエミュレータが動かない[iptables]

JenkinsのAndroid Emulator Plugin を利用して、CIをしているが

今日、なぜかエミュレータが立ち上がらない不具合が発生した。


$ /var/lib/jenkins/tools/android-sdk/platform-tools/adb start-server
[android] Starting Android emulator
[android] Erasing existing emulator data...
$ /var/lib/jenkins/tools/android-sdk/tools/emulator -no-boot-anim -ports 47334,36406 -prop persist.sys.language=en -prop persist.sys.country=US -avd hudson_en-US_800_WVGA_android-8 -no-snapshot-load -no-snapshot-save -wipe-data -no-window
WARNING: Cache partition already in use. Changes will not persist!
emulator: warning: opening audio output failed

ERROR: Timeout after 5 seconds
[android] Emulator did not appear to start; giving up
$ /var/lib/jenkins/tools/android-sdk/platform-tools/adb disconnect localhost:36406
[android] Stopping Android emulator
$ /var/lib/jenkins/tools/android-sdk/platform-tools/adb kill-server
Archiving artifacts
Finished: NOT_BUILT

結局、原因はiiptablesの設定だった。

adb の待ちポートへのアクセスをlocalhostを含めて全て遮断していたためだった。

3時間くらいこれで詰まった・・・馬鹿らしい・・・。

まあ、今後同じ様な問題に出会った際の対応はこれでできたと、そうしておこう。

2012年5月27日日曜日

【Android】BluetoothChatをAndroid4.0で試す【Bluetooth】

テスト用端末はNexus S (Android4.0.4)

接続先のPC(bluecove)をサーバーに、NexsusSをクライアントとして試します。

そのままのコードを動かすと下記のような問題が発生した。

  •     ActionBarのテキストを変更できない。
  •     UUIDの初期設定が異なっている
   
そのため、コードの修正を行う。とは言え、ちょっとコメントアウトするだけだけど。

ActionBarの設定
BluetoothChat.java(252行目あたり)

 private final void setStatus(int resId) {
  final ActionBar actionBar = getActionBar();
  // actionBar.setSubtitle("un connect");
 }

 private final void setStatus(CharSequence subTitle) {
  final ActionBar actionBar = getActionBar();
  // actionBar.setSubtitle(subTitle);
 }



レイアウトのxmlを見てないからアレだけど、ActionBarが表示されてない? まあ、面倒なので出さないことにします。

UUIDの設定

 // private static final UUID MY_UUID_SECURE =
 // UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
 private static final UUID MY_UUID_SECURE = UUID
   .fromString("00001101-0000-1000-8000-00805F9B34FB");


今回はSECUREの方を変更しましたが、場合によってはINSECUREを変更かも。

サーバーのコードは、サンプルで公開されている、SPP Server Source Codeそのまま。

以上の設定でどうにか動きました。ただ、サーバーは接続が切れるまで待ち状態なのでそのへん適当に弄る必要があります。

結構面倒くさいなぁ。手持ちの端末が無いので、4.x以上でしかテストできないからアプリ作ってもほぼ自分用かな。

ゆっくりソースを読んでいきます。

2012年4月30日月曜日

BufferedReaderから、文字列を取り出す #scala

よく使いそうなんだけど、忘れそうなのでメモ。


  private def readContentString(reader: BufferedReader) = {
    def readerLocal(accumulator: StringBuilder): String = {
      reader.readLine() match {
        case null => accumulator.toString()
        case content => readerLocal(accumulator.append(content))
      }
    }
    readerLocal(new StringBuilder)
  }


accumulatorをStringにして accumulator + content

なんてことをやったら、ダメなんだろうなと最近知りました。

ループの中で文字列を連結するときに + は避けたほうが良いよという話です。

バイトコード言いよバイトコード。

2012年3月12日月曜日

ループ内でのインスタンス作成

ちょっと、釈然としない問題があったのでメモ。

Befor

for (final String imageUrl : stringlList) {
    final URL url = new URL(imageUrl);//Warning
    ...
 }


このコードだと、PMDで ループ内でインスタンスを作るのは避けてください(Avoid instantiating new objects inside loops)が表示されてしまう。 色々と解決方法を検討した結果 After

for (final String imageUrl : stringList) {
    final URL url = createURL(stringList);
   }

private URL createURL(final String url) throws MalformedURLException {
 return new URL(url);
}


とすることで警告を消すことができた。 メソッドに分けただけで、同じじゃないか・・・? 可読性とかも変わっていないような気がするし、メモリ管理の面で見ても結局はループ内でのインスタンスを作成していることに変わりは無い。 まあ、そのうちベンチマークしてみるとするか・・・。

2012年3月2日金曜日

[JUnit]DatePickerをテストケースから操作する[Android]

Androidのテストでは、ウィジェットの操作はUIのスレッドで動作させる必用があるとのこと。

今回は、DatePickerを操作する。ソースは以下。

  activity = getActivity();

  fromDate = (DatePicker) activity.findViewById(R.id.from_data);
  toDate = (DatePicker) activity.findViewById(R.id.to_data);
  activity.runOnUiThread(new Runnable() {

   @Override
   public void run() {
    // TODO Auto-generated method stub
    fromDate.init(fromY, fromM, fromD, null);
    toDate.init(toY, toM, toD, null);
   }
  });
アクティビティのインスタンスから、runOnUiThreadを使ってUIのスレッドでの動作を行わせるとのこと。

今夜はリファクタリング的なことをやって、無駄に増えていった処理用のクラスを纏めていました。


リファクタリングとは、外部から見た時の挙動が変わってはいけない、とのこと。この本に書かれていた。

多分、クラスを分ける必用があるんだろうなぁとは思うけれど、どう分ければいいのかがよく分かっていなくて、後から見返すとかなりアレなことになっていることが多い。

2012年2月24日金曜日

【Android】オブジェクトをByte配列にしたりその逆したり【作ったよ】

現在製作中のAndroidアプリでデータベースを利用することになっている。

カラムをいちいち作ってもいいんだけど、割りとクラスの構成が面倒くさいのでBlob型で保存することにした。

という訳で、オブジェクトをByte配列に変換したり戻したりするメソッドを実装しますか。

Byte配列に変換
 public byte[] toByte() {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  try {
   ObjectOutputStream oos = new ObjectOutputStream(baos);
   oos.writeObject(this);
  } catch (IOException e) {
   // TODO: handle exception
   return null;
  }
  return baos.toByteArray();
 }


バイト配列から変換
 public static Party byteToParty(byte[] b) {
  Party p = null;
  try {
   p = (Party) new ObjectInputStream(new ByteArrayInputStream(b))
     .readObject();
  } catch (OptionalDataException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (StreamCorruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return p;
 }


JUnit使って動作確認。テストケースはこれで。
 public void testToByte() {
  byte[] b = party.toByte();
  assertNotNull(b);
 }

 public void testByteToParty() {
  byte[] b = party.toByte();
  Party p = Party.byteToParty(b);
  assertEquals(p.getDate(), date);
  assertEquals(p.getTime(), time);
  assertEquals(p.getPlace(), place);
  assertEquals(p.getperson(), person);
  assertEquals(p.getKeyword(), keyword);
  assertEquals(p.getPlaceBy(), placeBy);
 }

問題なくテストを通ったから良いでしょう。

2012年2月5日日曜日

【Android】複数のメールアドレスに対して送信するIntentを作りたい

Intentから、メールを送信するのはやり方としては様々なサイトに書かれていましたが、複数のメールアドレスに対して送る方法が無かったのでメモ。

具体的には、extra data を EXTRA_EMAILに、そしてToアドレスをStringの配列にする必用があったとのこと。

参考にしたサイトはこちら

今作っているアプリは、ListViewで選択をしたメールアドレスに対してメールを送信するので

1.ArrayListにToアドレスを保存

2.配列に変換

3.putExtra

な感じ。

コードは以下。
ArrayList toList = new ArrayList();
    Intent intent = new Intent(Intent.ACTION_SEND);
    for (Member member : memberList) {
     if (member.isJoin()) {
      toList.add(member.getMail());
     }
    }
    intent.putExtra(Intent.EXTRA_EMAIL,
      (String[]) toList.toArray(new String[0]));
    intent.putExtra(Intent.EXTRA_TEXT, "メール本文");
    intent.putExtra(Intent.EXTRA_SUBJECT, "メールタイトル");
    intent.setType("message/rfc822");
    startActivity(Intent.createChooser(intent,
      "choose email client"));


当然だけど、putExtraはArrayList型を引数にしてあげても動く。お陰で詰まってた。ArrayListでも大丈夫だろう、と勘違い。

2012年1月19日木曜日

[YahooPipes!]XMLをJSONに変換したい!!


xmlよりもJsonの方が好きです。

JavaScriptからデータを持ってくるとき、XMLHttpRequestだと例のクロスドメイン問題があるからね。

動的にscriptタグを作ってJSONPとかを埋め込むと便利なんです。

しかし、割りとxmlでしかデータを配信していないサービスが存在するのもまた、事実。

という訳で、xmlをJsonに変換するサービスを作ればいいじゃないかっ!

時間もないし簡単に作りたいじゃないかっ!

なんて、探していたらYahoo!Pipesってのがあるんですね。知らなかったよ。

マッシュアップをする時には、すごく便利そう。今回使うモジュールは,
-URLInput
-URLBuilder
-FetchData

のみ。アウトプットはノーカンだろJK...

出来たパイプは下の図の通り。すっげぇ!! 何もやってない!!
今回作ったモジュールたち

JSONへの変換だとかは、YahooPipes!のデフォルトの機能を使います。

URL

パラメータ
_reader:出力形式。JSONにしましょう。
xmlurl:XMLを吐き出すURL。WebAPIだとか色々。
_callback:コールバック関数。JSONPにしたいときに。

作ったもののレベル的には、本気で大したものじゃないですね。でも、必要だったんだからしかたない。

JSONの出力もYahooPipes!の機能ではなく自作するべき。いらん情報がくっついて来ているわけだし。

まあ,当面はこれを利用することになる。改造とかはそのうち・・・そのうち・・・

2012年1月12日木曜日

timeコマンドをパイプでつなぐ

Linuxのtimeコマンドをパイプとかで繋ぎたいんだよって、話。

time ls -la | grep sys

じゃ、だめです。timeは、標準エラー出力なんだ。そこで

time ls -la 2>&1 | grep sys

でも、だめなんだ。
timeの出力をリダイレクト

を、見るまで知らなかったパイプの仕様。

>1行全て実行した後に時間が出力されるの

とのこと。そこで

(time ls -la ) 2>&1 | grep sys

とするのが正解。

覚えておいて損は無いね。

2012年1月7日土曜日

Windowsタスクスケジューラとシェルスクリプトを使って、サーバーのバックアップを自動化したい

この記事を読んだ。

>PCのバックアップやデフラグなど、ソフト側でスケジュール化できるものは自動化を優先し

あー、やっぱりバックアップは自動化するべきなんだなぁ・・・。

家のサーバーのバックアップは手動で

1. VMWareESXi上で、仮想ハードディスクをコピー

2. サブマシンにコピー

3. 外付けハードディスクにコピー

を行なっている。基本的に週一で、土曜日に行う。

手動で、しかもサブマシンはLAN外には公開していないので外出時にはバックアップを取ることができないといえば、できない。

ちょっと、問題には思っていた。

という訳で、バックアップ処理の自動化を行うべくスクリプトを書く。

今回は、Cygwin上でSSHのリモートコマンドを実行し、最終的にサブマシンにコピーする部分までを一気に行う。

外付けハードディスクは、実は常時通電をしておらず、バックアップの時のみ手動で電源を入れている。この作業の自動化は今回は見送る。

と言うか、無理なんじゃないだろうか・・・?

これが、今回用意したスクリプト
backup.sh

backup.sh
#!/bin/sh

USER_NAME=user_name
HOST_NAME=host_name_OR_ip_adress
BACKUP_CMD=vmfs/volumes/DateStore1/backup.sh

TARGETS="Server1 Server2"

STORE_DIR=/cygdrive/G

delete_old_data(){
        ssh $USER_NAME@$HOST_NAME rm -rf /vmfs/volumes/DateStore2/*
}

delete_old_data

for target in $TARGETS; do
        ssh $USER_NAME@$HOST_NAME $BACKUP_CMD $target
done

scp $USER_NAME@$HOST_NAME:~/vmfs/volumes/DateStore2/* $STORE_DIR

delete_old_data


ま、これだけですね。
$BACKUP_CMDは事前に用意したVMWareESXiで仮想ハードディスクをコピーするためのコマンド。このサイトを参考に作った。

ちなみに、参考サイトではCRONを使って自動化を行なっている。というのも、別のNFS別のサーバーにコピーしたファイルを転送しているため。

今回は、サブマシンがWindowsなのでその手段がとれない(できるけど、面倒くさい)。

Winndowsと言うことで、自動化はタスクスケジューラを使う。

コントロールパネル→管理ツール→タスクスケジューラ

”基本タスクの作成”

から、名前と説明を入力し

トリガー:毎週
    毎週:開始日、間隔、曜日を設定。

操作:プログラムの実行
    プログラムの開始:sh.exeのパスをプログラム/スクリプトに、さっき書いたスクリプトのパスを、引数の追加(オプションん)に入力。
   
これで完了ですね。

設定が正しいかどうかは、追加したタスクを選択して実行をクリックする。

これで、バックアップも自動で行えるようになりました。

あとは、アップデートかなぁ・・・?サーバーたちのアップデートは毎晩行うように設定してありますが、Windowsマシンはどうでもないので。

これは、大したことでもないでしょうね。

2012年1月5日木曜日

【Android】電話帳からメールアドレスと名前を取得する

今作っているアプリで、電話帳から登録名とメールアドレスを取得し一覧を表示する必用がある。

そこで、実装を試す。そんなに難しくないとたかをくくっていた。

なんとか、取得ができたのでメモ。

まず、失敗例





String[] Projection = { Email.DISPLAY_NAME, Email.DATA };

Cursor managedQuery = getContentResolver().query(Email.CONTENT_URI,Projectionl, null, null, null);

while (managedQuery.moveToNext()) {
 builder.append(managedQuery.getString(managedQuery.
getColumnIndex(Email.DISPLAY_NAME))).append(",").
append(managedQuery.getString(managedQuery.getColumnIndex(Email.DATA1)));
}
Log.d(TAG, builder.toString());

これを実行すると、メールアドレスの取得は出来るのだが、DISPLAY_NAMEがひたすらnullになる。それじゃあ、困る。


そこで、そもそも本当に登録名も取得できるのかを確認。

Cursor managedQuery = getContentResolver().query(Email.CONTENT_URI,
 null, null, null, null);

StringBuilder builder = new StringBuilder();
while (managedQuery.moveToNext()) {
 for (int i = 0; i < managedQuery.getColumnCount(); i++) {
  builder.append(i).append("=").append(managedQuery.getString(i));
  builder.append(",");
 }
 builder.append(managedQuery.getString(1));
 builder.append("\n");
 }
Log.d(TAG, builder.toString());

一応 i = 31 || 33 || 57 || 59

の時に、登録名を取得できていることが確認できた。

次に

builder.append(" is ").append(managedQuery.getColumnName(i));

を挟んでみて、カラムの名前を取りに行くと

i = 31 がdisplay_name

i = 32 がdisplay_name_alt

i = 57 がsort_key_alt

i = 59 がsort_key

さて、データがあるのなら話は早い。失敗例を元に実装を行う。


String[] Projection = { "display_name", Email.DATA };

Cursor managedQuery = getContentResolver().query(Email.CONTENT_URI,
 Projection, null, null, null);

StringBuilder builder = new StringBuilder();
while (managedQuery.moveToNext()) {
 builder.append(managedQuery.getString(0));
 builder.append(managedQuery.getString(1));
 builder.append("\n");
}
Log.d(TAG, builder.toString());

これで、登録した名前とメールアドレスを取得することができた。長かったぜ・・・。

ちなみに、Email.DISPLAY_NAMEの値は公式リファレンスによると、Data4 となっているらしい。

2番目の方法で、データを全部取得した時Data4は確かにnullになっていた。確かに・・・ああ、なっていたさ・・・。

2011年12月9日金曜日

PreferenceActivity でサマリを動的に変更したい。



現在作成中のアプリでは、PreferenceActivityを利用しています。

設定した値によって、表示されている項目のサマリーが変更するとステキなので、実装をします。



こういう感じで、設定項目の下に設定値を表示したい。
具体的には、項目の内容が変更されたときのリスナーを設定し、コールバックメソッドでサマリーの内容を書き換えます。

リスナーの設定を
onResume()

で行い、解除を

onPause()


で行なっています。


 SharedPreferences.OnSharedPreferenceChangeListener listener; //設定値変更時のリスナーを保存するField
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.preference_activity);
  addPreferencesFromResource(R.xml.party_preference);
  
  //省略
  listener = setOnChangeLitener();
 }
 
 //設定値変更時のリスナークラスの定義
 private SharedPreferences.OnSharedPreferenceChangeListener setOnChangeLitener() {
  return new SharedPreferences.OnSharedPreferenceChangeListener() {

   @Override
   //コールバックメソッド
   public void onSharedPreferenceChanged(
     SharedPreferences sharedPreferences, String key) {
    // TODO Auto-generated method stub
    Log.d(TAG, "value is changed");
    //全てのPreferenceに実行する
    findPreference(key).setSummary(
      sharedPreferences.getString(key, ""));
    //特定のキーの場合のみ、実行する
    if(key.equals(SEARCHBOOKS_KEY)) 
    searchbooksPref.setSummary(
      searchbooksMap.get(sharedPreferences.getString(key, ""))); }    
   }
  };
 }

 @Override
 protected void onPause() {
  // TODO Auto-generated method stub
  super.onPause();
  //登録
  getPreferenceScreen().getSharedPreferences()
    .unregisterOnSharedPreferenceChangeListener(listener);
 }

 @Override
 protected void onResume() {
  // TODO Auto-generated method stub
  super.onResume();
  //消去
  getPreferenceScreen().getSharedPreferences()
    .registerOnSharedPreferenceChangeListener(listener);
 }  

2011年11月29日火曜日

JSONGen JSON文字列からJavaのコードを作りたい

WebAPIなんかを利用する際、JSON文字列を取得し解析し、JAVAのクラスとして利用することは割とある。

データの量が少ないものならば良いが、多くなってくると自分でコードを書くのが面倒くさくなる。

そんなとき、このようなサービスがあった。


JSONGen

使い方は簡単、URLにWebAPIのリクエストを書けばいい。

折角なので試してみよう。

URLを
http://express.heartrails.com/api/json?method=getAreas

とし、パッケージ名、クラス名を適当につける。

また、Use Java 5 Genericsにチェックを付ける。


次のようなJAVAのコードが得られる。


package tets;

import java.util.List;

public class Result1{
    private Response response;

  public Response getResponse(){
  return this.response;
 }
 public void setResponse(Response response){
  this.response = response;
 }
}


package tets;

import java.util.List;

public class Response{
    private List area;

  public List getArea(){
  return this.area;
 }
 public void setArea(List area){
  this.area = area;
 }
}


これは便利。

ただし、JSONにJavaの予約語を利用している場合は注意。問答無用で変数が作られるので、困ったことになる。

その場合は、利用しているライブラリによって異なるが例えばJSONICならアンダースコアをつけることで回避できる。

何にせよ便利。