2012年4月24日火曜日

Windows7(アップグレード版)をVMware Fusionにインストールするときの注意点

VISTAを7へアップグレードしようかと思って買っておいたアップグレード版のWindows7。

でもVISTAをそのままにしておきたくなって、仮想マシンとしてMac上に64bit版のWindos7を入れようとしたら、ライセンス認証で躓いてしまった。エラーが表示されて認証が通らないのだ。

「0xC004F061: ソフトウェア ライセンス サービスで、指定されたプロダクト キーはアップグレードにのみ使用できることが判明しました。クリーン インストールには使用できません」

参考:アクティブ化でエラー 「0xC004F061: ソフトウェア ライセンス - Microsoft Answers


ポイント:Windows7をVMware上にインストールするには2回インストール作業が必要

7のアップグレード版は、XPやVISTAのプロダクトキーを入力してアップグレードとみなされるのではなく、稼働している対象OS上でアップグレード作業を行ってはじめてアップグレードとみなされる。


よって、

1. 一度、敢えてプロダクトキーを入力せずに体験版モードでWindows7をインストール
2. そのすぐ後で、そのWindos7上のROMからアップグレード版インストール作業を重ねて行う
3. 二度目のインストールの時だけ、プロダクトキーを入力する

という手順でインストールを進める必要がある。

つまり2回のインストール作業が必要で、プロダクトキーを入力するのは2回目のみだ。

VMware Fusionでは、予めプロダクトキーやユーザーアカウントを設定しておく簡易インストールが可能だが、それも敢えて行わない方がいい。プロダクトキーが要求される際に空欄でインストールを進めていることを自分で確認した方がいい。

この手順で、無事にアクティブ化が完了した)^o^(


その後、延々とモグラたたきのように、Windows Updateをかけ・・・。

最初にインストールした時は、認証エラーが出るとは思わず、散々Windows Updateをかけていたが、結局アクティブ化できずに時間を無駄にしてしまったorz。


ポイント:ライセンス認証が通ってからWindows Upadteをするべし

2012年3月13日火曜日

Notificationをタップしてギャラリーで画像を開く

画像のダウンロードが完了した際にNotificationを表示している。

Notificationをタップして確認のため画像を開くときに、標準のギャラリーで開きたいなと思って書いてみたコード。

protected void onPostExecute(String description) {
 if (error) {

  showNotification(DOWNLOAD_CANCELED,"Data download ended abnormally!", "", null);

 } else {

  //開いてみるだけなのでACTION_VIEWをセット
  Intent intent = new Intent(Intent.ACTION_VIEW);

  intent.setType("image/*");

  //ターゲットの画像URIを設定
  intent.setData(download_uri);

  //PendingIntentを作成
  PendingIntent contentIntent = PendingIntent.getActivity(myAppContext, 0, intent, 0);

  //Notificationを表示
  showNotification(DOWNLOAD_DONE, "Data download is complete!",description, contentIntent);

 }
}

private void showNotification(int mode, String contentTitle,String contentText, PendingIntent contentIntent) {

 Notification notification = null;
 long now = System.currentTimeMillis();
 switch (mode) {
 case DOWNLOADING:
  notification = new Notification(android.R.drawable.stat_sys_download, contentTitle, now);
  notification.defaults |= Notification.DEFAULT_LIGHTS;
  notification.defaults |= Notification.DEFAULT_SOUND;
  notification.flags = Notification.FLAG_ONGOING_EVENT;
  break;
 case DOWNLOAD_DONE:
  notification = new Notification(android.R.drawable.stat_sys_download_done, contentTitle,now);
  notification.flags = Notification.FLAG_AUTO_CANCEL;
  break;
 case DOWNLOAD_CANCELED:
  notification = new Notification(android.R.drawable.ic_menu_close_clear_cancel,contentTitle, now);
  notification.flags = Notification.FLAG_AUTO_CANCEL;
  break;
 }

 notification.setLatestEventInfo(myAppContext, contentTitle,contentText, contentIntent);
 notificationManager.notify(notification_id, notification);
}

Notificationをタップすると・・・

ダウンロード後の画像がギャラリーで開きます。


Notificationとギャラリーを絡めたサンプルがあまり見当たらなかったので忘備録としてメモメモ。

2012年3月9日金曜日

Cursorのclose()が原因で Attempted to access a cursor after it has been closed

Activity.managedQuery()でCursorを取得し、データ取得後にCursorをclose()していたら、close()のタイミングが悪くてRuntimeExceptionが発生。

java.lang.RuntimeException: Unable to resume activity {jp.hogehoge.test/jp.hogehoge.test.DownloadActivity}: android.database.StaleDataException: Attempted to access a cursor after it has been closed.

ソースの抜粋
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.download);

 // MediaStoreのDBを保存日の降順で検索
 Cursor cursor = managedQuery(URI, PROJECTIONS, WHERE,WHERE_PARAM, MediaStore.Images.Media.DATE_ADDED+ " desc");

 if (cursor.moveToFirst()) {
  do {
  } while (cursor.moveToNext());
 }
 cursor.close();

}// onCreate()

他のActivityを前面に出し、再度、DBからの一覧を表示した元の画面へ戻ってきたタイミングで発生する。

原因は、onCreate()の中でcursor.close()していたこと。

Activityのライフサイクルからいうと、再度前面へ戻ってきた時にonCreate()はコールされないので、DBからの一覧を取得できず「a cursor after it has been closed」となるわけだ。ごもっとも。

close()を明示的にコールしなければExceptionは発生しなくなった。


だがしかし、close()しないのはお作法として良いのか?と思い検索してみたら、Stack Overflowに参考になるポストがあった。
参考:managedQuery() vs context.getContentResolver.query() vs android.provider.something.query() - Stack Overflow

managedQuery() will use ContentResolver's query(). The difference is that with managedQuery() the activity will keep a reference to your Cursor and close it whenever needed (in onDestroy() for instance.) If you do query() yourself, you will have to manage the Cursor as a sensitive resource. If you forget, for instance, to close() it in onDestroy(), you will leak underlying resources (logcat will warn you about it.)

managedQuery() では、Activityがカーソルへの参照を保持していて必要なくなった時(onDestroy()が呼ばれた時)にクローズされる、とある。よって、明示的にclose()しなくてもよさそうだ。

ちなみに、ContentResolver.query()を使った場合は、自分で明示的にクローズしないとリークが起こるよとある。メモメモ。


managedQuery() はdeprecatedなので、本来なら使いたくないのだが、代替となるCursorLoaderはHoneycomb以上でしか使えない。

まだまだGingerbread搭載機種が発売されている現状では自分でコンパチビリティを書かないといけない。面倒なので使っていない\(^o^)/