挥手告别2011

2011年,不平凡的一年。

这一年,最喜欢的球星外星人罗纳尔多退役了,爱上足球很大程度上是因为罗尼。

这一年,最爱的小牛队夺得了NBA总冠军,总算没有重蹈2006的覆辙。

这一年,开创了移动互联网时代的乔帮主登船了,C语言之父,人工智能之父也都登船了。

这一年,我毕业了,开始工作了。

时光荏苒,大学四年很快就过去了,毕业的那一刻,在一起生活了四年的哥们姐们,真的是有种依依不舍的感觉。毕业旅行去了山东日照,那应该是青春岁月里非常happy也非常有意义的一次旅行了。毕业了,然后各奔东西。我得到了一份自我感觉还算可以的工作,做着自己喜欢的移动互联网开发工作。

2012,世界末日很显然不会到来,生活还得有条不紊的进行。

2012,努力工作,充实自己,为梦想起航。

2012,学英语,写程序,还有一大堆的事….

不要忽视ViewFlipper

当我们需要实现多标签页程序的时候,相信很多人首先会想到用TabActivity来解决。没错,TabActivity就是用来解决多标签程序的。但其实,我们真的有必要一定要用TabActivity来解决吗?尤其是当多标签页程序里面嵌套的子Activity又是多标签的时候。这里我要介绍的是我比较钟爱的ViewFlipper。

实现多标签页程序的时候,通常都会使用TabHost,然后把TabWidget的visibility属性设置为gone(很多人都觉得原生的tab太丑,且现在大多数的UI都在模仿iPhone上面的UI,tab放在底部),而TabWidget的功能则用RadioGroup来实现。用TabActivity来实现的程序易于维护,因为每个页面都分别到了每个子Activity里面实现。但是可能有些同志会想当然的看到多标签就用TabActivity, 如果TabActivity里面的子Activity又继承了TabActivity,在监听按键的时候系统将不知道该返回到哪层,导致出错,这样的结果显然不是我们期望看到的。如果需要在子Activity里面实现多标签,我们可以用ViewFlipper来实现。布局代码大致如下:

<RadioGroup> </RadioGroup>

<ViewFlipper

        android:animationCache="false"
        android:alwaysDrawnWithCache="false" android:drawingCacheQuality="high"
        android:persistentDrawingCache="none"
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:inAnimation="@anim/push_in" android:outAnimation="@anim/push_out">
        <include layout="@layout/xxx0" />
        <include layout="@layout/xxx1" />
        <include layout="@layout/xxx2" />
    </ViewFlipper>

在子Activity里面用ViewFlipper来实现页面的切换显然要比再继续继承TabActivity明智得多,嵌套越深越是容易出现问题。

ViewFlipper比较适用于布局切换时动画效果要求较高(inAnimation和outAnimation分别控制下一个页面的进入动画和当前页面的退出动画),各个布局间传递数据比较频繁。用ViewFlipper实现时,很显然所有的代码都是在一个Activity里面实现了,既然都在一个Activity里面,各个页面间的数据传递当然比在Activity间用Intent或者Broadcast来传递数据方便的多,但所有页面逻辑代码写在一个Activity里面带来的问题显然就是可维护性不好。

一个页面需要用一个Activity来实现,在我看来,这不是什么准则,如果逻辑代码不是很复杂,我更倾向于把所有页面逻辑代码写在一个Activity里面(关键是我喜欢控制页面的进出动画效果),毕竟大多数手机程序也大不到哪去,维护起来也不是什么难事。但是如果逻辑代码很复杂,而且需要很好的扩展性,最好还是分开来实现,这样后期的维护和升级也相对更轻松些,毕竟一个产品能否成功,升级和维护还是占很大的比例的。

关于布局的一些使用想法

布局这一块,我想使用最多的就是LinearLayout线性布局以及RelativeLayout相对布局了。AbsoluteLayout绝对布局很少用,我只是在初学的时候用了,而且还搞出笑话来了。老板布置的作业,我在我的G3上使用AbsoluteLayout布局,在我的手机上看上去很完美,谁知道面试的时候老板用的是G7,跑起来一看,整个UI都缩在左上角那一块了,老板还半开玩笑的说是不是我的审美有问题啊。

LinearLayout布局适合于从左往右顺序排列,或者从上往下顺序排列。RelativeLayout则适用于左右固定,或者上下固定,中间可以扩充满整个布局。在使用LinearLayout的过程中,我想layout_weight是需要重视的属性之一,这个属性可以很容易的进行控件的等比例布局。RelativeLayout的使用过程通常是把靠边的控件先定义,然后定义中间的控件是在前面定义的控件的左边还是右边还是上边下边等等。LinearLayout通常情况下是不能滚动的,如果需要滚动,则可以在LinearLayout的外面包一层ScrollView。

FrameLayout用的也比较多,FrameLayout主要是用于几个不同控件的显示,在写代码的时候,只需要对最上面的控件进行显示或者隐藏就行了,而不像别的布局,一个显示出来然后把另一个隐藏掉。

TableLayout感觉用的不是很多,用LinearLayout或者GridView就能够很好的实现TableLayout的效果。

在使用LinearLayout,FrameLayout的过程中,layout_gravity是需要重视的属性,这个属性可以设置控件是偏上还是偏下,是水平居中还是垂直居中。layout_gravity是布局内部控件相对于整个布局的重心,而gravity是设置控件内部的重心。

在布局的时候,尽可能的使用sp,dip等依赖设备的长度单位,这样在所有屏幕尺寸差不多大小,但是分辨率不一的机器上看上去效果都能够基本保持一致。如果是要实现某种特效,那就得针对各种分辨率新建文件夹如layout-320×480,layout-480×854分别放置布局文件。

很多人可能不是很清楚margin和padding之间的区别,按我的理解,margin是对外,padding则是对内。怎么说呢,margin是设置view本身和其他view之间的距离,而padding是设置包含在view内的子view到view的边界之间的距离。

AsyncTask的使用

AsyncTask,从字面意思去理解就是异步任务。这里可以打个不恰当的比方,A同学去批发一批货物,先去跟店家商讨价钱下订单(onPreExecute)等前期工作,A同学是个大忙人,在一家店耽搁的时间超过5秒,就活不下去了,所以A同学会在店家准备货物的这段时间(doInBackground)去忙别的生意,待店家准备好货物之后会告知A同学货物准备好了或者是没有货了,A同学正常情况下会对店家的消息作出响应(onPostExecute),在这段过程当中,有需要的话店家可以通过publicProgress及时向A同学通告准备了多少的货物。但A同学也很有可能会变卦,发现他不想要这批货物了,他就会(onCancelled), 如果A同学处事妥当的话,他应该要以某种标记来通知店家不要准备货物了,如果不通知店家的话店家会继续把货物准备到好。A同学如果不想要这批货物之后(onCancelled),他就不会再对这批货物进行任何处理(onPostExecute)了.

AsyncTask<Type1, Type2, Type3>, Type1是传递给doInBackground的参数的类型,Type2是传递给onProgressUpdate的类型,Type3是doInBackground执行完毕然后传递结果给onPostExecute的参数类型。

new一个AsyncTask,然后execute,正常情况下会先调用onPreExecute, 然后调用doInBackground,接着调用onPostExecute。如果要做一些耗时的网络操作,并且网络操作过程中或是完成后需要通过UI展现出来,用AsyncTask来做是最适合不过了。譬如下载的时候,显示下载进度用户体验可能更好些,可以在doInBackground里面通过调用publishProgress函数,publishProgress会将参数传递给onProgresUpdate,然后在onProgressUpdate里面更新UI。当下载完成之后,需要显示播放界面则可以在onPostExecute里面执行。

但是有时候总是会出现我们意想不到的情况,例如在下载的时候,这一首歌曲还没有下完,又点击了下一首,很显然,当前这首歌就不应该再继续下载了。怎么办呢,我们可以通过XXXtask.getStatus()==Status.RUNNING来判断当前任务是否仍在运行,如果仍在运行,我们就要想办法把它停掉。可以通过调用XXXtask.cancel(true),这个函数会触发onCancelled, 我们可以在onCancell里进行进一步处理,但是onCancelled虽然调用了,假如doInBackground里面的任务没有执行完,仍然会继续执行下去。如果想停止下载,可以通过在onCancell里面设置标记位isCancelled,然后在doInBackground里面每一次执行的时候都判断标记位是否为true,如果为true,则应当进行相应处理,然后返回。在执行过onCancell之后,onPostExecute是不会再执行了。

从以上的描述过程来看,doInBackground是由另外的线程来执行的,其余的方法则都是由UI线程来处理的,所以耗时的工作应该要放在doInBackground里来处理,不然会出现ANR的,当然Android里面提供的通信方式还可以是thread-handler,broadcast-service. 我屡试不爽的就是thread-handler了,用handler的消息处理机制绝对要比回调函数好用得多。

充实

洗个澡出来,神清气爽,正好可以写篇博客。

忙了一天,晚上写了一晚上的代码,脖子都酸了,程序临时添加功能真是伤不起啊,还好提前预留了很多的接口好扩展,不然这样一改等于要重头再来了。苦逼的码农日子就是这样,拿人钱财替人办事天经地义。

Description Resource Path Location Type Error generating final archive: Debug Certificate expired on 11-9-15 下午11:49 HJDict Unknown Android Packaging Problem

要不是上面的这个错误信息,俺都不知掉接触android开发已有一年了。时间过得真快,去年的这个时候还在学校忙着找工作,做软件工程的课设呢。而使用android的时间都已经一年半了,想想当初买android手机时,不能用蓝牙,不能发彩信,而如今已遍地是android手机。

下午跟一公司姐姐一同回来,不知道怎么绕到谈论穿着时说每次看见我都穿这身衣服,给人不换衣服的感觉,让哥决定以后注重穿着,哥天天换衣服,但却是每次遇到她都穿这身衣服,真是不巧。

晚上去买了个60块钱的鼠标,用惯了30块钱鼠标的人用起60块钱的鼠标来真是畅快无比,陪伴我两年半的30块钱鼠标彻底退役。

周末又到了,明天可以睡到自然醒咯。

2011-09-14

今天是平常的一天,但却又有点不平常。自己第一个成型的产品终于内测了,虽然内部人测试热情并不高,但自己还是有点兴奋。昨天老板提的几点建议,今天早上总算是勉强完成了,不太好实现的也跟上头沟通过了,下午开始写第一封群发测试的邮件,卖了一下萌,又是亲又是哦的连我自己都受不了了。

下午下班,跟三个一起吃过饭的女生一同坐小黑车回来,我渐渐的感觉到我对其中一个有意思,但是却不敢邀请一起去吃饭,要不是三个女生在一起也许我会厚脸皮一回的。继续观望吧,一个人有点孤单,但却很自由。

在宿舍打开google邮箱不是一般的难,这不是网速的问题,因为看视频流畅的不行,只能说一声fuck GFW, 买的VPN也不起作用,同fuck。在推特和微博人人上溜达了一圈,不知不觉一个多小时过去了。

刚洗澡出来,一看GT在闪,是老板在跟我提需求,幸好之前做的时候预留了位置,不然数据库得重构那又得费劲折腾了,大boss的需求是必须要满足的,不满足也要说明情况。

不写了,看书睡觉,今夜有皇马比赛,hala,madrid。

想到什么写什么

今天中秋,一个人苦逼的在家里宅着,公司发的一盒月饼8个,每晚啃两个,到今晚刚好啃完了。小时候的中秋节都是去海边玩耍赏月,而如今一个人在异乡打工,酸甜苦辣自知。

今天狠下心一下子买了两个VPN,一个是包月不限流量的,供PC使用,一个是包流量的,供我的pad和手机使用。以后再也不想去找免费VPN,找代理,修改host,或者用自由门了,浪费宝贵的时间,关键没心思去折腾了。

转眼间,工作也快三个月了,这个月底就要转正了,不知道转正工资会加否。其实不管加薪不加薪,至少我认为毕业时果断到目前这家公司这个决定没有错,不管是从经济上还是为未来前程考虑上。如果没有之前的苦逼实习阶段,我就不会果断另谋出路,我就是一个随遇不安的人。

目前的工作我有很大的自由度,产品的设计编码全都是我一个人负责,毕竟手机开发也不是什么大项目,不需要多人合作,感觉多人合作反而会降低效率。虽然有时候某个功能花费了我很多的心血,但是上头认为不合适,经过讨论该砍掉还是砍掉。目前的工作也不用加班,也没有人催我项目要什么时候上线,但作为新人,我虽然不加班,但是还是会把项目带回家做,也只有不断的学习才能使自己更有竞争力。

捣腾了两个多月,第一个产品马上要上线了,也不知道如何去评估,反正自我感觉良好,借着公司的推广,看这个产品能不能受欢迎了。在新东家工作感觉还是很好的,至少生活还有点盼头,从最初的不适应,到现在有点归属感,工作也越来越顺手了。

理想与现实还是有差距的,以前总认为工作之后,晚上有时间可以去去酒吧,或者去吃烧烤。但其实生活中,除了周末,平常也都是睡醒去公司工作,晚上回来,到外面吃个饭,回家,洗澡,上网,睡觉。醒来接着新的一天。

但这就是生活,平平淡淡的才是生活。接下来,工作上继续努力,遇到感觉良好的妹子就努力去追。

跟球迷喝茶聊天,他说他们公司欠薪,生活费也都是从家里要,国企也欠薪啊。但现实就是这样,他说生活就是这么无奈,在这个流氓的国度,遇上流氓了也就自认倒霉,你逞强说不定你就是下一个倒霉蛋。确实是,在这个流氓的国度,D就是赤裸裸的挑战屁民的底线,屁民又能咋样。权势横行,我也不能改变什么,我当下要做的就是把工作做好,把技术练好,其他的事还是搞搞挂起吧,等老子哪天有钱了再当个返聘愤青吧。

现在的twitter倒是很平静的,比国内微博和谐多了,依旧经常上twitter,但是不参与讨论,周末有空就去跟推特小鸟们踢踢球。对于社会上的蛋疼事,我也还是会经常看看,毕竟说不定哪天这种倒霉事掉到自己头上,该认命还是该反抗心理还有个底。

生活依旧继续,那些曾经在一起4年,在这个夏天各奔东西的兄弟姐妹们,你们工作生活还好吧?

android开发第二季

经过两天的奋战,一个背单词的android原型应用总算弄出来了。在开发的过程中,又增长了很多的知识,不亲手调试下,总会想当然地认为如何如何,当真正亲自调试的时候,才能够体会到其中精髓。

开发的过程中,学习到了几点重要的知识点。自己的经验还是很欠缺,之前用List,Map的时候没有注意到这些东西的构造,都是想当然的用了,没有出问题自己也就没有注意。但这次,程序一直无法启动,一开始以为是Manifest文件的问题,但是把大量代码注释掉之后,一段一段调试的时候,才发现,原来是List,Map的错误用法导致程序无法启动的。容器如List,Map的值都是链接过去的,而不是申请内存然后把对象拷贝过来,这就使得用同一个变量赋值我的整个容器中的每一个值都是指向同一个对象,导致程序运行错误。这让我想到了文件系统,内存回收是否像文件系统一样,根据块的链接数是否为零来判断是否为垃圾块,然后回收呢?GC系统还有待好好学习。

还有一个知识点就是一个Activity的运行周期,通常我们的初始化都是在onCreate中进行,但是要是在初始化时出现错误怎么办呢?运行onCreate时进程是不能够被kill掉的,但是如果我不处理错误,程序一运行就挂掉了,什么提示信息都没有。后来上网查了,Activity的设计是很有道理的,Activity在运行onResume时才开始绘制界面,如果错误在onCreate中能够被处理当然是不会有任何提示信息的。所以后来我的解决办法就是设置一个标记,然后结束onCreate函数的运行。再在onResume中根据标记处理错误信息。

通过这次的学习,我才渐渐意识到在学习使用一些东西时,要先从这些东西的设计思想开始学习是很有必要的。同时很多的知识还必须要经受实战才能够掌握,而不是想当然的认为,这样很危险。