一个封装 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您的回答实在是差矣差矣!求人不如求己,我自己研究了一个下午终于写出来了,发给你看看也无妨!

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

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

千万不要把Listview放在ScrollView里

晚上逛了一下 eoe android论坛,见到一坨人千方百计的把ListView弄到ScrollView,还研究出一些策略,并引以为豪。eoe market也是用这样的设计,滚动条显示很诡异,时长时短。ListView 本来是不应该 放在 ScrollView 里的,Google员工 Roman Guy早已回复:“There is no need to put a ListView in a ScrollView since ListView already supports scrolling. Do NOT put a ListView inside a ScrollView. ListView already handles scrolling, you’re only going to run into trouble. “ 更详细的,大家可以看看他在 google i/o 上的ListView视频讲解。大家不要抱着侥幸的心理,要用正确的方法去做正确的事情。如果真的需要ListView不同行显示这样的设计,可以参考Mark Murphy提供的http://github.com/commonsguy/cwac-merge

ListView和Gallery实现Market首页界面(补充版)

http://www.3gqa.com/?p=1941 可以看到沈青海老师的一段讲解视频。优酷的视频不是很清晰,可以在http://www.3gqa.com/?page_id=1307 页面按照提供的QQ登录网络硬盘下载高清版本。按视频动手写了一下,发现两个问题:
1. 用滑鼠无法滚动到Galllery的图片
2. 整个Galllery处于Selectable,很难看,如下图:
andriod market gallery demo
解决方法:
1. 在ListView ,调用requestFocus方法还不够, 还需要setItemsCanFocus。
2. 不让第0项处于可选中状态。
public boolean areAllItemsEnabled() {
    return false;
}

public boolean isEnabled(int position) {
    return position != 0;
}
ListView功能强大,除了上面所用的方法,还可以用 addHeaderView 的方法把Gallery加进来,实现同样的效果。addHeaderView的使用,请参阅android reference 或Mark Murphy 在《The Busy Coder’s Guide To Advanced Android Development》书中提供的HeaderFooter 示例。

CDMA MMS PUSH 彩信通知

这里用的模组是 via威盛的cdma。首先,设置短信通知格式:
AT+CNMI=2,1

用一cdma手机给模组发一条彩信,由于URL 链接较长,网络可能会连续发送多条(常见是 2 条)Wap Push 短信,应根据长短信标准拼接后再做进一步处理。

+CMT:”RAM”,4,186,”000002fdea020602069966084006010008a8000310f130018e0460001880
35000c2820c0008008fc02e11a4189185c1c1b1a58d85d1a5bdb8bdd9b990b9dd85c0b9b5b5ccb
5b595cdcd859d9402d21ebe12320a61113daddde108ccd5b19149040236420da1d1d1c0e8bcbcc4
c0b8c8ccd0b8c4ccdcb8c4c4e8e0c0e0c0bddd85ccbd113daddde108ccd5b1914904022016040c0a8
c02243600c4cccce4c8e0dcc4c8d0d40228003060907031436470a01400e06040d32cc1080″

+CMT:”RAM”,5,63,”000002fdea020602069966084006014c082d000310eb9001130088001880
35000850020000806023808a3dc003060907031436470a01400e06040d32cc1080″

分析一下第一条:

teleserviceId为65002,就可以判断这时一条彩信通知,GSM的是通过分析端口号来做判断。进一步分析,提取到 TP_UD为:

00 03 10 06 A0 01 85 04 18 00 10 01 1F 80 5C 23 48 31 23 0B 83 83 63 4B 1B 0B A34B 7B 71 7B B373 21 73 BB 0B 81 73 6B 6B 99 6B 6B 2B 9B 9B 0B 3B 28 05 A4 3D 7C 24 64 14 C2 227B 5B BB C2 1199 AB 63 22 92 08 04 6C 84 1B 43 A3 A3 81 D1 79 79 89 81 71 91 99 A1 71 89 99 B971 89 89 D1 C181 C1 81 7B BB 0B 99 7A 22 7B 5B BB C2 11 99 AB 63 22 92 08 04 40 2C 08 18 15 18 04 48 6C 01 8999 99 C9 91 C1 B9 89 91 A1 A8 04 50

Wap push短信 PDU 中的 User data,按照短信标准解析,前面部分是 Header信息,如 Msgid、Num_field 等,后面部分是 Chari 内容。Chari 内容需要再进一步解析,中国电信的 Wap Push 短信PDU 中的 User data 里的 Chari 也分为两部分,前半部分是 Header 信息,类似于 User data的 Header 信息,后面部分数据才是 WDP 数据,需要按照 WDP 协议(Wireless Datagram Protocol)进行解析。

WDP

Msg Indetifier:
SUBPARAMETER_ID        8       0000000
SUBPARAM_LEN     8       00000011
MESSAGE_TYPE     4       0001 (Deliver) /0010 (Submit)
MESSAGE_ID  16     -Generated –
HEADER_IND  1       0
RESERVED      3       000

User Data
SUBPARAMETER_ID        8       00000001
SUBPARAM_LEN     8       Number of Octets in this Sub Parameter, not including SUBPARAMETER_ID and SUBPARAM_LEN
MESSAGE_ENCODING   5       00000
MESSAGE_TYPE     0       Ignored
NUM_FIELDS  8       This field shall be set to the number of characters included in this subparameter.

CHARi      Variable   Characters. This shall include NUM_FIELDS occurrences of this field
RESERVED      0-7   All zeroes used for padding.

(This field shall contain the number of bits required to make the entire subparameter an integer number of octets in length.

CHARi
MSG_TYPE       8       00000000
TOTAL_SEGMENTS         8       Total  number of segments
SEGMENT_NUMBER       8       The Segment Number
DATAGRAM      (NUM_FIELDS – 3)*8         Segmented WDP Datagram

WDP Datagram Segment
SOURCE_PORT       16     Source Port
DESTINATION_PORT       16     Destination Port(2948)
DATA        N*8  N bytes of Data from the Layer above WDP

按照上面的格式,解析CHARI就是

00 02 00 23 F0 0B 84 69 06 24 61 70 70 6C 69 63 61 74 69 6F 6E 2F 76 6E 64 2E 77 61 70 2E 6D 6D73 2D 6D 65 73 73 61 67 65 00 B4 87 AF 84 8C 82 98 44 4F 6B 77 78 42 33 35 6C 6452 41 00 8D 9083 68 74 74 70 3A 2F 2F 31 30 2E 32 33 34 2E 31 33 37 2E 31 31 3A 38 30 38 30 2F77 61 73 2F 444F 6B 77 78 42 33 35 6C 64 52 41 00 88 05 81 03 02 A3 00 89 0D 80 31 33 33 39 3238 37 31 32 3435 00 8A

00 MSG_TYPE
02 TOTAL_SEGMENTS
00 SEGMENT_NUMBER
23 F0 SOURCE_PORT
0B 84 DESTINATION_PORT
69 06 24 61 70 70 6C 69 63 61 74 69 6F 6E 2F 76 6E 64 2E 77 61 70 2E 6D 6D73 2D 6D 65 73 73 61 67 65 00 B4 87 AF 84 8C 82 98 44 4F 6B 77 78 42 33 35 6C 6452 41 00 8D 9083 68 74 74 70 3A 2F 2F 31 30 2E 32 33 34 2E 31 33 37 2E 31 31 3A 38 30 38 30 2F77 61 73 2F 444F 6B 77 78 42 33 35 6C 64 52 41 00 88 05 81 03 02 A3 00 89 0D 80 31 33 33 39 3238 37 31 32 3435 00 8A DATA

这是第一条的 DATA,同样分析第二条的 TP_UD为:

00 03 10 06 A0 01 0A 00 40 00 10 0C 04 70 11 47 B8

CHARI为

00 02 01 80 8E 02 28 F7

DATA为80 8E 02 28 F7

和第一条合并起来,那么DATA就是

69 06 24 61 70 70 6C 69 63 61 74 69 6F 6E 2F 76 6E 64 2E 77
61 70 2E 6D 6D73 2D 6D 65 73 73 61 67 65 00 B4 87 AF 84 8C 82 98 44 4F 6B 77 78 42 33 35 6C 6452 41 00 8D 9083 68 74 74 70 3A 2F 2F 31 30 2E 32 33 34 2E 31 33 37 2E 31 31 3A 38 30 38 30 2F77 61 73 2F 444F 6B 77 78 42 33 35 6C 64 52 41 00 88 05 81 03 02 A3 00 89 0D 80 31 33 33 39 3238 37 31 32 3435 00 8A80 8E 02 28 F7

61 70 70 6C 69 63 61 74 69 6F 6E 2F 76 6E 64 2E 7761 70 2E 6D 6D73 2D 6D 65 73 73 61 67 65 00 == application/vnd.wap.mms-message

B4 87: Push Flags: 87
AF 84: X-Wap-Application: 04
8C 82: X-Mms-Message-Type: m-notification-ind
98 44 4F 6B 77 78 42 33 35 6C 6452 41 00   Transaction-ID: DOkwxB35ldRA
8D 90 : X-Mms-mms-version : 1.0
83 68 74 74 70 3A 2F 2F 31 30 2E 32 33 34 2E 31 33 37 2E 31 31 3A 38 30 38 30 2F77 61 73 2F 444F 6B 77 78 42 33 35 6C 64 52 41 00  Content-location:http://10.234.137.11:8080/DOkwxB35ldRA

88 05 81 03 02 A3 00 expirty:
89 0D 80 31 33 33 39 3238 37 31 32 3435  From: 1339287124
8A80  message-class:”personal”
8E 02 28 F7  message-size:

注: B4,AF,8C,98 等,是高位加1(0x80)之后的content type.

Pages: Prev 1 2 3 ... 11 12 13 14 15 16 17 18 19 20 21 Next