2012年12月27日星期四

Android开发笔记(九)


Android开发笔记(九)

  • 单线程处理多模块逻辑
     最近工作其中的一个重要任务,在组网层(?)之上实现任务层逻辑,目前功能包括文件传输与历史记录。为了模块具有良好的独立性与复用性,除了设计一套良好的对外接口外(在此不讨论接口问题,参见~~),还需考虑合适的线程模型--采用单线程。其实单线程模型设计很简单,关键在于:
     1. 管理单线程的生命周期,并维护其线程队列。
     2. 调用接口,内部逻辑第一件事做的是转至内部处理线程即投递消息到线程队列。
          在线程循环处理消息的前提下,线程队列将消息继续投递至对应的子模块消息处理。
     3. 内部子模块必须实现独立的消息处理函数,子模块间的消息互相不影响。

     Java(android)SDK就提供了如下说明的线程解决方案而且很完善,正所谓得天独厚啊。相关的类型及说明如下:
     HandleThread或Thread,即Java提供的线程,主要就是创建线程对象,start线程,退出线程。
     Looper,即线程的消息队列,每一个线程对应一个消息队列,一对一关系。退出线程是由Looper.quit退出线程消息循环替代完成的。
     Handler,即关联至对应线程队列的消息处理类型。一个消息队列允许对应有多个消息处理对象,一对多的关系。

  • 随机读写文件
     刚开始做Android开发时,遇到读写文件情况都是顺序的读写,所以使用InputStream或OutputStream可以简单顺利搞定。但后来遇到其他复杂的应用场景,可能不是顺序的读写即随机读写。
     1. 首先尝试使用java.io.RandomAccessFile,简单使用示例如下:
     文件输入输出流:mFileOutput = new RandomAccessFile(new File(uri.getPath()), "rwd");//允许读写,追加写入。
     文件输入流:mFileInput = new RandomAccessFile(new File(uri.getPath()), "r");
     设置偏移位置:mFileOutput.seek(mFileOutput.length());
     读取文件(流)大小:mFileInput.length();
     读取数据:readLen += mFileInput.read(buffer, 0, bufferLen);
     写入数据:mFileOutput.write(data); mFileOutput.flush();
     关闭文件流:mFileInput.close();
     注意:如上创建随机读写文件流,均以android.net.Uri对象打开文件,下同
     关于RandomAccessFile类型的具体介绍参见:android-sdk-RandomAccessFilejdk-RandomAccessFile
     
     很遗憾的是,我在Android设备上尝试使用RandomAccessFile随机读写文件未成功,在创建对象时候失败抛异常:

FileNotFoundExceptionif the file cannot be opened or created according to mode.
     网上搜索很多办法犹未解决问题,由于项目时间逼近所以暂留下问题在此笔记,容后续再考虑。你有什么办法吗?

     2. 接着,找了另一种办法实现了随机读写文件这样的功能,使用java.nio.channels.FileChannel 对象操作文件读写。使用FileChannel的简单示例如下:
     输入流FileChannel:
          ContentResolver cr = context.getContentResolver();
          mInputStream = (FileInputStream) cr.openInputStream(uri);
          mFileInput = mInputStream.getChannel();
     输出流FileChannel:
          ContentResolver cr = context.getContentResolver();
          FileOutputStream fileOutputStream = (FileOutputStream) cr.openOutputStream(uri);
          mFileOutput = fileOutputStream.getChannel();
     设置偏移位置:mFileInput.position(beginPos); 或mFileOutput.position(mFileOutput.size());
     读取数据:mFileInput.read(buffer);// buffer is ByteBuffer object.
     写入数据:writtenLen += mFileOutput.write(ByteBuffer.wrap(data, 0, data.length));
     关闭Channel:mFileInput.close(); 或关闭对应的文件流:mInputStream.close();
     
     这次就成功地以Uri对象打开了(输入输出)文件流,得到对应的FileChannel对象,并顺利地实现了随机读写文件流功能。
     相比RandomAccessFile,虽然FileChannel这种办法看起来粗略一些,更多的是需自己设计,但其效率未必较差:D 。
     关于FileChannel类型的具体介绍参见:android-sdk-FileChanneljdk-FileChannel

btw. android文件路径如:(/mnt/sdcard/...),Uri内容如:(content://media/external/...)。



  • 对象序列化类型
     可以先尝试回答一个问题,在Java编程什么时候需要用到对象序列化?
     1. 通过序列化保存对象,如保存至磁盘。
     2. 通过序列化传输对象。如网络传输,进程间传输等。
     在Java编程做Android开发过程中,对象序列化可以使用到的主要类型包括: ParcelParcelable、Serializable。
1.在使用内存的时候,Parcelable 类比Serializable性能高,所以推荐使用Parcelable类。
2.Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3.Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点, 也不提倡用,但在这种情况下,还是建议你用Serializable 。


在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC(进程间通信)机制,必然要求使用性能更出色的对象传输方式。在这样的环境下,Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。Parcel的实现过程是这样的:
1. 整个读写全是在内存中进行,主要是通过malloc()、realloc()、memcpy()等内存操作进行,所以效率比JAVA序列化中使用外部存储器会高很多;
2. 读写时是4字节对齐的,可以看到#define PAD_SIZE(s) (((s)+3)&~3)这句宏定义就是在做这件事情;
3. 如果预分配的空间不够时newSize = ((mDataSize+len)*3)/2;会一次多分配50%;
4.  对于普通数据,使用的是mData内存地址,对于IBinder类型的数据以及FileDescriptor使用的是mObjects内存地址。后者是通过flatten_binder()和unflatten_binder()实现的,目的是反序列化时读出的对象就是原对象而不用重新new一个新对象。

  ParcelParcelable简单的使用,如下:
  Parcelable praceable = intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
  NetworkInfo otherNetworkInfo = null;
  if (praceable != null) {
     final Parcel pracel = Parcel. obtain();
     praceable.writeToParcel(pracel, 0);
     otherNetworkInfo = (NetworkInfo) pracel.readValue(NetworkInfo. class.getClassLoader());
  }

   注意:Serializable的实现,只需要继承(implements) Serializable即可。这只是给对象打了一个标记,系统会自动将其序列化。
  关于ParcelParcelable、Serializable三者的详细说明参见:android-sdk-Parcelandroid-sdk-Parcelableandroid-sdk-Serializable

(完)


2012年12月26日星期三

宁静致远.生活态度


宁静致远


  • 诗句
  源自《西游记》第八十五回(心猿妒慕母 魔主计吞禅),其中有诗句如下:
  佛在灵山莫远求,灵山只在汝心头。
  人人有个灵山塔,好向灵山塔下秀。
    -- 乌巢禅师《多心经》四句颂子


  • 段子
  三藏道:“徒弟,我岂不知?若依此四句,千经万典,也只是修心。”

  行者道:“不消说了,心净孤明独照,心存万境皆清。差错些儿成惰懈,千年万载不成功。但要一片志诚,雷音只在眼下。似你这般恐惧惊惶,神思不安,大道远矣,雷音亦远矣。且莫胡疑,随我去。”


  那长老闻言,心神顿爽,万虑皆休。 


  • 感悟
  宁静以致远。当下的我乃内年少尙无为时,且不说“淡泊以明志”。惟求“宁静以致远”,助我常怀有优良心态,不懈学习,追求上进!


 (完)

2012年12月15日星期六

另一种“荒野求生”

另一种的“荒野求生”
  源自知乎的一个话题(问题)。


  • 话题:

五年编程经验,跳槽到新公司后,月薪 6000 元,但工作内容就是写注释,写了一年注释,这种情况在编程行业普遍吗?

我有五年的编程经验,其中一年是实习,其余四年在一家小公司做外包。由于我不习惯公司整天把我外派到别的公司做技术,于是我就跳了槽。
现在这家公司是一家所谓的大企业,已上市,技术团队几百人,公司名字就不说了。月薪6000元,我上一份工作月薪是4500元。
但工作内容就是给代码写中文注释,整天就是跟//打交道,写了一年注释。
我另一个同事更离谱,整天看代码然后用txt文档记录可能出错的地方,别说开发,他一年多都没配过ide。就算他找出错给总监,总监也不理,测试那组几十个人,也轮不到他,他找到的人家早就找到了。
现在这份工作总的来说,能看到别人写的非常牛X的代码,很多非常牛X的算法,但没有办法参与到开发过程中去,该不该跳槽?首先我承认我技术不如别人,但同样拿6000的很多人都在做开发。

  • 一楼:
从描述看,这是一家“荒野求生”型公司。这样的公司特点是,新员工被仍在一个荒岛上自生自灭,优胜劣汰之后,剩下几个“幸存者”都是技术和性格非常强悍的人。
这类公司挑战员工的有:
1. 目标感,不告诉你什么时候来救你。你必须对长期在岛上生活做充分的准备。一个明确的目标使得你不至于放弃求生的希望——我要学习什么样的技术;
2. 发现食物的能力,没有现成的吃得给你,你必须把各种野菜变成食物充饥。
3. 竞争意识, 食物少或者没有食物,大家必须靠抢夺食物为生。你必须要主动的解决项目中暴露的问题,而不能等待它 assign 给你。
这样的公司不是适合所有的人。但一旦你挺过来了, winner 的感觉会伴随你以后的工作。



  • 二楼:

我觉得你对自己的定位有问题,说白了只能说你是个合格的员工,公司叫你写注释你就只写注释?
如果你以这种思维跳槽,你到其他公司也不会有大的发展,我觉得你在这岗位上应该突破自己的职责做出些贡献。
比如现在的岗位
@梁涛说的:“要是你把所有的代码和注释画成流程图”,那公司肯定把你奉为牛人;
另外你通过看代码可以了解这个产品和系统最核心的东西,也许你可以发现缺陷,提供改进方案;也许你可以从某个方面设计出优化系统的办法;公司一定会给你更合适的岗位;

你还可以通过看代码了解代码编写者的能力和缺点,在你对每个人了解后很适合在以后提出好的意见,也很可能获得提升走上管理岗位;
......
太多了,努力吧,哥们;


(其他评论)……


  • 我的评论:
看了楼主的问题,还有楼上诸位的一些评论!我也在此说几句吧,希望可以给楼主一些好的意见!
均同意一楼和二楼的意见,小总结一下:
1, “荒野求生存”,你需要更加主动给自己想主意啊,把事情(理清代码逻辑,不单单是添加注释)做全面、精彩了!挺过来了那么你的“生存能力”必然很大提升!
2, 明确你的定位,@yaocoder就举出了几个方面颇好!
还有,一些我的感触:
a. 楼主现在的公司环境还算比较宽松啊,可以分配给你这么一闲差。既然这样,好像更有空间给自己充电啊!
b. 都五年的编程经验了,你一定可以有更好的发展的,完全不局限于此!加油。
刚好,昨晚在微博转发了这么一条:
#管理者说#无论你从事哪一行,你都不只是别人的员工——你还是自己的职业生涯的员工。——曾任英特尔公司董事长安迪·格鲁夫(Andrew S·Grove)


补充一下:
不要单单局限于当下的简单工作(任务),尽量发挥自己的主观能动性吧,适当有点危机感,营造另一种“荒野求生”吧。何况现在自己还很年轻,对自己允许苛刻一些,不枉少年!
有的人会说,“人生不必太累了,何必呢?“ 哼,苛刻不代表就累了,真的。恰恰很多人也这么说,“每当回忆过去最美好的时候,都是那些吃苦的日子。”

(完)

2012年12月5日星期三

几条工作备忘

几条工作备忘
  -- 与工作效率有关


  • 如何逃避项目延期厄运呢?
眼见身边故事的总结,个人鄙见:
1. 项目前期尽量安排紧凑,都给老子动起来;
2. 管理者对项目天天做到把控,安排各进度,能清楚手下都在忙啥;
3. 积极调动每人主动性,参与一些项目把控任务;
4. 友好善待每位手下,难但尽量做好。
至少,我所在项目没延期,而隔壁项目则严重延期了(一月)!话说回来还是我们的TL管理有方,虽说其要求比较苛刻了!

  • 如何给自己提高工作积极性与成就感呢?
1. 坚持总结、撰写技术资料,博文发布分享更好;
2. 根据近期项目经验积累,整理成文积累下来;
3. 对从事方向的前沿技术或产品保持关注;
4. 乐于与身边同事彼此技术交流或产品意识或新奇古怪;
5. 不忘定期如半年或三月,为自己争取加薪升职机会。

会议讨论过程遇到有人闹情绪激动怎么办?1迅速告诉自己他只是就事论事;2他的性格决定如此,每人都有自己的个性可以理解;3他的激动表示其认真投入与执著值得肯定、甚至仰慕;4此时我需要表现更加镇静,思路清晰,否则考虑暂停继续交锋式的探讨交流;5引以为戒,有话好好说最好了!

  • 如何把握好与上司相处呢?(转)
与上司相处九原则:
1.当上司讲话的时候,排除紧张意念,专心聆听;
2.有所选择地向上司报告;
3.讲点战术,不要直接否定上司建议;
4.解决好自己分内问题;5.维护上司形象;
6.积极工作;
7.信守诺言,若你承诺的一项工作没兑现,他就会怀疑你是否守信用;
8.了解你的上司;
9.关系要适度。@世界经理人网站



  • 如何设计良好的接口?
如何设计良好的接口,让多模块间的交互行为看似完美又简洁?
这种解决办法在哪里,有这种银弹的吗?没有!我想永远都没有答案,具体问题看情况具体分析,最多只能说银弹值得去追求!甚至,在糟糕的情况如项目危急紧急时候,哪管什么银弹不银弹的,只要能保证模块间交互没问题就万事大吉了,即使它有着千疮百孔,银弹最多那也是后事(追求)。被A逼迫着的情况,B还要求着要银弹,C怎么办?继续追求银弹?
PS. 到此有点儿吐槽的味儿了~!哈哈:D 

  • 如何算是过于强调结构设计呢?
1. 项目需求还未明确就不断追求模块化与系统架构;
2. 仅为直观的结构而调整架构而无从编码与实用性考虑;
3. 项目开发时间与人力资源均紧张情况下追求完美架构与标准文档化;
4. 用理论的一些名词强加定义不同的结构部分。


遇到困难时你的第一反应呢?
 “遇到困难学会逆向思维。”道理简单,可惜很多人当时都懵住了,完全不知所错,甚至越走越难!
  把图片倒过来看看吧!你会发现很快乐!有时候把事情倒过来想就不一样了!转给我的朋友们。遇到困难学会逆向思维,也许会柳暗花明。。。”

(完)


做技术,做深做透,不急不躁!


做技术,做深做透,不急不躁!
===
故事从这里说起,先引用RTX内容如下:
---------------------------
longshen 17:04:08
刚刚测试了下motorola电信定制版,创建软AP问题。
主要是其WifiConfiguration比其他多出 wifi_ap_gateway、dhcp_start_addr、dhcp_end_addr 三个字段。
需要用reflect进行设置,否则会导致motorola重启。
设置这三个字段后,motorola可以创建软AP,正常通信了。

team leader 17:04:31
好的,幸苦了
team leader  17:04:44
以后我们技术,就参考快牙和快传吧。
技术这东西,还是努力做深做透彻,不要急于做结论。
有个学习和深入的过程。

junkunhuang 17:05:46
嗯,我当时没做深入进去。


===
今天,在工作上遇到一件尴尬的事情,不妨在此讲述故事并做小小的总结一番,与大家分享。虽说当时让我有点儿找不着台阶下的感觉,TL说的那些多少是落在我份上的,但我不得不承认先前我没保持足够的好奇心与专注把功能做深下去做好。

数月(2-3月)前,繁忙于无线项目开发工作,团队人员稀少(加上Team Leader共5位),分工明确且任务繁多。干活如打仗似的一场续一场的
……
当时我负责做Android系统的Wifi热点功能主要包括创建于关闭热点,得到的解决方案除了那台MOTO电信定制机(系统),都可以在其他机器上正常完成功能。开发时间仓促,当时与TL沟通后,最后就索性判断,若系统为电信定制则认为不支持该功能(创建Wifi热点)。
……
过了数月,突然发现某一流行的应用竟在那台MOTO系统上顺利创建热点,完成数据传输。那一定是我们的程序做的不完善,遇到的问题没有给予解决。
继而TL与longshen就该问题讨论起……在longshen同学很给力地进一步“追踪”尝试之下,最终顺利找到了电信定制(android)系统的私有窍门。
再然后我便知道了这事情,当时甚为尴尬,像犯了过错似的。我想最好把这件事情当是一课,记录下来提醒日后自己做事严谨,同时分享大家!

===
最早的时候,或许保持足够的好奇心与专注继续探究问题下去,那么只要一两小时的事情,问题便得以解决!不会有今日之尴尬,早知今日何必当初,所以谨记:做技术,需做深做透彻,且不急着做结论!稍作修剪作为文章标题:做技术,做深做透,不急不躁!
感谢你们,我的团队,我的战友们,我的TL!

(完)