2014年9月1日星期一

给Apk瘦身

原文地址:http://t.cn/RhA02xh,这里简单总结如下。

现在apk越来越大,原因有如下几个:
  1. 多dpi支持([l|m|tv|h|x|xx|xxx]dpi)
  2. Android开发工具和生态系统的发展
  3. 为了提高用户体验的高分辨率ui设计
  4. ...
减少Apk大小的,可以从如下几个方面入手:
  • Java源代码
  • 资源文件res/assets
  • native code
保持代码卫生 :去掉不用的代码和类库,保持代码干净;
运行Proguard:proguard能够便利你所有的代码路径,把没有用到的代码重apk中剔除。并且能够重命名变量,尽量精简你的代码;
使用Lint:上面的proguard只是分析Java代码。lint工具能够分析你资源文件(/res),使用./gradlew lint就能够检测出没有用的资源文件;
合理使用资源:资源文件并不必要覆盖所有的dpi,我个人只是覆盖了hdpi、xhdpi、xxhdpi;
最小化资源配置:引入第三方库的时候,去掉你用不上的资源,例如语言翻译、图片资源,可以使用Android Gradle Plugin的resConfig来配置;
压缩图片:pngquant, ImageAlpha, ImageOptin等工具
限制架构数量:一般只要支持armabi和x86就够了
尽可能的重用:android:tint改变颜色,使用xml旋转得到不同角度的图片
代码中渲染:例如帧动画

2013年8月1日星期四

Android中实现类似iOS的SwitchButton控件

iOS的SwitchButton深入人心,也被Android上的产品设计借鉴,在Android4.0中,系统就带有原生的Switch控件了。但是在老版本的Android上,怎样实现这个功能呢?
最简单的方法就是,把SwitchButton看成是个CheckBox或者ToggleButton,直接设置button属性或者background属性就可以。








但是这样实现,并没有像iOS上那样的滑动动画效果。下面介绍两种自定义的SwitchButton的控件的开源库。
http://ankri.de/switch-button-for-android-2-3-gingerbread/ 
这篇博文中详细介绍了其实现方法,也可以下载到源代码。这个可以用手拖动开关,效果非常接近了。但是也是有缺点的,不能实现背景移动,其背景是一个ProgressDrawable。
https://github.com/Issacw0ng/SwitchButton
这个是我坚果的最完美模拟iOS效果的SwitchButton。可以实现拖动,背景也可以跟着拖动。但是代码的实现上不是那么严谨,不能调整大小,不能灵活自定义样式。

这两个的实现原理基本类似,代码也比较少,有兴趣的同学可以研究一下源代码,非常值得学习的开源项目。

2013年7月15日星期一

[Android] Context, 什么是Context

注:本文翻译自Context, What Context?,原文链接在这里,作者是Dave Smith。ps:这个网站的是设计风格非常清新。

Context可能是Android应用中最常用的元素,而它也可能是最容易误用的。
Context对象是如此常见和传递使用,它可能会很容易产生并不是你预期的情形。加载资源、启动一个新的Activity、获取系统服务、获取内部文件路径以及创建view(其实还远不止这些)统统都需要Context对象来完成。我(原文作者)想做的只是给大家提供一些Context是如何工作的见解,以及让大家在应用中更有效的使用Context的技巧。

Context的类型
并不是所有的context实例都是等价的。根据Android应用的组件不同,你访问的context推向有些细微的差别。

Application - 是一个运行在你的应用进程中的单例。在Activity或者Service中,它可以通过getApplication()函数获得,或者人和继承于context的对象中,通过getApplicationContext()方法获得。不管你是通过何种方法在哪里获得的,在一个进程内,你总是获得到同一个实例。

Activity/Service - 继承于ContextWrapper,它实现了与context同样API,但是代理这些方法调用到内部隐藏的Context实例,即我们所知道的基础context。任何时候当系统创建一个新的Activity或者Service实例的时候,它也创建一个新的ContextImpl实例来做所有的繁重的工作。每一个Activity和Service以及其对应的基础context,对每个实例来说都是唯一的。

BroadcastReciver - 它本身不是context,也没有context在它里面,但是每当一个新的广播到达的时候,框架都传递一个context对象到onReceive()。这个context是一个ReceiverRestrictedContext实例,它有两个主要函数被禁掉:registerReceiver()和bindService()。这两个函数在BroadcastReceiver.onReceive()不允许调用。每次Receiver处理一个广播,传递进来的context都是一个新的实例。

ContentProvider - 它本身也不是一个Context,但是它可以通过getContext()函数给你一个Context对象。如果ContentProvider是在调用者的的本地(例如,在同一个应用进程),getContext()将返回的是Application单例。然而,如果调用这和ContentProvider在不同的进程的时候,它将返回一个新创建的实例代表这个Provider所运行的包。

保存引用
第一个我们需要解决问题是,在一个对象或者类内部保存一个context引用,而它生命周期却超过其保存引用的对象的生命周期。例如,创建一个自定义的单例,它需要一个context来加载资源或者获取ContentProvider,从而保存一个指向当前Activiy或者Service的引用在单例中。

糟糕的单例
public class CustomManager {
    private static CustomManager sInstance;
 
    public static CustomManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new CustomManager(context);
        }
 
        return sInstance;
    }
 
    private Context mContext;
 
    private CustomManager(Context context) {
        mContext = context;
    }
}
这里的问题在于,我们不知道这个context是从哪里来的,并且如果保存一个最终指向的是Activity或者Servece的引用是并不安全的。这是一个问题,是因为一个单例在类的内部维持一个唯一的静态引用,这意味着我们的对象,以及所有其他它所引用的对象,将永远不能被垃圾回收。假如这个Context是一个Activity,我们将保存与这个Activity相关的所有的view以及其他大的对象,从而造成内存泄漏。

为了解决这个问题,我们修改单例永远只是保存Application context:

改善的单例:
public class CustomManager {
    private static CustomManager sInstance;
 
    public static CustomManager getInstance(Context context) {
        if (sInstance == null) {
            //Always pass in the Application Context
            sInstance = new CustomManager(context.getApplicationContext());
        }
 
        return sInstance;
    }
 
    private Context mContext;
 
    private CustomManager(Context context) {
        mContext = context;
    }
}
现在这个例子中,我们的Context来自哪里都没有关系,因为我们这里保存引用是安全的。Application  Context 本身就是一个单例,所以我们再创建另外一个static引用,不会造成任何内存泄漏。另外一个很好的例子是,在后台线程或者一个等待的Handler中保存Context的引用,也可以使用这样的方法。

为什么我们不能总是引用Application context呢?正如前面说的,引用Application context永远不用担心内存泄漏的问题。问题的答案,就像我在开始的介绍中说的,是因为不同context并不是等价的。

Context的能力
Conext能做的通用操作决定于这个context最初来源于哪里。下表所列的是,在应用中常见的会收到context对象的,以及对应的每种情况,它可以用于哪些地方:

ApplicationActivityServiceContentProviderBroadcastReceiver
Show a DialogNOYESNONONO
Start an ActivityNO1YESNO1NO1NO1
Layout InflationNO2YESNO2NO2NO2
Start a ServiceYESYESYESYESYES
Bind to a ServiceYESYESYESYESNO
Send a BroadcastYESYESYESYESYES
Register BroadcastReceiverYESYESYESYESNO3
Load Resource ValuesYESYESYESYESYES

注:NO1 表示Application context的确可以开始一个Activity,但是它需要创建一个新的task。这可能会满足一些特定的需求,但是在你的应用中会创建一个不标准的回退栈(back stack),这通常是不推荐的或者不是是好的实践。
NO2 表示这是非法的,但是这个填充(inflation)的确可以完成,但是是使用所运行的系统默认的主题(theme),而不是你app定义的主题。
NO3 在Android4.2以上,如果Receiver是null的话(这是用来获取一个sticky broadcast的当前 值的),这是允许的。

用户界面UI
从前面的表格中可以看到,application context有很多功能并不是合适去做,而这些功能都与UI相关。实际上,只有Activity能够处理所有与UI相关的任务。其他类别的context实例功能都差不多。

幸运的是,在应用中这三种操作基本上都不需要在Activity范围之外进行,这很可能是android框架故意这么设计的。尝试显示一个使用Aplication context创建的Dialog,或者使用Application context开始一个Activity,系统会抛出一个异常,让你的application崩溃,非常强的告诉你某些地方出了问题。

一个并不明显的问题是填充布局(inflating layout)。如果你已经读过了我(原文作者)的上一篇文章Layout inflation,你就已经知道它可能是一个非常神秘过程,伴随一些隐藏的行为。使用正确的context关系到其中的一个行为。当你使用Application context来inflate一个布局的时候,框架并不会报错,并返回一个使用系统默认的主题创建一个完美的view给你,而没有考虑你的applicaiton自定义的theme和style。这是因为Acitivity是唯一的绑定了在manifast文件种定义主题的Context。其他的Context实例将会使用系统默认的主题来inflater你的view。导致显示的结果并不是你所希望的。

规则的路口
可能有些读者已经得出两个规则互相矛盾的结论。可能有些情况下,在某些Application的设计中,我们可能既必须长期保存一个的引用,并且为了完成与UI相关的工作又必须保存一个Activity。如果出现这种情况,我将会强烈建议你重新考虑你的设计,它将是一个很好的“反框架”教材。

经验法则
绝大多数情况下,使用在你的所工作的组建内部能够直接获取的Context。只要这个引用没有超过这个组建的生命周期,你可以安全的保存这个引用。一旦你要保存一个context的引用,它超过了你的Activity或者Service的生命周期范围,甚至是暂时的,你就需要转换你的引用为Application context。


2013年4月20日星期六

每天一点差距

突然发现本来在同一个起点的人,突然发现已经不是同一个世界的人了。一步一步走下来的差距大的让人难以想象。。。

2013年1月11日星期五

【转帖】你有多少钱,我愿意嫁给你

发信人: nndbf (晴天小丫丫), 信区: Friends 标 题: 你有多少钱,我愿意嫁给你 发信站: 北邮人论坛 (Sat Nov 12 00:48:36 2011), 站内 小毛同学说,你写的帖子上“十大”了。打开网页看到这么多留言,心中惶恐。 其实,这个年代的好女孩有很多很多。 也许是媒体、电影和现实中,把“有钱、有房、有车”的结婚要求渲染地太重要了。 又或是,每个人心中都在不安:对未来的迷茫、对自己能力的质疑。 然后把这种不安投射在爱的人身上:怕Ta也对自己丧失安全感。 但生活,不是你不安,它就会眷顾你。 必须自己勇敢面对,承认自己的不足,然后扎扎实实、认认真真地努力走下去。 ——我举不出太多,只好写一个不典型的文科生的例子了———— 07年 周末出去打工发传单,早晨9点到晚上10点,站一天发出5000份才给50块钱,还要拖着笨重的腿赶公交车回学校; 每天更换学校报刊栏的报纸,一个月学校发260块,冬天必须得徒手,戴手套捻不开,每个冬天手都是冰凉冰凉的,一直到毕业; 08年 给别人的书做校对,300多万字,一个标点一个标点的反复核对3遍,拿到了不到800块钱,然后眼睛有一星期都在红肿; 给一个网站写资讯,因为跟纽约有时差,整个大二就没好好睡过几个晚上; 09年、10年 考虑后放弃了读研,绝大部分时间在校外实习,拿着实习工资,晚上时间做兼职翻译;也卖过几个不值钱的域名,1块钱注册800块卖的;当过家教,做过收银...太多了,我自己也不太记得了。 ...... 一个什么都不太懂的文科生,赚钱能力真得比你们弱爆了。 只能身兼数职、最廉价的劳动力了。 但是这4年,我负担起了自己和妹妹上大学的全部费用,外公胃癌手术一半的手术费,并且会定期打钱给家里。大学毕业第一个月,用攒下的钱和第一份正式的薪水,买了3台冰箱给两个舅舅和小姨,给家里安装了太阳能。 我没有觉得这有什么了不起,因为过去4年的每一块钱,我都赚的不容易。 而你们会写代码、会做那个、会做那个,都比我强多了。只要努力都会过得很好。 我只是想说,我们心底有最爱的人,才会有勇气面对各种不安、压力和困惑。 我们都还年轻,还有大把的光阴可以努力。 现在可能摆在面前的有很多很多困难。 忍一忍,就过去了。 也不用过于不安。 因为真正爱我们的人,永远在原地爱着我们。 【以下为帖子原文】 ——————————————————————— 马上要毕业的小毛同学,从9月开始,你进入一轮又一轮的笔试和面试。 有时候被公司鄙视了,或者感觉面的不好,你的眼神就开始躲着我。拿到不错的offer,你又喜上眉梢。 然后我又一不小心,居然一本正经地给你分析起来 ——种种加起来不过是年薪20来万而已,扣税扣金完了再交房租,其实不多。况且又不能保证解决户口...... ————————然后你就有点点沉默了———————— 你想给我一个安稳、可靠的形象。 你想多赚点钱照顾自己,照顾好家人也照顾好我。 但多数RD都要经历这么一个平平凡凡的开头。 以后或者升职加薪,或者跳槽,或者创业,或者转型......那都是后话了。 开始就是这种不痛不痒的薪水——养的活,却生活不起。 ————————所谓对的人—————————— 大概5月或者6月的时候,我在你们BYR发过一个征友的帖子。但那段时间恰好很忙:毕业、创业、回老家......所以一直就没联系站短的人。 因为工作总打交道,慢慢注意到身边还在实习的你。 从3月份一起工作过(你貌似一直都是实习生哦)到现在,也不算相处很短了吧。你总体上没有改变我对RD男的基本看法:比较单纯、实在,靠谱。 有一句特俗的话叫“在对的时间遇见对的人”。 所谓对的人,于我而言,就是那个在身边一直埋头写代码、没空抬头看我的苦逼程序猿了。o(∩_∩)o (对了,后来你说是因为你害羞。。。。。。。。) ————————RD男 能不能别这么实在———————— 貌似每个女生都觉得衣服不够穿,鞋子不够搭配......购物是女人的天性,不花钱不shopping就跟不让吃饭一样。 但你也。。太实在了。。。 去逛街买东西,你当着售货员的面跟我说,这个你买不起。。然后我当时觉得特别尴尬。。唉,小毛同学,下次能不能小声点只跟我说呀。。。o(∩_∩)o ——————————你有多少钱,我愿意嫁给你—————— 跟RD打交道挺多,基本也了解各个公司的薪资水平。 若无什么彩票砸中、创业成功之类的彩头,借鉴一下别人的经历,也能估计一下你这职业轨迹。 你要是问我,你有多少钱,我才愿意嫁给你。 我回答肯定特干脆。 你管饭么。 你管饭,我就愿意。 我说真的。你管饭么。 -- ※ 修改:·nndbf 于 Nov 13 16:53:45 2011 修改本文·[FROM: 117.79.233.*] ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 117.79.233.*]

2012年7月3日星期二

[翻译]使用U盘和git在多个电脑上共享工作

译注:因为需要频繁的在各电脑上切换,例如在实验室电脑和自己的电脑上工作,工作代码又需要在同版本控制之下。要满足这样的需求,可以使用网上免费的Git托管服务器,例如GitHub,但是免费的托管项目,又需要开源。如果有一个可以可以移动的Git服务器,问题就解决了,本文就是一个把Git服务器版本库放到U盘里面的解决方案,当然你要保证你的U盘别丢了。(第一次翻译别人的博客,翻译不正确的地方请指出。)


以下是原文翻译,原文可以在这里找到:http://timwise.blogspot.com/2008/05/sharing-work-between-computers-with-usb.html.

===
因为我在网上没有找到正好符合这个目的(使用U盘和git在多个电脑上共享工作)的解决方案,所以我做了如下的方案。

此方法可以同远程的svn服务器同时使用,如果没有的话,也可以适用。

首先,在第一个电脑上,使用git-svn clone (或者 克隆一个git库,或者新建一个工作目录),从远程代码库获取你的工作的拷贝到本地:
mkdir ~/project.git
cd ~/project.git
git-svn clone svn://project-server/trunk
git repack #for good measure
然后插上U盘,我们假设U盘是vfat/fat32/fat16格式的,并且挂载的路径为/media/flash.在U盘上创建一个空版本库,我们创建一个bare库,因为我们并不需要在此库保存工作拷贝(译注:也就是说是服务器版本库,没有工作目录)。
mkdir /media/flash/project.git
git --bare init /media/flash/project.git
然后,把U盘上的git版本库作为远程分支加到本地的git版本库中。我这里使用"flash"作为远程版分支的名字,你可以使用任何你喜欢的名字:
git remote add flash /media/flash/project.git
到这里如果你立刻push,可能会出现错误。因为fat文件系统格式在文件上并不支持可执行标记,所以所有的hook都是自动激活状态的。因为我将来并不打算使用这些hook,所以我直接删除掉所有的hook,这样做可能会产生错误,但是对我来说并没有出错。所以使用如下命令删除所有的hook:
rm /media/flash/project.git/hooks/*
然后push你的当前工作目录内容到U盘:
git push flash
此命令会复制你所有提交了的工作到U盘,即使你还没有使用"git-svn dcommit"命令push到远程的svn服务器。你还可以指定提交分支:
git push flash mybranch
现在,假设你转换到另外一个电脑上工作,插入上面的那个U盘,我们这里假设路径和设备和上面的那台电脑一样。这里做和上面完全相同的操作来从svn上克隆版本库:
mkdir ~/project.git
cd ~/project.git
git-svn clone svn://project-server/trunk
git repack #for good measure
然后添加U盘的库作为远程库,并且pull下来所有的改变:
git remote add flash /media/flash/project.git
git pull flash master
git pull flash mybranch #if you like
当你在任意一台电脑上提交了一些改变到git,或者从svn上pull了最新的版本,都可以使用如下命令更新U盘的版本库:
git push flash
然后你可以在其他电脑上,从U盘里面pull最新的版本:
git pull flash master
如果没有在push到svn之前,先向U盘中push改变,事情就非常简单。如果你向U盘中push了一些改变,然后再向SVN服务器中push,你将需最做更多一些的工作。这是因为当你运行“git svn dcommit”来push你最新的git提交日志svn服务器的时候,删除了本地的提交日志,然后从服务器上获取回来这些日志。 这意味着git将不认识你本地的改变,因为本地改变与U盘中是一样的,而有不同的提交信息和SHA1值。但你试图push到U盘的时候,将会提示 "! [rejected] master -> master (non-fast forward)",因为老版本的提交信息还在那里。 为了解决这个问题,你需要扔掉U盘上匹配的那些改变。 如下面所示使用git reset命令, 其中HEAD~1应该是你需要扔掉的提交的个数(例如,HEAD~3将扔掉U盘上你最近的3个提交):
cd /media/flash/project.git
git --bare log #to see how many changes don't have svn information
git --bare reset HEAD~1
然后你就可以正常提交了:
cd ~/project.git
git push flash

2012年6月4日星期一

把文件转换为PDF格式--JODConverter的使用

项目中需求,需要把其他文件格式转换为PDF格式,到网上找了一些解决方案。其中这里说的比较全面:http://stackoverflow.com/questions/3022376/how-to-convert-ms-doc-to-pdfhttp://ihaztehcodez.michael-lloyd-lee.me.uk/2010/10/converting-microsoft-office-word-excel.html。综合考虑通用性和效果,决定采用OpenOffice API的组件,这里有OpenOffice的SDK:http://www.openoffice.org/download/other.html#tested-sdk

后来搜索到一个开源项目,正是我所需要的:JODConverter,项目主页在这里:https://code.google.com/p/jodconverter/ 很遗憾的是,此项目作者在2011年11月份就声明停止了对此项目的维护。先下载下来此项目的文件,果然能够顺利转换格式。

1 简介
JODConverter是一个使用OpenOffice.org或者LibreOffice,自动转换文件格式的工具,支持的格式有 PDF, RTF, HTML, Word, Excel, PowerPoint, 和Flash。JODConverter可以用作Java库,或者命令行工具,或者web应用。

2 基本用法:
下载项目主页上的二进制包,解压,即可在命令行中运行:
java -jar lib/jodconverter-core-3.0-beta-4.jar test.doc test.pdf
可以把test.doc文件,转换为pdf。
在Linux下转换如果转后出现了乱码,是因为缺少了相应的字体,安装相应的字体即可。http://riches.blog.51cto.com/1167414/394610

3 文档
这里有关于JODConverter的详细文档,不过此文档是JODConverter 2.x的,但是通过此文档可以详细了解JODConverter的作用。
最准确的文档还是要参考官网:https://code.google.com/p/jodconverter/wiki/GettingStarted 和
https://code.google.com/p/jodconverter/wiki/BuildingFromSource

4 自己编译源码,运行jodconverter-sample-webapp
按照官网的提示:使用Maven编译jodconverter-core源码,但是webapp怎么编译,并没有写,从这个提问中我们可以找到答案:https://groups.google.com/group/jodconverter/browse_thread/thread/fab586c38a2f5b24。最后编译得到的.war文件,即可运行web app。


参考网址:
 1 http://stackoverflow.com/questions/3022376/how-to-convert-ms-doc-to-pdf
 2 http://ihaztehcodez.michael-lloyd-lee.me.uk/2010/10/converting-microsoft-office-word-excel.html
 3 https://code.google.com/p/jodconverter/

2012年5月14日星期一

[zz]Windows下可用msysgit下载Android源码


Windows下可用msysgit下载Android源码。
比如,要下载base:

以上两句,分别下载了Android的4.0.4_r1.1和2.3.7_r1的base项目版本。
现在Google需要Username和Password,才能下载Android源码,需要先到https://android.googlesource.com/new-password
去生成。

Android中ListView的HeadView/FooterView

在Android中,可以对ListView设置HeaderView和FooterView,其中HeadView或者FooterView并不是ListItem的一部分。

我在使用listview.addFooterView()的时候,结果并没有显示出来FooterView。后来查文档看到,说是addFooterView()的调用一定要在listiew.setAdapter()之前,果然有效。

后来在这里看到,http://stackoverflow.com/questions/4317778/hide-footer-view-in-listview,其实,只要在addAdapter()之前,任意调用了addHeaderView或者addFooterView,在setAdapter()之后调用addHeaderView都是有效的。

参考地址:
http://developer.android.com/reference/android/widget/ListView.html

http://stackoverflow.com/questions/4317778/hide-footer-view-in-listview

https://code.google.com/p/android/issues/detail?id=12870

2012年5月11日星期五

Android在layout xml中使用include

在Android的layout样式定义中,可以使用xml文件方便的实现,有时候为了模块的复用,使用include标签可以达到此目的。
例如:  <include layout="@layout/otherlayout"></div>

Android开发的官方网站的说明在这里:https://developer.android.com/resources/articles/layout-tricks-reuse.html
其中,有提到: Similarly, you can override all the layout parameters. This means that any android:layout_* attribute can be used with the <include> tag,意思是任何android:layout_*属性都可以应用在<include>标签中。

如果使用如下代码:
<relativelayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        < textview
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/somestring"
            android:id="@+id/top" />
        
       
        <include < layout="@layout/otherlayout"
       android:layout_below="@id/top" />
        
</relativelayout >
发现include的otherlayout,并没有在如我们预期的在id/top这个TextView下面,而是忽略了android:layout_below属性。经过Google发现,很多人遇到类似的问题。

有解决方法是在include的外面再包一层LinearLayout,如下:
<linearlayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/top" >
        
        < include layout="@layout/otherlayout">
</linearlayout >
解答道:必须同时重载layout_width和layout_height熟悉,其他的layout_*属性才会起作用,否这都会被忽略掉。上面的例子应该写成这样:
<include layout="@layout/otherlayout">
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:layout_below="@id/top" />


另外,关于xml的复用,还可以使用merge标签,merge标签主要是用来优化显示的,减少View树的层级,可以参考这里:https://developer.android.com/resources/articles/layout-tricks-merge.html, 翻译版在这里:http://apps.hi.baidu.com/share/detail/20871363

参考网址:



2012年3月26日星期一

毕业了

今天学校毕业典礼,也毕业了很多次了,本以为自己慢慢的麻木了,每次毕业也不禁想起自己的校园生活,认真的看一下自己的校园。

可能不只是人,失去的时候才知道珍惜,当我要离开这个校园的时候,也不免觉得校园很亲切。在这里也待了六年多了,校园环境渐渐熟悉,熟悉校园的每一个角落,小小的校园一切都很自然。以前到别人的学校,感觉哪些不太对劲,虽然嘴上说了自己学校不好一万遍,还是觉得自己学校很舒服。学校也越来越陌生,新的体育馆、新的食堂、新的宿舍楼、新的实验楼、咖啡厅、超市,学校里面的建筑慢慢的换上了新的容颜。可能习惯了校园原来的样子,新的食堂和餐厅,很长时间从来都没有去过,新的宿舍楼和实验楼也与我们没有关系。以前的超市很小,买东西也很方便,现在超市大了,东西也找不到了。学校里面还出现了极不相称的咖啡厅...寝室网段变了,失去了59.64,现在上网开始要登陆了。学校论坛换了皮肤,域名变了。FTP走了,BT来了,最近又换了极丑的样子...学校变化的太快,自己在校园里面活动的圈子也越来越小。之前还会在学校各个教学楼和图书馆穿梭,到后来基本上就是在实验室和寝室了。作为即将离校的“老油条”,突然对比当时入校的时候,变化太大,但我依然熟悉,也依然陌生。

四年的本科生活,已经忘记了很多的细节,学习是当时的主旋律。本科毕业的时候也曾经迷茫和失落。三年后的现在,经历了匆匆的研究生生活,上课、实验室、
实习。很多问题还是没有答案,现在的状态很不像当时想的那样。曾经很在乎的问题,现在也关紧要了。是老了,还是成熟了;是看透了,还是麻木了;是堕落了,还是接收现实了...我不知道,也不会有人告诉我。

毕业了,很多计划的事情没有做,很多要完成的事情,也留下来了烂摊子,以后也没有机会了。虽然早就进入了半工作的状态,却总是把自己当成学生看。今天之后,将不再有“学生”这个挡箭牌,责任和担当也随之而来。新的开始可能不只是生活,而是心态。我不知道我是否做好了准备,但是时间可不管你,往前冲吧...

(2012年3月26日 学三-203)

2012年3月7日星期三

Cygwin的文件权限管理

在使用Cygwin编译的时候,突然遇到这样的问题:
install: cannot open `./obj/local/armeabi-v7a/libnative_camera_r2.2.2.so' for reading: Permission denied
根据错误提示,可以知道是文件权限的问题,这个文件是Cygwin的bash编译生成的。Cygwin是模拟Linux环境的,对生成的文件会赋予默认的权限。通过查看此文件的权限,确实有问题,没有读写权限。

在网上找到解决方案:http://nai-chu.blog.163.com/blog/static/909724402010224852713/

因为我使用的是Cygwin 1.7,我这里转载这部分如下:
Cygwin 1.7 版改用 /etc/fstab 文件来控制权限设置。所以用编辑器打开 c:\cygwin\etc\fstab 文件,在里面添加这一行:
none /cygdrive cygdrive binary,user,noacl,posix=0 0 0
注:作者原文的这一行设置对我的情况无效,我这里做了修改。
保存文件,整个设置就完成了。
最后,让我们看看在如上设置之后,在Cygwin中创建的新文件的默认权限:

可见,Everyone用户拥有对文件的完全控制权限(在我的电脑上是有了读和可执行的权限,不过我的问题已经解决了),而这正是Microsoft Windows默认的权限。

参考网址:
http://nai-chu.blog.163.com/blog/static/909724402010224852713/

2012年3月3日星期六

Linux把窗口快捷切换到最前的方法


在Linux使用的时候,可能需要来回切换窗口,需要把某个窗口提到最前来,也就是激活,如果没有打开此程序,就先打开。例如经常需要把字典调出来。在Windows下的有道字典就有这个功能。在Linux可以更加方便的对任何程序实现此功能。这里需要用到wmctrl工具。

在Ubuntu下,首先安装:
sudo apt-get install wmctrl

wmctrl的用法有很多,可以使用多种方法来控制窗口。这里主要用到如下功能:
wmctrl -a "window name"

这里-a参数表示激活(Active),后面接窗口的名字,这里并不需要完全精确匹配,只需要是目标窗口的一部分就可以,例如:wmctrl -a "pdf"就可方便激活pdf阅读器(因为pdf阅读器的窗口名字会根据文档名字变化,.pdf是唯一不变的)。

接下来实现:没有打开此程序的话,就直接打开,否则直接激活此程序。可以使用如下脚本,保存为/home/tom/bringToFront文件,第一个参数表示程序名,第二参数表示窗口名(或者窗口名的一部分)。
#!/bin/bash
if [ `wmctrl -l | grep -c "$2"` != 0 ]  
then
    wmctrl -a "$2"
else
    $1 &
fi

并且给此文件增加可执行权限chmod +x,就可以这样使用次脚本了:
./bringToFront chrome "Chrome"
这里会先执行查看是否打开了chrome,如果没有开打,就打开,否则,把Chrome窗口激活。
PS:后来发现有人用了更加简单的方法实现:
wmctrl -a "winname" appname


最后,就是绑定快捷键,Ubuntu的keyboard程序,能够非常方便的实现自定义快捷键绑定:
例如:就定义了几个常用的程序的快捷键如图所示。


参考网址:

2012年2月29日星期三

VIM使用小技巧-重新载入文件


有时候要使用VIM打开了一些文件,但是在其他地方把次文件改动了,例如使用git进行checkout等操作,需要重新载入此文件。

1 重新载入当前文件:
:e
:e! #放弃当前修改,强制重新载入
2 重新载入所有打开的文件:
:bufdo e 或者 :bufdo :e!
:bufdo命令表示把后面的命令应用到所有buffer中的文件。

参考网址:
http://stackoverflow.com/questions/1272007/refresh-all-files-in-buffer-from-disk-in-vim
http://vim.wikia.com/wiki/Run_a_command_in_multiple_buffers

2012年2月27日星期一

MS实习结束了

从去年10月27日,到今天正好四个月了,明天就要Check out了。四个月,也是我经历最长的一次实习,这里说说我的体会。

1 面试
经过朋友的内推,首先接到电话面试的通知,第一次电话面试,可能也被公司的名气所震慑,感觉很紧张。面试经历了一个小时,基本上全是算法。最后一个算法磕磕碰碰,在面试官的提示下,算是得出了结果。忐忑等了一个星期,得到去公司面试的通知,全程三个小时,三个面试官,都是算法,并且直接在白板上写Code。拿到了实习的offer,实习三个月后,公司安排了正式员工的面试,整个流程差不多,面试过程都是算法并写Code。最后一面是级别比较高的Manager,首先要英文做自我介绍,我顿时就懵了,因为前面所有的面试都是中文,措手不及啊,结结巴巴没有说出几句来。然后就是聊聊实习项目和体验,自己的优缺点,为什么想来这里等一些常规的问题。因为前面形成了思维定式,以为会全是算法,想不到最后一面会这么“文艺”,完全没有准备,自认为表现非常的不好,但是很庆幸最后得到了offer。
MS面试算法算法是王道,准备算法好算法,而且要注意和面试官交流。面试官并不是要看到你会多少算法,还有很重要的是你解决问题的能力,遇到难题,能不能积极思考,并得出解决方案。算法固然重要,但是也要准备常规的面试问题,例如英文自我介绍(外企必备的),自己的优缺点等。我个人很认同MS的面试方式,算法为主,也不会有太难的算法,面试官都很nice,会引导你解决问题。

2 工作
公司上下班的时间非常灵活,没有固定上下班时间,因为公司以结果为导向,只要能够完成任务就可以。大家上下班的时间都比较灵活,Mentor和Manager也不管你什么时候到。实习生请假也比较容易。这是我最喜欢的地方之一。
原则上,MS对实习生有很完善的培养计划和目标,因为从实习生Review和One-One制度上都可以感受到,虽然执行的时候可能会有些偏差。公司的开发工具完全是使用自己的一套,有些并没有对外发布,所以有时候出了问题,搜索都困难。有太多的工具,在我四个月的实习时间里面,很多东西都没有搞清楚。
让我非常惊讶的是公司的办公系统。Email、会议、IM、远程协作都是原来可以整合的如此完善和方便。工作上交流都是英文,自己的Writing skill可能有些进步,但是很遗憾的是,在这段时间里面,并没有联系自己的口语。

3 生活
必须说的是公司的福利确实非常好。可以玩的东西确实很多,乒乓球、台球、桌上足球等。免费的早餐、饮料、水果吃得很happy。不过食堂确实有些小贵啊。

4 后记
办完了Check out手续,交上门卡那一瞬间还是有点不舍。Mentor送我的话是:祝贺你快要正式踏上社会!

2012年2月14日星期二

写给你

我们在一起已经0了。想写点东西送给你。

End

2012年1月1日星期日

2011已经过去

今天已经步入了新的一年。回首一下,想不到“世界末日”的2012年来的这么快。大家各种总结,我也尝试着回忆一下我的这一年。平时觉得自己过的很混乱,每天都感觉都差不多,但是试着回忆一下,却发现这一年经历了这么多事情。

春节刚回到回家,惊闻妈在工地上做事,出了事故,小腿骨被压骨折。回家第一件事情就去跑去躺在医院病床上的妈妈,脚上打着石膏,本来就瘦削的面庞,有明显被疼痛折磨的痕迹。看到妈妈这样的状况,顿时眼泪涌出来。还遇到黑心的老板,不愿意赔偿,朴实的老百姓,哪有什么公平可言啊。在过年的前一天,妈妈勉强出院回家过春节。妈妈已经年过半百,还在做着只有二三十岁的年轻人能胜任的体力活,不管风吹日晒,酷暑严寒,都需要在高空作业。曾经弱弱的和爸妈说,您歇着吧,不要再出来干这种活儿了。爸妈总是摇头说,你还没有参加工作,虽然你上学不需要什钱,但是,家里的日常支出也是不小的负担的,等你工作了再说吧。我语塞。

开学后,快要面临毕业的事情,开始找实习。幸运的进入创新工场实习。在李开复名声的召感下,非常憧憬和珍惜这份实习。实习过程中经历了很多,加班、团队、创业、产品、开发等等,很多东西都让我有了比较直观的认识,并且亲身参与其中。后来还换了几次实习,分别到阿里和微软,算是各种类型的公司文化都有体验,实习让我收获很多,也让我失去了很多。在实习中遇到的人,现在想想都感觉很美好,谢谢我遇到的每一个人。世界很大也很复杂,圈子很小也很单纯...

六月三十号开始我不再单身,开始进入我这个年龄的人都期待了无数遍的恋爱生活。可能是命运,也是实习给我的馈赠。在一起也有半年的时间,不是算长也不算短,也经历过很多事情。出去玩、搬家、做饭、甜蜜、吵架、抚慰。有付出,也有幸福。有压力,也很舒服。在恋爱中,很容易让一个人变得透明,所有的性格和脾气都可以暴露无遗,甚至被放大。两个人走到一起不容易,一直走下去却更不容易。不成熟的我,给我们的感情带来很大的影响。我也知道后面的路很长,摩擦一定还会有,期望我们能好好走下去。期望能到修成正果的那一天。

8月的一天晚上,我和正常的时间一样给家里打电话,却感受到电话那头传来异样的气氛。我一直追问下去,果然,家里有事,事情远远超出我能承受的范围--爸爸可能得了肺癌。晴天霹雳一般,我买了第二天的票赶上了回家的火车。在省肿瘤医院,爸爸的检查结果出来,确诊为中晚期。妈妈从家里打来电话,妈妈在那头号啕大哭,我也在这边泪如雨下,却极力控制自己的声音...命运,你为什么这么做弄人,我可怜的爸爸,从我记事起,就一直忙忙碌碌,为了我们找个家,为我们这几个孩子,什么不能吃的苦都吃了,什么不能受的委屈都受了,什么样的穷日子也都过了,在我即将成人独立的时候,在我即将有机会让爸妈能够停下来的时候,在我爸爸身体慢慢虚弱的时候,却还要然这样恐怖的恶魔来这么我爸和我的家人,难道我们家受的苦还不够吗,命运要这样来作弄,多么希望命运之神突然发现自己弄错了,只是不小心开的一个玩笑,明天就告诉我这一切都是假的。我甚至到目前都不敢接受这样的事实,无数次从梦中惊醒,说真的,我害怕了。“子欲养而亲不待”,爸!我是不孝的,这么多年来,我从来没有孝敬过您,一直觉得以后有的是机会,等我挣钱再来孝敬您,可是发现可能连这样的机会都可能会没有了。可怕的恶魔,你为什么要这个时候出现,我不解...我不解...

因为要找工作,我回到北京找工作。在实习的同时,准备简历,网上海投简历,接下来,奔跑各地赶场笔试,面试。有时候在同一天参加六七个面试,而且在不同的地方,几乎一天能踏遍北京东西南北。好多天下来,简历或者面试之后就石沉大海,疲惫和沮丧几乎都要把我击垮。谢谢yq在我身边陪伴和鼓励,谢谢同学之间的相互帮助,我们都走过来了。找工作尘埃落定,本来就不胖的我,也掉下来几斤肉。

2011年,对我来说,是噩梦般的,也是有惊喜的。命运2011年给我的一切我都接受,2011都过去了,新2012也来到了,祈祷2012命运的垂青,让我爸爸好起来,期望我的家人都健康幸福!

2011年12月16日星期五

在Blogger中添加代码语法高亮

对于一个码农,博客中有代码是不可避免的,语法高亮也是博客的必备功能了。之前在Google App Engine使用Micolog搭建了一个自己的博客系统,那里添加代码高亮插件是十分简单的。因为所有文件都可以自己上传和定义。

但是怎样在Google提供的博客系统Blogger添加代码高亮功能呢?在网上搜罗了一下,果然什么都有。因为Blogger系统提供了完善的模板系统,可以通过修改博客的模板来达到目的。 首先,代码高亮当然是使用顶顶大名的SyntaxHighlighter插件,官方地址: http://alexgorbatchev.com/SyntaxHighlighter/。现在需要做的就是怎么把它整合进入我们的Blogger的模板。

具体操作如下:
  1. 进入您的相应的博客的后台,选择“模板” or "Templete";
  2. 这里可以选择自己喜欢博客整体布局,然后点击“修改Html”;
  3. 打开了模板的html代码,如果你是网页设计高手,这里您就可以大展身手了。如果您看到这个些密密麻麻的代码,完全晕了,不要紧。找到这样的标签对b:skin。把如下文件中的代码加到标签对b:skin的CSS定义之后:
    http://syntaxhighlighter.googlecode.com/svn/trunk/Styles/SyntaxHighlighter.css
    这里使用Google Code上host的SyntaxHighlighter.css,所以不用自己把里面的代码拷过来粘在这里了。
  4. 然后在里面找到标签/head,在这之前添加如下代码:
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    这里是添加syntaxhighlighter的语言javascript文件。
  5. 最后,找到标签/body,在此标签之前添加如下代码:

    这里是让语法高亮处理生效。到这里全部设置已经完成。为了保证您的编辑没有错误,可以首先预览一下,确认无误后再保存。
  6. 具体的用法是,如果在写文章的过程中需要输入代码段,可以,具体做法如下:在写博客的时候切换到HTML模式,在相应的位置输入,下面是一个例子:

    Put your code here...

参考网址:
http://heisencoder.net/2009/01/adding-syntax-highlighting-to-blogger.html
http://yacoding.blogspot.com/2008/05/how-to-add-syntax-highlight-to-blogger.html

2010年10月28日星期四

Test Post by Email

Word press 可以使用邮件发表博文,这里来尝试一下。

使用邮件的方式来写博客,可以间接避开博客地址登陆不上去的问题。关于使用邮件写博客的方法,这里有一个说明文档:http://en.support.wordpress.com/post-by-email/

例如一些常用的标签: