Androidアプリリリースしました。
リリースしたはいいけど、DL数がまるで伸びないのでアピールしておく。
Instaplus
http://jp.androlib.com/android.application.com-limelabo-instaplus-pDpjD.aspx
今後の展開
- いくつか実装したい機能があるので、しばらく細かいアップデートがあると思います。
思っていること
Androidアプリをとりあえず作ろうと思ってリリースしたはいいけどあまりのDL数の少なさにへこんでいる。
後発だから厳しいのか、アプリがしょぼいのか、instapaperが思いのほか認知されていないのか?
Hello QuickAssist
ちょっと、はまったのでメモ。
Hello QuickAssistの流れ
- plugin.xmlにextentionを追加
- IQuickAssistProcessorを実装したクラスを作成する
基本的には上記だけでOK。
注意点としてはIQuickAssistProcessorの実装をしたときにデフォルトコンストラクタを作っておくこと(英語で書いてあったために見落として、結構はまった・・・)
plugin.xml
そのままですね。
<?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.4"?> <plugin> <extension point="org.eclipse.jdt.ui.quickAssistProcessors"> <quickAssistProcessor class="com.limelabo.ui.MyQuickAssist" id="com.limelabo.ui.MyQuickAssist" name="com.limelabo.ui.MyQuickAssist"> </quickAssistProcessor> </extension> </plugin>
ソース
実際に表示するには、IQuickAssistProcessor#getAssists()でIJavaCompletionProposalの配列を返さないといけないので、そのあたりも適当に実装する。
IJavaCompletionProposal#apply()はアシスタントが実行されたときの処理で、まともに実装すると結構大変そうなので、あとで書く(かも)。
package com.limelabo.ui; import org.eclipse.jdt.ui.text.java.IInvocationContext; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; import org.eclipse.jdt.ui.text.java.IProblemLocation; import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; /** * */ public class MyQuickAssist implements IQuickAssistProcessor { /** * コンストラクタ * (引数なしコンストラクタが無いと生成してくれない) */ public MyQuickAssist() { super(); } public boolean hasAssists(IInvocationContext context) { System.out.println("hasAssists"); return true; } public IJavaCompletionProposal[] getAssists(IInvocationContext context, IProblemLocation[] locations) { System.out.println("getAssists"); IJavaCompletionProposal[] assists = { new HelloCompletionProposal() }; return assists; } class HelloCompletionProposal implements IJavaCompletionProposal { @Override public int getRelevance() { // 表示順番0-100(100が一番上に表示される) return 100; } @Override public void apply(IDocument document) { // 実行時の処理 System.out.println("apply"); } @Override public String getAdditionalProposalInfo() { return null; } @Override public IContextInformation getContextInformation() { return null; } @Override public String getDisplayString() { // 表示ラベル return "Hello QuickAssist"; } @Override public Image getImage() { // アイコン return null; } @Override public Point getSelection(IDocument document) { return null; } } }
Inkscapeでエンベロープを実行するとエラーが出る
ロゴでも作るようにInkscapeを入れてみたはいいけど、エンベロープを実行すると↓のエラーが・・・
The fantastic lxml wrapper for libxml2 is required by inkex.py and therefore this extension. Please download and install the latest version from http://cheeseshop.python.org/pypi/lxml/, or install it through your package manager by a command like: sudo apt-get install python-lxml
要するに、pythonのlxmlライブラリ(?)がないといっているみたい。
lxmlのインストール(Windowsの場合)
以下のサイトからpythonをダウンロードして、インストールする。
以下のサイトからez_setup.pyを適当なのフォルダにダウンロード
以下のコマンドを実行する
easy_install lxml
終わり
最後に
結局、エンベロープは機能的に使えるようになったけど、私にはどうも使いこなせないかも・・・
クラスロードについてもう少し調べてみた
前回の記事と同様に、クラスロードに関してはVM次第な部分があるので、参考程度でお願いします。
前回からさらに
init/createdのログをみてもらうとわかるのだけれど、この時点でClassLoaderSampleがすでにクラスロードされている。
ClassLoaderSampleには、Buzz4を返すメソッドがあるにもかかわらず、Buzz4はロードされておらず、クラスロードされるのは、実際にBuzz4をnewしたときとなっている。
逆にBuzz/Buzz3はClassLoaderSampleがロードされた段階で、ClassLoaderに登録されてしまっている
ようするに
クラスがロードされるときは、自クラスを構成するクラスを全部読み込んでるわけではなく、キャストの必要なものだけがロードされているようだ。
返り値の型とreturn時の型が同じであれば、呼ぶまでは何もロードしていない。
ちなみに
フィールドでも同じ現象が起きるみたい。
また別の機会にでも検証してみようかな
環境
JDK1.6
出力結果
### init #### class limelabo.ClassLoaderSample class limelabo.ClassLoaderSample$Buzz class limelabo.ClassLoaderSample$Buzz3 #### created #### class limelabo.ClassLoaderSample class limelabo.ClassLoaderSample$Buzz class limelabo.ClassLoaderSample$Buzz3 #### Buzz3 #### class limelabo.ClassLoaderSample class limelabo.ClassLoaderSample$Buzz class limelabo.ClassLoaderSample$Buzz3 #### Buzz4 #### class limelabo.ClassLoaderSample class limelabo.ClassLoaderSample$Buzz class limelabo.ClassLoaderSample$Buzz3 class limelabo.ClassLoaderSample$Buzz4
ソースコード
package limelabo; import java.lang.reflect.Field; import java.util.Vector; public class ClassLoaderSample { public static void main(String[] args) { ClassLoader cl = ClassLoader.getSystemClassLoader(); printClassLoader("### init ####", cl); ClassLoaderSample hoge = new ClassLoaderSample(); printClassLoader("#### created ####", cl); hoge.createBuzz3(); printClassLoader("#### Buzz3 ####", cl); hoge.createBuzz4(); printClassLoader("#### Buzz4 ####", cl); } private Buzz createBuzz3() { return new Buzz3(); } private Buzz4 createBuzz4() { return new Buzz4(); } static class Buzz { } static class Buzz3 extends Buzz { } static class Buzz4 extends Buzz { } /** * @param message * @param cl */ private static void printClassLoader(String message, ClassLoader cl) { System.out.println(message); Class<?> c = cl.getClass(); // ClassLoaderまでさかのぼる for (; !ClassLoader.class.getName().equals(c.getName()); c = c.getSuperclass()) { } try { Field classesField = c.getDeclaredField("classes"); classesField.setAccessible(true); Vector<Class> classes = (Vector<Class>) classesField.get(cl); for (Class loadedClass : classes) { System.out.println(loadedClass); } } catch (Exception e) { // とりあえず無視 e.printStackTrace(); } } }
JavaでのClassLoaderの動き(まとめ)
※ソースと出力結果が間違っていたので一部修正(2010/5/11)
プロジェクトでクラスがロードされるのが遅い*1とかで調べることがあったので、実際どんな条件でロードしているのかをまとめてみた。そもそも、クラスを小さく(適切な大きさに)していればClassLoaderの動きなんて調べなくてもいいはずなんだけど、そこは大人の事情ってやつで。
ちなみに、ホントに細かい動作とかは使ってるVMとかに影響されるので100%これが正しいってわけではないと思います。
まぁ、参考までに結構動きが変わるってことがわかればいいかなと
調査方法
基本的には、事あるごとにClassLoaderからロード済みのクラスをSystem.outして、どんな感じでロードしているかを調べてみた。
流れとしては、
で、それぞれgetBuzz(int)から先の動きは以下のとおり
int | 返り値 | クラス名 | インスタンス生成方法 |
---|---|---|---|
0 | (Buzz0) | Buzz0 | コンストラクタを直接 |
1 | Buzz | Buzz1 | Buzz1.getInstance()内でBuzz1のコンストラクタ生成 |
2 | Buzz2 | Buzz2 | Buzz2.getInstance()内でBuzz2のコンストラクタ生成 |
3 | Buzz | Buzz3 | Hoge#createBuzz3()内でBuzz3のコンストラクタ生成 |
4 | Buzz4 | Buzz4 | Hoge#createBuzz4()内でBuzz4のコンストラクタ生成 |
5 | Buzz | Buzz5 | Factory.createBuzz5()内でBuzz5のコンストラクタ生成 |
6 | Buzz6 | Buzz6 | Factory.createBuzz6()内でBuzz6のコンストラクタ生成 |
7 | Buzz | Buzz7 | リフレクションによる生成 |
8 | Buzz8 | Buzz8 | リフレクションによる生成 |
結果
(0,2,4,6,8)はgetBuzz(int)の返り値Buzzと、生成時の返り値がBuzz以外のものは、Hogeがロードされた段階で(今回はHoge内にmainがあるのでまとめて呼ばれてしまっている)getBuzz(int)内で返される可能性のあるものすべてがクラスロードされている。
(3)も基本的にはHogeのクラスロード時に読み込まれるけど、メソッドが別なのでワンテンポ遅れてるっぽい
(1,5,7)は実際にメソッドがキックされたときにクラスがロードされている
(7)は生成はしているはずなのにClassLoader内に含まれていない(謎)
まとめ
リフレクションは別格だとしても、返り値は具象クラスを指定するより、抽象クラスやインターフェースを指定したほうが、最小限のクラスロードですみそう。
そのために、ファクトリーメソッドを用意してメソッド内のクラスの粒度(?)をそろえるのが良さそう。*2
以下、参考資料
環境
JDK1.6
出力結果
### init #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 #### created #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 #### getBuzz0(limelabo.Hoge$Buzz0) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 #### getBuzz1(limelabo.Hoge$Buzz1) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 #### getBuzz2(limelabo.Hoge$Buzz2) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 #### getBuzz3(limelabo.Hoge$Buzz3) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 #### getBuzz4(limelabo.Hoge$Buzz4) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 #### getBuzz5(limelabo.Hoge$Buzz5) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 class limelabo.Hoge$Facotory class limelabo.Hoge$Buzz5 #### getBuzz6(limelabo.Hoge$Buzz6) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 class limelabo.Hoge$Facotory class limelabo.Hoge$Buzz5 #### getBuzz7(limelabo.Hoge$Buzz7) #### class limelabo.Hoge class limelabo.Hoge$Buzz class limelabo.Hoge$Buzz0 class limelabo.Hoge$Buzz2 class limelabo.Hoge$Buzz4 class limelabo.Hoge$Buzz6 class limelabo.Hoge$Buzz8 class limelabo.Hoge$Buzz3 class limelabo.Hoge$Buzz1 class limelabo.Hoge$Facotory class limelabo.Hoge$Buzz5 class limelabo.Hoge$Buzz7
ソースコード
package limelabo; import java.lang.reflect.Field; import java.util.Vector; public class Hoge { public static void main(String[] args) { ClassLoader cl = ClassLoader.getSystemClassLoader(); printClassLoader("#### init ####", cl); Hoge hoge = new Hoge(); printClassLoader("#### created ####", cl); for (int i = 0; i < 8; i++) { Buzz buzz = hoge.getBuzz(i); printClassLoader("#### getBuzz" + i + "(" + buzz.getClass().getName() + ") ####", cl); } } private Buzz getBuzz(int i) { switch (i) { case 0: return new Buzz0(); case 1: // 返り値はBuzz return Buzz1.getInstance(); case 2: // 返り値はBuzz2 return Buzz2.getInstance(); case 3: // 返り値はBuzz return createBuzz3(); case 4: // 返り値はBuzz4 return createBuzz4(); case 5: // 返り値はBuzz return Facotory.createBuzz5(); case 6: // 返り値はBuzz6 return Facotory.createBuzz6(); case 7: // 返り値はBuzz return createBuzz7ByReflection(); case 8: // 返り値はBuzz8 return createBuzz8ByReflection(); default: throw new IllegalArgumentException("arg is " + i); } } private Buzz createBuzz3() { return new Buzz3(); } private Buzz4 createBuzz4() { return new Buzz4(); } static abstract class Buzz { } static class Buzz0 extends Buzz { } static class Buzz1 extends Buzz { static Buzz getInstance() { return new Buzz1(); } } static class Buzz2 extends Buzz { static Buzz2 getInstance() { return new Buzz2(); } } static class Buzz3 extends Buzz { } static class Buzz4 extends Buzz { } static class Buzz5 extends Buzz { } static class Buzz6 extends Buzz { } static class Buzz7 extends Buzz { } static class Buzz8 extends Buzz { } static class Facotory { static Buzz createBuzz5() { return new Buzz5(); } static Buzz6 createBuzz6() { return new Buzz6(); } } private Buzz createBuzz7ByReflection() { try { return (Buzz) Class.forName("limelabo.Hoge$Buzz7").newInstance(); } catch (Exception e) { // ignore } return null; } private Buzz8 createBuzz8ByReflection() { try { return (Buzz8) Class.forName("limelabo.Hoge$Buzz8").newInstance(); } catch (Exception e) { // ignore } return null; } private static void printClassLoader(String message, ClassLoader cl) { System.out.println(message); Class<?> c = cl.getClass(); // ClassLoaderまでさかのぼる for (; !ClassLoader.class.getName().equals(c.getName()); c = c.getSuperclass()) { } try { Field classesField = c.getDeclaredField("classes"); classesField.setAccessible(true); Vector<Class> classes = (Vector<Class>) classesField.get(cl); for (Class loadedClass : classes) { System.out.println(loadedClass); } } catch (Exception e) { // ignore } } }
Trac Lightningでハイライトを有効にする
Googleで検索してもなかなか見つからなかったので、一応メモ
wikiは最初からハイライトされるみたいだけど、リポジトリブラウザはされなかったので。
Trac Lightningでハイライトを有効にする(1)
Tracの設定をします。
ファイルタイプごとのmime-type
MIMEタイプ | WikiProcessors |
---|---|
application/javascript | js |
application/pdf | |
application/postscript | ps |
application/rss+xml | rss |
application/rtf | rtf |
application/x-csh | csh |
application/x-genshi | genshi |
application/x-genshi-text | genshitext |
application/x-sh | sh |
application/x-troff | nroff roff troff |
application/x-yaml | yaml yml |
application/xsl+xml | xsl |
application/xslt+xml | xslt |
image/svg+xml | svg |
image/x-icon | ico |
model/vrml | vrml wrl |
text/css | css |
text/html | htm html |
text/plain | COPYING ChangeLog INSTALLAUTHORS README RELEASE TXT text txt |
text/x-ada | ada |
text/x-asm | asm |
text/x-asp | asp |
text/x-awk | awk |
text/x-c++hdr | H HH c++hdr hh hpp |
text/x-c++src | C C++ CC c++ c++src cc cpp |
text/x-chdr | chdr h |
text/x-csharp | C# c# cs csharp |
text/x-csrc | c csrc xs |
text/x-diff | diff patch |
text/x-eiffel | e eiffel |
text/x-elisp | el elisp |
text/x-fortran | f fortran |
text/x-haskell | haskell hs |
text/x-idl | idl |
text/x-inf | inf |
text/x-ini | cfg ini |
text/x-java | java |
text/x-ksh | ksh |
text/x-lua | lua |
text/x-m4 | m4 |
text/x-mail | |
text/x-makefile | GNUMakefile Makefile make makefile mk |
text/x-objc | m mm objc |
text/x-ocaml | ml mli ocaml |
text/x-pascal | pas pascal |
text/x-perl | PL perl pl pm |
text/x-php | php php3 php4 |
text/x-psp | psp |
text/x-pyrex | pyrex pyx |
text/x-python | py python |
text/x-python-doctest | pycon |
text/x-rfc | rfc |
text/x-rst | rst |
text/x-ruby | rb ruby |
text/x-scheme | scheme scm |
text/x-sql | sql |
text/x-tcl | tcl |
text/x-tex | tex |
text/x-textile | textile txtl |
text/x-vba | bas vb vba |
text/x-verilog | v verilog |
text/x-vhdl | vhd vhdl |
text/x-zsh | zsh |
text/xml | xml |