test latex on blogspot
Method1,
following http://mathcache.appspot.com/static/docs.html
use javascript to render latex
Method2,
edit on http://www.codecogs.com/components/equationeditor/equationeditor.php
show generated image directly
yichao firstname, zeaster nickname, zhang lastname
Method1,
following http://mathcache.appspot.com/static/docs.html
use javascript to render latex
Method2,
edit on http://www.codecogs.com/components/equationeditor/equationeditor.php
show generated image directly
Labels: blog
目前Android的源代码完全开放给了社区. 由于它的开放性, 易移植性, 它将不仅仅是一个手机操作系统, 近日社区中已经有人把Android移植到Asus Eee PC 1000H以及HP mini note 2133上. 其中蓝牙和无线也可以正常驱动.
可以预见的, Android将在更多的设备上生根发芽!
对于那些希望锻炼技术的同学们, Android的源代码是一个难得的学习机会!
整套Android源代码包括2部分, 一是platform部分, 另外一个是tools部分.
git://android.git.kernel.org/platform/manifest.git
git://android.git.kernel.org/tools/manifest.git
整个Android系统是由OHA各个厂商贡献的小系统组成的一个大系统.
Platform就是这个大系统, 目前它由16个核心系统, 61个外部系统, 21个内置的android应用程序或服务组成.每个小系统的功能简介可以参考http://source.android.com/projects
tools部分就是用来管理这些小系统的工具集, 可以方便小系统各自独立开发, 或者日后替换掉某个小系统, 又可以方便的把各个小系统集成到一起.
它包括了一个repo工具, 用来更方便的管理git代码库. 一个基于Rietveld的Gerrit代码review在线工具.
'''我很想知道这2个工具名字的来历?!
难度是为了纪念Gerrit Rietveld, 这位荷兰家具设计师?!
'''
啰唆了这么多, 才回到主题上, 学习android的tips,
一个tip就是善用这个Gerrit代码review在线工具. 通过它可以查看Android的code changes以及code review过程中的代码点评. 从中可以学习很多大师们的编程技巧. 所有open changes在这里
http://review.source.android.com/
比如change-6647, http://review.source.android.com/6647
是memcached以及MogileFS的作者Brad Fitzpatrick提交的. 他希望把系统是否在24小时模式这个boolean变量缓存下来,而不是每次都调用开销比较大的方法去判断.
这是代码的diff输出
http://review.source.android.com/6647/diff/1/za3656e3b0c4d095fd434b4c6a3dd70f07501f8f3
为了缓存这个boolean变量, Brad Fitzpatrick增加了2个static变量,
private static Context m24HourLastContext = null;
private static boolean mCached24HourMode;
但Code reviewer Romain Guy 不同意这次change, 原因也记录到了Gerrit上.
因为增加的static变量m24HourLastContext会造成内存泄露, 并且Romain给了一篇介绍类似内存泄露的blog.
http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/
在这篇blog中, 可以看到更多的Android实现细节. 比如android.graphics.drawable.Drawable对象由于callback方法而对其所属android.view.View的引用, 可以更加清晰的理解为什么Android平台上会出现这种内存泄露.
另外, Romain也说明了
(a)Android内置的Home Screen应用程序是如何解决Drawable对象对View的引用问题的.
(b)以及常见的2种避免类似内存泄露的方法.
Romain Guy这个同学也是个UI高手, 他学生时代在SUN参与了JDK中Swing的开发, 毕业后去了Google.
还有一些change可以反映出一些细节问题, 比如, http://review.source.android.com/6601
在Reviewer的评语中看到, 他要求能重用StringBuilder的地方绝不新建一个StringBuilder对象. 可见其对代码控制之严, 之细.
精致的软件就需要这样精致的控制.
以上这些仅仅是我看过5,6个chagnes后总结的, 相信如果阅读更多, 可以从中学习到更多的tips.
PS1,
Steve Guo同学的blog中有数十篇其工作中对android底层代码的分析, 值得推荐
http://letsgoustc.spaces.live.com/
PS2,
上面那个Dalvik中Drawable对象内存泄露的问题, 实际上是由于Dalvik默认就给Drawable增加了callback功能而引起的内存泄露.
由此联想到Sun的JDK中java.io.ObjectOutputStream的一个设计问题.
详见http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4363937
其中也是由于ObjectOutputStream默认就认为其write的objects有依赖关系而将它们都保存到一个table中, 所以在传输大量对象时, 如果不间断的调用reset方法,就会导致OutOfMemoryError.
这些JVM设计者默认就给这些类设计了超级完备的功能, 而实际上大多数情况并用不上这些功能, 比如, drawable的callback功能, ObjectOutputStream输出对象的依赖关系.
如果默认使用最简单常用的功能, 而在特殊情况下, 由调用jdk的开发人员根据实际需要配置复杂的功能, 那么不仅可以提高运行效率, 也可以降低出现OutOfMemoryError的几率.
那么为什么他们还都要往复杂上设计?!
Recently, I'm developing a website by grails.
Few days ago, I found a problem, the web server hangs after requesting the homepage.
The latest change is that the homepage is requesting 15+ articles instead of just 2 articles.
For development environment, the articles are stored in mysql.
The article is retrieved by requesting another link article controller,
and the related code in ArticleController.groovy looks like this,... ...
def article = Article.get(id) //#1
if(article){
def info = articleService.retrieveInfo(article) //#2
}
... ...
code #1, finds the article instance from mysql db.
code #2, articleService is a grails service in grails-app/services directory.
the retrieveInfo method retrieves some info from the given article instance without any db operation.
The homepage should show 15+ articles, so the code above runs 15+ times in 15+ separate http request threads.
And then the grails embedded web server jetty HANGS. no more response.
After deploy the application in tomcat, tomcat hangs too.
What's the problem?
I guess it may due to thread deadlock, but how?
First, I got the java thread dump,
//redirect console output to a fileyichao src $ grails run-app > console.txt 2>&1
//after requesting homepage, press ctrl+\ (or kill -QUIT <pid>) to generate Java thread dump.
I found many threads are waiting on and locked the same monitor 0x96c6de90.
this is the code snippet, it's btpool0-15 thread, btpool0-14~2 threads are just the same.
"btpool0-15" prio=10 tid=0x08a76800 nid=0x22e4 in Object.wait() [0x8f2f2000..0x8f2f60c0]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x96c6de90> (a org.apache.commons.pool.impl.GenericObjectPool)
at java.lang.Object.wait(Object.java:485)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:748)
- locked <0x96c6de90> (a org.apache.commons.pool.impl.GenericObjectPool)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
......
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
at ArticleController.xxxx(ArticleController.groovy:85)
......
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:295)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:503)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:827)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:511)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:210)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:379)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:361)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
the ArticleController.groovy:85 code is the code #2 above.
This time, I found that in grails, when we define "boolean transactional = true" in ArticleService.groovy.
articleService.retrieveInfo() method opens a connection even if we have no db operation.
so every single thread tries to open mysql connection twice by code #1 and #2 above.
But we are just open connection and only select data from mysql, why hangs?
The code waits at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:748)
Thanks to apache, I can easily download the source code, and the line 748 is,public Object borrowObject() throws Exception {
........
synchronized(this) {
........
switch(_whenExhaustedAction) {
........
case WHEN_EXHAUSTED_BLOCK:
try {
if(_maxWait <= 0) {
wait(); //#line 748
} else {
wait(_maxWait);
}
...........
see #line 748, we got this, in GenericObjectPool.borrowObject() method, if connections in pool exhausted, it will block.
The default active connections limit is 10, but we have 15+ thread, so all block!
Actually it should not to be like this. And Indeed it's already filed bug for apache commons dbcp 1.2.1.
The grails 1.0.3 is just using commons-dbcp-1.2.1.jar.
you can find this bug at https://issues.apache.org/jira/browse/DBCP-260
PS:
In grails, calling any methods in transactional-enabled services will try to open a db connection.
So only call methods in transactional-enabled services if they are related to db operation and really need transaction.
Put all other methods in transactional-disabled services or normal groovy in src/groovy/*.groovy files.
This resolves the problem above successfully.
BTW, The transaction is enabled by default in grails 1.0.3.
Labels: opensource, web
默哀...
使用牛博网捐款救助灾区
详情请见
http://www.bullog.cn/blogs/liuyanban/archives/136782.aspx
向军人致敬!
空15军强行空降
http://blog.sina.com.cn/s/blog_4cdb2e8301009g42.html
Labels: life
I developed two custom widgets for ZInfo.
One is called RichText that can show links with custom display text, rather than the link itself.
The other is a more powerful dialog. It will be discussed later.
Android provides a widget called TextView with auto link feature.
That means you can show this:
This is http://zeaster.com/blog/
but, how to show this:
This is my blog.
How to show a link with custom display text?
RichText helps us in this way:
RichText rt = (RichText) findViewById(R.id.rich_text);
StringBuilder sb = new StringBuilder();
sb.append("This is a demo about how to use RichText.\n");
sb.append("a custom android widegt show links with custom display text, rather than the link itself.\n");
sb.append("This is <a href='http://zeaster.com/blog'>my blog</a>\n");
sb.append("This is <a href='http://infosword.com/zinfo'>ZInfo</a>\n");
rt.setRichText(sb.toString());
With this code, you got:
SpannableString is used in RichText to show custom style.
For more details, check its source code.
ZInfo is finally released for Android Developer Challenge after our many hard working days.
It's an information sharing platform based on your contacts and location.
The video demo can be found at http://infosword.com/zinfo/video.html.
We gave a presentation about ZInfo on Beijing Open Party - Before the Rain.
It makes me the most excited that I meet a lot of open source followers.
They are very friendly, full of passion, enjoy coding! I learned a lot from them.
Special thanks to cleverpig!
He is so kind and want to sponsor us a server to host ZInfo.
And he understands us fully when we decided to put off releasing publicly recently.
It's so great to meet you guys in the community!
Labels: google, mobile, opensource
Have a try if you like unix.
Labels: blog
These days, I've been developing an application that reads and writes entries from/into Android Contacts.
Everything goes fine until I need to insert email entry into Android Contact by Contact Content Provider API.
This is how to insert a people or phone entry into contact (people, phones table):
getContentProvider().insert(People.CONTENT_URI, values);
getContentProvider().insert(Phones.CONTENT_URI, values);
That's fine according to
http://code.google.com/android/devel/data/contentproviders.html
However when I insert an email entry into contact (in contact_methods table) using:
ContentURI uri = getContentProvider().insert(ContactMethods.CONTENT_URI, values);
It just returns null, nothing inserted, and nothing shows up on logcat.
Why? the link above says it should be fine!
To find the answer, I post a thread in Google Group:
http://groups.google.com/group/android-developers/browse_thread/thread/9ed4ff7fc1338b7c
However no response.
then I have been diving into build-in Contacts Application for 2 days to find how Google used their own api.
Luckily, I got the key.
see details on my another post:
http://zeaster.blogspot.com/2007/11/how-to-decompile-dex-file-on-android_28.html
You should insert an email like this:
ContentURI uri = People.CONTENT_URI.addId(user_id).addPath("contact_methods");
ContentValues values = ...
uri = getContentResolver().insert(uri, values);
why? I guess Google should provide one same way to insert content.
That's the main inconvenience.
I guess what's even worse is Google does not provide enough docs or log warnings for this tip.
Here are the others:
2.
when insert an email for a not-created-yet user id, It's still inserted successfully.
when the user id created in the future, the user would have the email address.
I guess Google should prevent this happen.
Actually many checks Google need to do.That's really a beta SDK.
3.
The content provider API is not Object-Oriented enough.
I feel it tedious to use.
4.
Maybe this is greedy.
I hope there is API to manipulate database that's similar to ActiveRecord for Rails.
Maybe I will implement one like that if time permits.