Pages:  1 2 July 2010 – lytsing's Blog

Month: July 2010

  • 再说说代码风格

    老掉牙的话题了,晚上bb给我发一段 php代码,别人写的taobao api,要修改一下cache,我看了,头都大了,代码缩进tab与空格并用,导致我用vim打开很乱。一般,代码写得很糟糕的,我都拒绝看,老朋友嘛,硬着头皮看看,用indent对齐一下,还算好。再看一些函数的命名,我又晕了一把。比如
    public function SendCheng ($mode = 'GET',$format = 'xml')
    还真的看不明白是什么意思。

    在小的软件公司,很多新员工来上班第一天,领导拷贝一堆pdf技术文档给你自个儿看,公司压根儿没编码规范的文档,祸害从此开始。从另一个侧面来说,作为一个程序员,自己也有责任去看《程序设计实践》,网上流传的《华为编码规范》,林锐的《高质量C/C++编程指南》等。千万不要搞什么像Button1, Button2, Button3, xingbie(性别), jifen(积分, 这个的命名方式,害人害己。美工A进公司时也已经工作3年了,网页与图片都是随便的001.html, 002.html, 003.index,不明白是什么意思。我问她为什么不给它们起个有意思的名字,比如一张表示团队的图片,teamwork,jpg 与001.jpg,谁更容易管理,更容易让搜索引擎找到?她说以前没人要求她这么做过,文件随意放,老师没教过要这样做的。再者,搞网站3年,竟然不知道什么是w3c,我真的感到悲哀,同时也为我自己感到悲哀,没有做这方面的测试,以为这是基本的知识,大家都知道了。

    良好的代码风格,是一个程序员的基本修养。

  • 小探 android版QQ空间(体验版)

    STONE说tx早有android版 QQ空间了,于是下载看看,感觉还行,功能太少了。不甘心,看看里面有什么好玩的,不会是个wrapper web的吧,于是决定反编译看个究竟。虽然大家都在骂腾讯,但不可否认的是,他们产品的用户体验做的很好, 搞android开发,也可以看看他们产品,好的界面设计,我们也可以拿来用。前文已经介绍了一些反编译apk的工具,搞软件开发的,至少有那么一点hack精神,学会反编译apk是Android应用程序开发的一项基本技能。

    UI

    界面是淡蓝色风格,也是我比较喜欢的风格,美工图片作图比较到位。看看下边的Tab吧,跟web一样了.

    android qzone 体验版

    开始琢磨一下,到底用什么东东做的?原来是自定义的tabTextStyle,里面还有非常多自定义的view, style,正应那句话:“优秀的组件都是自定义的”。

    personcenterheaderview.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <LinearLayout
        android:orientation="vertical"
        android:background="@drawable/homepageheadbg"
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        xmlns:android="http://schemas.android.com/apk/res/android">
        <LinearLayout
            android:orientation="horizontal"
            android:id="@id/LinearLayoutUserMood"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.0">
            <LinearLayout
                android:gravity="center"
                android:background="@drawable/personhead"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="4.0px"
                android:layout_marginTop="5.0px">
                <ImageView
                    android:id="@id/ImageViewUserIcon"
                    android:layout_width="49.0dip"
                    android:layout_height="49.0dip"
                    android:scaleType="centerCrop" />
            </LinearLayout>
            <LinearLayout
                android:orientation="vertical"
                android:id="@id/saynamegroup"
                android:background="@drawable/saydialog"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8.0px"
                android:layout_marginRight="10.0px"
                android:layout_weight="1.0">
                <TextView
                    android:textSize="14.0px"
                    android:textColor="@color/black"
                    android:ellipsize="end"
                    android:id="@id/TextViewMood"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="2.0px"
                    android:layout_marginRight="2.0px"
                    android:maxLines="2"
                    android:layout_weight="1.0"
                    />
                <TextView
                    android:textSize="12.0px"
                    android:id="@id/TextViewTime"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="2.0px"
                    android:layout_marginTop="2.0px"
                    style="@style/unnoticeableTextStyle"
                />
            </LinearLayout>
        </LinearLayout>
        <LinearLayout
            android:gravity="center"
            android:orientation="horizontal"
            android:id="@id/LinearLayoutTabNav"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
            <TextView
                android:gravity="center"
                android:id="@id/TextViewTabMood"
                android:layout_width="wrap_content"
                android:layout_height="36.0dip"
                android:text="心情"
                android:layout_weight="1.0"
                style="@style/tabTextStyle" />
            <TextView
                android:gravity="center"
                android:id="@id/TextViewTabBlog"
                android:layout_width="wrap_content"
                android:layout_height="36.0dip"
                android:text="日志"
                android:layout_weight="1.0"
                style="@style/tabTextStyle" />
            <TextView
                android:gravity="center"
                android:id="@id/TextViewTabAlbum"
                android:layout_width="wrap_content"
                android:layout_height="36.0dip"
                android:text="相册"
                android:layout_weight="1.0"
                style="@style/tabTextStyle" />
            <TextView
                android:gravity="center"
                android:id="@id/TextViewMessage"
                android:layout_width="wrap_content"
                android:layout_height="36.0dip"
                android:text="留言板"
                android:layout_weight="1.0"
                style="@style/tabTextStyle" />
        </LinearLayout>
    </LinearLayout>

    数据交换

    采用对象序列化,那么提供api的服务端也是用java写的了。

    代码组织

    搞了很多封装,写了N多个组件,不过看起来还清晰。

    命名规则

    不知道tencent有没有公司内部的规范文档,但我看到

    zhuye1.png
    zhuye2.png
    zhuye3.png

    android:id=”@id/ImageView01″
    android:id=”@id/ImageView02″

    之类的,感到很失望,浪费我时间来翻尸体。

    国际化

    在layout xml文件还出现
    android:text=”上传”,android:text=”取消” android:text=”请输入验证码” 之类的东西,为什么不用@string/xxx 呢?

    res/values/strings.xml 里写了很多中文,已经有了values-zh目录,为什么不写到里面呢?

  • 强悍的Android反编apk译软件 apktool

    apktool 下载地址: http://code.google.com/p/android-apktool/
    使用说明上面的链接也写非常清楚,需要注意的就是java是1.6版本的。

    前段时间整理了一个 wiki文档 http://lytsing.org/wiki/android/decompile.html ,简要列出了三个反编译工具:

    • smali
    • dedexer
    • dexdump

    今天下午与absurd老大聊了一下,他说apktool很强大,于是G它一把,看到youtubu有两个视频:

    Apktool Demo 1 – Editing HTC_IME resources

    Apktool Demo 2 – Smali improvements

    视频请自行翻墙观看。视频还有人留言:”Fantastic! Simply Awesome. Thanks so much, I will be looking for your dontate button” . Laugh!人家弄个软件也不容易啊。

    AndroidManifest.xml 一般用 AXMLPrinter2.jar 反编译后,勉强看懂,但还有一些字符串没翻译,apktool做的更彻底,一步到位。不过用AXMLPrinter2.jar反编译xml文件输出的结果很整齐美观。用Eclipse格式化layout的xml文件,结果不那么令人满意。在Jeff Sharkey的一篇博文中,他说Roman Guy会把xml格式化很漂亮,为此,曾经给Roman Guy发过邮件,至今没得到回复:(

    用dedexer反编译出来的ddx文件,参数名没显示出来,

    .method public static getSearchQueryForPublisher(Ljava/lang/String;)Ljava/lang/String;
    .limit registers 3
    ; parameter[0] : v2 (Ljava/lang/String;)

    apktool 反编译出来的smali文件,参数名都列出来了:

    .method public static getSearchQueryForPublisher(Ljava/lang/String;)Ljava/lang/String;
        .locals 2
        .parameter "publisher"

    用dedexer反编译出来的ddx格式文件,可读性会好一些。

    youtube的视频演示了如何修改代码,然后重新打包,签名发布。至于用来汉化,更是小case。同时,从另一个方面来讲,Android程序的安全问题也很是忧虑。

    apktool令人感到震撼,我那wiki页面信息全out了。

  • 一个封装 android.util.Log 的Log类

    在android代码的每个Activity,都不厌其烦的写:

    private static final String TAG = "MyActivity";

    然后需要打印的地方输入:

    Log.v(TAG, "index=" + i);

    写太多的TAG,也麻烦,如果不写TAG,用 this.toString() 也可行,不过还是一样,于是写个包装Log类,自动处理是哪个Activity,调用哪个函数,如下:

    /*
     * Copyright (C) 2010 Lytsing Huang http://lytsing.org
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.lytsing.android.util;
    
    /**
     * Wrapper API for sending log output.
     */
    public class Log {
        protected static final String TAG = "MyApplication";
    
        public Log() {
        }
    
        /**
         * Send a VERBOSE log message.
         * @param msg The message you would like logged.
         */
        public static void v(String msg) {
            android.util.Log.v(TAG, buildMessage(msg));
        }
    
        /**
         * Send a VERBOSE log message and log the exception.
         * @param msg The message you would like logged.
         * @param thr An exception to log
         */
        public static void v(String msg, Throwable thr) {
            android.util.Log.v(TAG, buildMessage(msg), thr);
        }
    
        /**
         * Send a DEBUG log message.
         * @param msg
         */
        public static void d(String msg) {
            android.util.Log.d(TAG, buildMessage(msg));
        }
    
        /**
         * Send a DEBUG log message and log the exception.
         * @param msg The message you would like logged.
         * @param tr An exception to log
         */
        public static void d(String msg, Throwable thr) {
            android.util.Log.d(TAG, buildMessage(msg), thr);
        }
    
        /**
         * Send an INFO log message.
         * @param msg The message you would like logged.
         */
        public static void i(String msg) {
            android.util.Log.i(TAG, buildMessage(msg));
        }
    
        /**
         * Send a INFO log message and log the exception.
         * @param msg The message you would like logged.
         * @param thr An exception to log
         */
        public static void i(String msg, Throwable thr) {
            android.util.Log.i(TAG, buildMessage(msg), thr);
        }
    
        /**
         * Send an ERROR log message.
         * @param msg The message you would like logged.
         */
        public static void e(String msg) {
            android.util.Log.e(TAG, buildMessage(msg));
        }
    
        /**
         * Send a WARN log message
         * @param msg The message you would like logged.
         */
        public static void w(String msg) {
            android.util.Log.w(TAG, buildMessage(msg));
        }
    
        /**
         * Send a WARN log message and log the exception.
         * @param msg The message you would like logged.
         * @param thr An exception to log
         */
        public static void w(String msg, Throwable thr) {
            android.util.Log.w(TAG, buildMessage(msg), thr);
        }
    
        /**
         * Send an empty WARN log message and log the exception.
         * @param thr An exception to log
         */
        public static void w(Throwable thr) {
            android.util.Log.w(TAG, buildMessage(""), thr);
        }
        
        /**
         * Send an ERROR log message and log the exception.
         * @param msg The message you would like logged.
         * @param thr An exception to log
         */
        public static void e(String msg, Throwable thr) {
            android.util.Log.e(TAG, buildMessage(msg), thr);
        }
    
        /**
         * Building Message
         * @param msg The message you would like logged.
         * @return Message String
         */
        protected static String buildMessage(String msg) {      
            StackTraceElement caller = new Throwable().fillInStackTrace().getStackTrace()[2];
    
             return new StringBuilder()
                    .append(caller.getClassName())
                    .append(".")
                    .append(caller.getMethodName())
                    .append("(): ")
                    .append(msg).toString();
        }
    }
    

    LogDemo.java:

    package org.lytsing.android.log;
    
    import org.lytsing.android.util.Log;
    import android.app.Activity;
    import android.os.Bundle;
    
    public class LogDemo extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            Log.i("index=" + 3);
        }
    }

    运行结果的Log信息,如下图:

    需要的话,懒得复制粘贴,可以下载Log.java压缩文件包Log.tar.gz

    此外Android 代码风格指南 特别说明了,日志记录开销很大,应尽量少用,写规范可靠的代码,减少对debug的依赖。

  • 结婚祝福

    在问问上看到一个帖子:
    我有一个同窗3年的初中女同学今天结婚了,至今有10年没见,我想写一篇大概100来字文言文格式送给她,希望大家帮忙出点主意!

    特别要求:不要七绝五言诗歌格式的,要有“吾呼哀哉”的那种文言文,就是古文那种,大概100字左右

    问题补充  2009-11-28 15:36

    对了,我跟她10年没见了,她也没有请我们这些同学,只是知道她今天结婚了,而且我们上班也没时间参加她的婚礼,只是因为同窗情谊,想用祝福语来表达自己的心意。

    提问人的追问   2009-11-28 18:15您的回答实在是差矣差矣!求人不如求己,我自己研究了一个下午终于写出来了,发给你看看也无妨!

    今是己丑冬月十一,吾一同窗陈素阳之新婚吉日,特此赋文以纪之,其辞曰:

    悠悠寒日,恰逢素阳良辰美景。忆往昔十载之今日,吾等皆埋头于九重卷章之下,错此吉日,吾今唯有悔之好玩矣,致使今朝前程未知,仕途坎坷;念今时此刻,亦 相隔浩程几许,且不能前去与汝祝之,心甚憾矣!然“相知无远近,万里尚为邻。”彼虽遥离故友,千里为祈福:光照前程似锦,霞映继途如花;姿容益比今昔好, 才华更胜往日佳;结五湖四海亲朋好友,识六路八方英雄豪杰!三年七载,同窗恰似千秋水;十天九岁,友谊可比万代疆!一心之中莫存隙,二根以内不杂愁;佛 曰:烟花非你,你非烟花。往事无须悼,此生明媚,明朝烟云笑!小女子唯有恭贺新婚之禧!百事皆可乐!