OS X Mervericks の Java6 と Java7 インストール

こんにちは。
去年まで古いMacBookPro (Mac OS X v10.6 Snow Leopard) を使ってました。
Mervericksが無料で公開されているから早く Upgrade しようと思っていましたが、ある使っているツールがどうしてもうまく動作しないといわれ、自分で調べる時間がなかったのでそのままにしてました。

ということで、この記事になるのですが、ついに Upgrade したのでそれを忘れないうちに書いておきます。
※あ、古いのを使ってないで、新しいの買った方がいいとかありますが。。。

  • 準備

「mervericks java」で検索すると、Mervericks に Java7 をインストールしても Eclipse は動かないとか、 Upgrade すると Java6 がインストールされていないとか書いてあったので、試した結果、以下の準備が必要でした。

[参考]
http://d.hatena.ne.jp/paraches/20131025
http://support.apple.com/kb/HT5559?viewlocale=ja_JP

Java6

以下から2つダウンロードして順番にインストール
https://developer.apple.com/downloads/index.action
※ログインしてください。

Java for OS X 2013-005 Developer Package
java_for_os_x_2013005_dp__11m4609.dmg

Java for Mac OS X 10.6 Update 17 Developer Package
java_for_mac_os_x_10.6_update_17_dp__10m4609
※最新のものをつかってくださいね。

※もしかしたらjava_for_os_x_2013005_dp__11m4609.dmgよりこちらでダウンロードしたものがいいかも
http://support.apple.com/kb/DL1572?viewlocale=ja_JP
Java for OS X 2013-005
JavaForOSX2013-05.dmg

  • Java7

以下からダウンロードしてインストールしてください
http://www.java.com/ja/download/faq/java_mac.xml
jdk-7u51-macosx-x64.dmg
※最新のものをつかってくださいね。
※Java6 しか必要なければ特にこれ以上、読む必要はありません。

  • 設定

ここまで実施すると Java6 と Java7 がインストールされた状態になり Java7 が優先されていると思います。
ここでどちらを選択するかはこの参考のリンクを参照してください。

一応、Java6 を使う場合は、以下を実施すると Java7 の参照を Java6 にかえられます。

  1. sudo mkdir -p /Library/Internet\ Plug-Ins/disabled
  2. sudo mv /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin /Library/Internet\ Plug-Ins/disabled
  3. sudo ln -sf /System/Library/Java/Support/Deploy.bundle/Contents/Resources/JavaPlugin2_NPAPI.plugin /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin
  4. sudo ln -sf /System/Library/Frameworks/JavaVM.framework/Commands/javaws /usr/bin/javaws

そして万が一、 Java7 に再度戻したいときは、以下を実施すると Java6 の参照を Java7 に戻せます。

  1. sudo ln -sf /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/javaws /usr/bin/javaws
  2. Java7 を再インストール

  • 最後に

万が一、うまく行かない場合は、インストールしたものを削除してもう一度やってみてください。アンインストール事態は以下のコマンドでできます。
※以下のコマンドのバージョンなど確認して実行にはお気をつけ下さい。

  1. sudo rm -rf /System/Library/Java/JavaVirtualMachines/1.6.0.jdk
  2. sudo rm -rf /Library/Java/JavaVirtualMachines/1.6.0_65-b14-462.jdk
  3. sudo rm -rf /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk
  4. sudo rm -rf /System/Library/Frameworks/JavaVM.framework
  5. sudo rm -rf /System/Library/Java
  6. sudo rm -rf /Library/Java

ではでは。

SpringMVC + Freemarker でstatic method アクセス方法 - 開発Tips

こんにちは。
FreeMarkerを使っていて、いろいろTipsがあったので、備忘録を兼ねてブログを書きます。

[構成]
freemarker-2.3.18
spring-webmvc-3.1.0.RELEASE

  • Shared variables

マニュアルをみればわかる通りですが、View(HTML、XMLJSONなど)の開発には補助的な機能・関数が必要になると思います。
http://freemarker.sourceforge.net/docs/pgui_config_sharedvariables.html

  • SpringMVC+Freemarkerで関数を開発する方法です。

[参考]
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/view.html#views-freemarker
http://d.hatena.ne.jp/tm8r/20110915/1316097034

springのTemplateMethodModelExを実装すれば完了ですね。
あとは、FreeMarkerConfigurerを継承してcreateConfigurationをOverrideするか、直接、Bean定義のfreemarkerConfigのfreemarkerVariablesに設定するかですね。

さて、ただ以下の構成で使っていた遺産をそのまま使うと問題がありました。

[構成]
freemarker-2.3.16
spring-3.0.5
webwork-2.2.7
struts2ではありません!古いです!

  • Accessing static methods

マニュアルをみればわかる通りですが、既存のライブラリ/ユーティリティの使って、Viewの開発したい場合に使えます。
http://freemarker.sourceforge.net/docs/pgui_misc_beanwrapper.html#autoid_55

まずは、Spring+Freemarker+Webworkで関数を開発する方法です。

  • FreemarkerManagerを継承してpopulateContextメソッドをOverride
public class XxxFreemarkerManager extends FreemarkerManager {
	@Override
	public void populateContext(ScopesHashModel model, OgnlValueStack stack, Object action, HttpServletRequest request, HttpServletResponse response) {
		super.populateContext(model, stack, action, request, response);
		model.put("XxxConverter", new XxxUtil()); // おまけ:インスタンスクラスの設定方法
		try {
			// staticクラスをこのように設定すればOKです
			model.put("XxxUtil", BeansWrapper.getDefaultInstance().getStaticModels().get(XxxUtil.class.getCanonicalName()));
		} catch (TemplateModelException e) {
		}
	}
}

freemarkerのSimpleHashModelを継承した、webworkのScopesHashModelにputすれば完了ですね。
あとは、webwork.propertiesのwebwork.freemarker.manager.classnameにXxxFreemarkerManagerを指定すればDefaultConfiguratioがが読み込みます。
しかし、既存の構成だと、これができないので、UtilクラスをTemplateMethodModelExを継承してリファクタリングするしかありません。

さて、それでは、SpringMVC+Freemarkerの組み合わせで"Accessing static methods"を実現してみましょう 。

[参考]
FreeMarkerView#exposeHelpers の抜粋

	/**
	 * Expose helpers unique to each rendering operation. This is necessary so that
	 * different rendering operations can't overwrite each other's formats etc.
	 * <p>Called by <code>renderMergedTemplateModel</code>. The default implementation
	 * is empty. This method can be overridden to add custom helpers to the model.
	 * @param model The model that will be passed to the template at merge time
	 * @param request current HTTP request
	 * @throws Exception if there's a fatal error while we're adding information to the context
	 * @see #renderMergedTemplateModel
	 */
	protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception {
	}
  • FreeMarkerViewを継承してexposeHelpersをOverride
public class XxxFreeMarkerView extends FreeMarkerView {
	@Override
	protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception {
		super.exposeHelpers(model, request);
		// staticクラスをこのように設定すればOKです
		model.put("XxxUtil" BeansWrapper.getDefaultInstance().getStaticModels().get(XxxUtil.class.getCanonicalName()));
	}
}
  • FreeMarkerViewResolverを継承してrequiredViewClassをOverride
public class XxxFreeMarkerViewResolver extends FreeMarkerViewResolver {
	public XxxFreeMarkerViewResolver() {
		setViewClass(requiredViewClass());
	}
	@SuppressWarnings("rawtypes")
	@Override
	protected Class requiredViewClass() {
		return XxxFreeMarkerView.class;
	}
}

ということでmodelにputすればOKです。
あとは、springのbean定義で、freemarkerConfigとviewResolverを定義してあげればおしまいです。

	<bean id="freemarkerConfig"
		class="XxxFreeMarkerConfigurer">
		<property name="templateLoaderPath" value="/WEB-INF/ftl/" />
		<property name="freemarkerSettings">
			<props>
				<prop key="default_encoding">UTF-8</prop>
			</props>
		</property>
	</bean>
	<bean id="viewResolver"
		class="XxxFreeMarkerViewResolver">
		<property name="contentType" value="text/html; charset=UTF-8" />
		<property name="cache" value="false" />
		<property name="prefix" value="" />
		<property name="suffix" value=".ftl" />
		<!-- use macro -->
		<property name="exposeSpringMacroHelpers" value="true" />
	</bean>
  • 最後に。

これで、Utilクラスのリファクタリング(TemplateMethodModelExを継承)しなくてもOKとなりました。
既存のFTLでstaticメソッドを呼び出している記述もそのまま利用できます。
めでたし。

HTML entity - 文字コード

こんにちは。
Webサービスを開発していろいろ HTML entity に関してTipsがあったので、備忘録を兼ねてブログを書きます。
なお以下で半角の「&」を全角の「&」で記述しています。
それでは、早速書いてみます。

  • ホワイトスペース文字の問題。

ホワイトスペース文字とはWIKIにあります。
http://ja.wikipedia.org/wiki/Unicode%E6%96%87%E5%AD%97%E3%81%AE%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0#.E3.83.9B.E3.83.AF.E3.82.A4.E3.83.88.E3.82.B9.E3.83.9A.E3.83.BC.E3.82.B9.E6.96.87.E5.AD.97
ここで問題になったのが、 U+2028 = &#8232; と U+2029 = &#8233; です。
他にも問題になる文字があるかもしれませんが、ホワイトスペースでは上記です。

これが出力方法にもよりますが、JavaScriptに影響を与えました。
結論は、ちゃんとEscapeすればいいのです。
特に、 &#8232; と &#8233; です。

  • ホワイトスペース文字の種類詳細。

ちなみに、なにがあるのか記載しておきます。

&#9; =U+0009
http://www.fileformat.info/info/unicode/char/0009/index.htm
&#10; =U+000A
http://www.fileformat.info/info/unicode/char/000A/index.htm
&#11; =U+000B
http://www.fileformat.info/info/unicode/char/000B/index.htm
&#12; =U+000C
http://www.fileformat.info/info/unicode/char/000C/index.htm
&#13; =U+000D
http://www.fileformat.info/info/unicode/char/000D/index.htm
&#133; =U+0085
http://www.fileformat.info/info/unicode/char/0085/index.htm
&#32; =U+0020
http://www.fileformat.info/info/unicode/char/0020/index.htm
&#8232; =U+2028
http://www.fileformat.info/info/unicode/char/2028/index.htm
&#8233; =U+2029
http://www.fileformat.info/info/unicode/char/2029/index.htm

  • HTML entity のエスケープ方法。

Javaの場合、ライブラリで、apache-commons-langを使えばエスケープできます。

    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
    StringEscapeUtils.escapeHtml(new String(\u2038));
    • commons-langコード(※参考のために抜粋)

http://commons.apache.org/lang/api-2.6/index.html

    /**
     * <p>
     * Escapes the characters in the <code>String</code> passed and writes the result to the <code>Writer</code>
     * passed.
     * </p>
     * 
     * @param writer
     *            The <code>Writer</code> to write the results of the escaping to. Assumed to be a non-null value.
     * @param str
     *            The <code>String</code> to escape. Assumed to be a non-null value.
     * @throws IOException
     *             when <code>Writer</code> passed throws the exception from calls to the {@link Writer#write(int)}
     *             methods.
     * 
     * @see #escape(String)
     * @see Writer
     */
    public void escape(Writer writer, String str) throws IOException {
        int len = str.length();
        for (int i = 0; i < len; i++) {
            char c = str.charAt(i);
            String entityName = this.entityName(c);
            if (entityName == null) {
                if (c > 0x7F) {
                    writer.write("&#");
                    writer.write(Integer.toString(c, 10));
                    writer.write(';');
                } else {
                    writer.write(c);
                }
            } else {
                writer.write('&');
                writer.write(entityName);
                writer.write(';');
            }
        }
    }
  • 余談ですが、StringEscapeUtilsはいろいろあります。
    escapeJava(String) : String
    escapeJava(Writer, String) : void
    unescapeJava(String) : String
    unescapeJava(Writer, String) : void
    escapeJavaScript(String) : String
    escapeJavaScript(Writer, String) : void
    unescapeJavaScript(String) : String
    unescapeJavaScript(Writer, String) : void
    escapeHtml(String) : String
    escapeHtml(Writer, String) : void
    unescapeHtml(String) : String
    unescapeHtml(Writer, String) : void
    escapeXml(String) : String
    escapeXml(Writer, String) : void
    unescapeXml(String) : String
    unescapeXml(Writer, String) : void
    escapeCsv(String) : String
    escapeCsv(Writer, String) : void
    unescapeCsv(String) : String
    unescapeCsv(Writer, String) : void
    escapeSql(String) : String
  • 最後に。

どんなときも文字コード対策は悩みの種ですね。
マルチバイドの国に生まれたために、表現豊かな文章は魅力ですが、プログラミングでは不毛な悩みが多いですね。
もっと便利なプログラミング言語を開発しろってことなのかもしれませんが。。。

Android ImageView - 開発Tips

こんにちは。

Android AppのImageViewを使って開発していろいろTipsがあったので、備忘録を兼ねてブログを書きます。

参考にしたのはこちらです。
http://d.hatena.ne.jp/komamitsu/20101209/1291907044
http://mtnk.org/down/PDF/OutOfMemoryError.pdf
http://d.hatena.ne.jp/hyoromo/20101001/1285943744
http://www.hoge256.net/2009/08/432.html
http://319ring.net/blog/archives/1269
http://lablog.lanche.jp/archives/192
http://d.hatena.ne.jp/hdk_embedded/20100518/1274121081
http://groups.google.com/group/android-group-japan/browse_thread/thread/fa40fe4d250541f5
http://ameblo.jp/yolluca/entry-10725668557.html

それでは早速書いてみます。

  • 画像読み込み中のアニメーションは、layoutでProgressBarを定義する。

ProgressBarを定義したものをLinearLayoutでincludeしましょう。
画像取得が終わったら、LinearLayoutのVisibilityをView.GONEにしてしまいましょう。
インターネットで、ViewFlipperで制御するやり方がありますが、Visibilityの制御とコストは変わらないので、ViewFlipperのViewを使うのとLinearLayoutのViewを使うのとでは、さまざまなコストが悪い気がします。
なので、Visibilityを制御するやり方が個人的にはしっくりきています。

  • 外部サイトの画像を表示する場合は、AsyncTaskが必須。

AsyncTaskにはConcurrentHashMap>でURLをキーにTask管理を行いました。
BitmapにはハードキャッシュのLinkedHashMapとソフトキャッシュのConcurrentHashMap>を使いました。
もちろんキーはURLです。
ハードキャッシュは、画像サイズを考えて、保持Bitmapデータ件数を調整しました。
ソフトキャッシュは、LinkedHashMap#removeEldestEntryのタイミングでハードキャッシュからソフトキャッシュに移動させてます。
あと、ListViewで画像表示する場合は、ListView#getViewで取得するViewに対して、setTagでModelクラスを設定しました。
そのModelクラスにBitmapを保持させてます。
このModelのBitmapの管理は、TaskのonCancelledが呼ばれたら、ModelのBitmapに対して、nullチェック、recycledチェックを行い、Bitmap#recycleを実施しました。

  • 外部サイトの画像を取得する際のBitmapFactory#decodeStramにはBitmapFactory.OptionsのinPurgeable = trueを設定して呼び出すといい。

このあたりは、上記の対策を含め、さまざまな箇所で、Bitmapのメモリ開放を実施して、OutOfMemory対策をするのがいいと思いました。

ちなみに、外部サイトから取得した画像データの0以下のデータはFilterInputStream#skipでスキップし読み込んでいます。

  • ListViewでのImageViewの取得をAsyncTaskにした場合は、ArrayAdapter#notifyDataSetChangedの呼び出しが必要。

これを行わないと、データ更新が行われません。
他の箇所でもViewの表示制御や更新、削除があった場合は、ArrayAdapter#notifyDataSetChangedは明示的に呼び出すようにしたほうがいいと思いました。

  • 最後に。

TODOは近いうちにチャレンジする機会があればやりたいですね。

  1. 画像とTaskキャッシュ機能を抽象化させて、公開したい。

Android ListView - 開発Tips

こんにちは。

Android AppのListViewを使って開発していろいろTipsがあったので、備忘録を兼ねてブログを書きます。

参考にしたのはこちらです。
http://blog.tappli.com/article/36222638.html
http://techbooster.jpn.org/andriod/ui/2979/
http://yaino.com/gzudoc2/0001/000108.html
http://d.hatena.ne.jp/poyonshot/20110224/1298556195
http://blog2.kojin.biz/2010/02/24/android%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA%E3%81%A7%E3%81%AE%E6%82%A9%E3%81%BF%E4%BA%8B%E3%81%9D%E3%81%AE%EF%BC%91/
http://www.techmaru.net/wordpress/20101123/listviewmemposition/
http://d.hatena.ne.jp/yokkong/20110426/1303805401
http://aki-ino.blogspot.com/2010/05/listview_317.html

それでは早速書いてみます。

  • ListView#addFooterView/ListView#addHeaderViewとListView#getAdapterの使い方には注意が必要でした。

まずは、今回はListView#addFooterViewを使いました。
そこで、ListViewをfindViewByIdして取得したら、ListView#addFooterViewを呼び出すようにしたほうがいいと思いました。
ListView#setAdapterを呼び出す前に実行しないといけないなら、このタイミングでいいのではと思いました。

また、ListView#getAdapterですが、ListView#addFooterView/ListView#addHeaderViewを呼び出すと、返却されるインスタンスが、HeaderViewListAdapterになります。
本来ほしいのは、ArrayAdapterや開発したArrayAdapterの子クラスですよね。
ということで、HeaderViewListAdapter#getWrappedAdapterで目的のAdapterインスタンスを取得しましょう。

なお、フッターのVisibilityや表示内容を制御する場合は、ListView#getCountに気をつけましょう。
ヘッダー、フッターの分も数えて制御しないといけません。
※Item10個をAdapter#addしてもListView#addFooterViewを実行しているとListView#getCountは11を返します。

  • ArrayAdapter#addのANR対策は取得するリストの数を分けてHandlerで呼び出しました。

これは100ループしてaddするのではなく、10ループ単位にわけて、Handlerで呼び出しました。
その際の、取得する位置はView#setTagで保持するか、Activityのインスタンスフィールドで保持しましょう。

また、自動読み込みのタイミングは、OnScrollListener#onScrollStateChangedでハンドリングしました。
スクロールがとまったらOnScrollListener.SCROLL_STATE_IDLEの状態になるので、そのタイミングで、次のリスト取得を実行しました。
このタイミングで10件ずつなら、違和感なくリストデータの取得ができると思います。

ちなみに、FooterViewの状態管理(もっと見ると読み込み中)の制御は自前で普通にやりましょう。

  • ListView#setOnItemClickListenerを使いませんでした。

インターネットを検索してもよく、ItemClickイベントが発生しない事例が多いようです。
原因は、Itemの子ViewにClickイベントが発生しているためだとあり、android:focusableやandroid:focusableInTouchModeの値をfalseにすればとありますが、それでも解決できなかったです。
なので、ListViewのItemそれぞれにOnClickListenerを設定しました。
設定するタイミングは、ListView#getViewです。
その際は、該当Viewにpositionなどを保持しておいて、ハンドリングしましょう。

  • 画像のキャッシュやAsyncタスクのキャッシュなどは、finishしたときに、clearとcancelしました。

これはOutOfMemory対策です。
ちなみに画像のキャッシュとAsyncタスクのキャッシュが必要な理由は、ListView#getViewの呼び出し回数が多すぎる!
普通に、画面内に4つのリストアイテムを表示するのに、同じpositionのアイテムが4回ぐらいListView#getViewが呼ばれます。
すでに、Taskが起動している場合は、また新規でTaskを生成して、呼び出すのは非効率です。
URLをキーにTask管理が必要だと思います。
また、画像をすでに取得済みの場合は、再利用するキャッシュの仕組みをしましょう。
こちらの場合もURLをキーに画像管理が必要だと思います。

  • 自前のスクロール位置制御は制御できませんでした。

こちらもインターネット検索をみるとArrayAdapter#notifyDataSetChangedの呼び出しとListView#invalidateViewsの呼び出しをすればOKとありますが、これが有効になるのは、ArrayAdapter#add、ArrayAdapter#removeがあったときのように思います。
単純にKeyEventに対して、ListView#setSelectionFromTopやListView#setSelectionを呼び出して、ArrayAdapter#notifyDataSetChangedを呼び出しても、変化がないです。
この辺は、もっと調査が必要かもしれませんが、現時点の回答です。

  • ListView#getChildAtとListView#getItemAtPositionがnullになる。

本来あるはずのpositionを指定して、ListView#getChildAtやListView#getItemAtPositionを呼び出しても、高速にスクロールを繰り返していると、nullが返却されることがあります。
なので、その際は、必ずnullチェックをして、Viewを利用しましょう。

  • Scrollの時に色が変わってしまうのを防ぐ

単純に好みの問題ですが、嫌ならandroid:scrollingCache="false"やListView#setScrollingCacheEnabled(false)を呼び出しましょう。

  • ListViewの行の間の区切り線を変える。

android:dividerとandroid:dividerHeightで変更可能です。

  • 最後に。

TODOは近いうちにチャレンジする機会があればやりたいですね。

  1. 自前のスクロール位置制御を完璧にしたい。

Android AppWidget - 開発Tips

こんにちは。

Android AppWidgetを開発していろいろTipsがあったので、備忘録を兼ねてブログを書きます。

参考にしたのは、こちらです。
http://d.hatena.ne.jp/moto_maka/20110121/1295550864
http://y-anz-m.blogspot.com/2011/06/androidappwidget.html

それでは、早速書いてみます。

  • AlermManagerは利用しませんでした。

AlermManagerを利用するとクラスのインスタンス管理が手間なのでやめました。
1時間に1度、動作してほしかったので、そのままandroid:updatePeriodMillisを利用しました。
※仕様的にAlermManagerでServiceを使う必要があり、onEnabledとonDisabledがあってもService停止されたら制御に困るので。

  • HandlerでANR対策を実施しました。

表示するテキストのリスト情報取得は外部通信が必要だったので、onUpdateからHandlerを使いANR対策をしました。
また、処理に時間がかかるとユーザ体感が良くないので、処理をわけてHandlerを使いました。

  • onReceiveで全イベントを処理しました。

アプリを起動したりする場合も、あえて、onReceiveでイベントを受け取り、IntentでContext#startActivityを実施しました。
※PendingIntent#getBroadcastに忘れずにappWidgetIdは指定してPendingIntentを取得します。

なお、この場合は、Intent#setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)が必要でした。
また、Intentの識別にIntent#setActionやIntent#setDataを利用して、ハンドリングしました。
※AndroidManifest.xmlのreceiverのintent-filterにactionを登録するのも忘れずに。

  • appWidgetIdは自前で生成しました。

onUpdateのときしか引数でもらえないので、自前で、作成しています。
それと、同じPendingIntentでも違うIntentとして処理してほしかったからです。

  • 画像取得方法は、AsyncTaskを使わず直列にしました。

理由は、ViewFlipperのautoStartを実施すると、設定された値がすぐに表示されます。
そのとき、画像が表示されないでテキストだけ表示されて、次の表示タイミングで画像とテキストが表示されるとユーザに違和感を与えるのではと思いました。
なので、表示されるタイミングでは、画像とテキストが同時に表示されるのが望ましいと思い、直列で取得する方式にしました。

  • AppWidgetManager#updateAppWidgetは必要に応じて呼びだしました。

これは、単純に呼んだ数だけ、再描画されるので、AppWidgetが配置されるまでの間に、おかしな描画がされてしまいます。。。
不必要に呼び出すのはやめましょう。。。

  • ViewFlipperのsetAutoStartとsetFlipIntervalは呼び出せませんでした。

これは原因がいまだ分からず、layout.xmlandroid:autoStartとandroid:flipIntervalを指定することにしました。

ここにたどり着くのがやっと。
http://stackoverflow.com/questions/7117463/how-to-change-androidautostart-attribute-of-viewflipper-in-remoteviews-program

  • 最後に。

TODOは近いうちにチャレンジする機会があればやりたいですね。

  1. AppWidgetのConfigureActivityを作りたかった。
  2. 画像キャッシュは自作でなく、com.google.common.collect.MapMakerを使いたかった。

hello world

はじめまして。
エンジニアをやっているものですが、ちょっと備忘録として残すために、ブログをはじめてみます。
ジャンル問わず書いていければいいかなと思っています。
宜しくお願い致します。