注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

分享,态度 ·~~

—— 十年太长,五年;如果可以回到五年前,你最想对那时候的自己说什么?

 
 
 

日志

 
 

解决ADT LogCat中文乱码问题  

2011-01-20 11:40:52|  分类: Android |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

这个问题从一开始接触到Android开发就困扰我很久了,平常除错少用中文log这个问题影响到不大,但是碰到需要把data (通常是远端的json or 本地端cache的sqlite)印出来观察这一种除错的情境时,这问题就头大了!

问了google也没有好解答,在android的google code里issue 1590就是在陈述这个问题,下面Comment提供的方法我试不出来,有趣的是用adb logcat在console下是不会有乱码的,所以问题一定出在ADT上,最近自已build了ADT trunk来用,刚好又遇到需要dump中文的data来debug的case,所以就尝试着自已来trace问题。

LogCat的相关的code都在LogPanel.java里,中文是我补充的一些注解...

public class LogPanel extends SelectionDependentPanel {
     private LogCatOuputReceiver mCurrentLogCat;

     //所有UI的Control都在這裡建立
     @Override
     protected Control createControl(Composite parent) {...}

     //自訂Filter的Tab都在這裡,Tab裡面有一個Table,Table包括5個TableColumn,分別是time、level、pid、tag和message
     private TabItem createTab(LogFilter filter, int index, boolean fillTable) {...}

    /**
      * Sent when a new device is selected. The new device can be accessed
      * with
{@link #getCurrentDevice()}.
      */
     @Override
     public void deviceSelected() {
         startLogCat(getCurrentDevice());
     }

     public void startLogCat(final IDevice device) {
         if (device == mCurrentLoggedDevice) {
             return;
         }

         // if we have a logcat already running
         if (mCurrentLoggedDevice != null) {
             stopLogCat(false);
             mCurrentLoggedDevice = null;
         }

         resetUI(false); //切換device時要清空Table所有的Row

         if (device != null) {
             // create a new output receiver
             mCurrentLogCat = new LogCatOuputReceiver();

             // start the logcat in a different thread
             new Thread("Logcat")  { //$NON-NLS-1$
                 @Override
                 public void run() {

                     while (device.isOnline() == false &&
                             mCurrentLogCat != null &&
                             mCurrentLogCat.isCancelled == false) {
                         try {
                             sleep(2000);
                         } catch (InterruptedException e) {
                             return;
                         }
                     }

                     if (mCurrentLogCat == null || mCurrentLogCat.isCancelled) {
                         // logcat was stopped/cancelled before the device became ready.
                         return;
                     }

                     try {
                         mCurrentLoggedDevice = device;
                         //會透過AdbHelper執行command,相當於adb logcat -v long,然後再把output丟給LogCatOutputReceiver parse
                         device.executeShellCommand("logcat -v long", mCurrentLogCat, 0 /*timeout*/); //$NON-NLS-1$
                     } catch (Exception e) {
                         Log.e("Logcat", e);
                     } finally {
                         // at this point the command is terminated.
                         mCurrentLogCat = null;
                         mCurrentLoggedDevice = null;
                     }
                 }
             }.start();
         }
     }
 }

class Device的method executeShellCommand有三个参数分别是String command, IShellOutputReceiver receiver, int maxTimeToOutputResponse,它会透过class AdbHelper来做一下adb utility的指令操作。

在第xx行时,执行了logcat -v long并把输出丢给LogCatOutputReceiver处理,所以我们的重点在于class LogCatOutputReceiver。

继续追进去method executeShellCommand会发现它会把所有接收的data丢给interface IShellOutputReceiver的method addOutput处理,现在这个角色就是class LogCatOutputReceiver,而它的method addOutput是继承class MultiLineReceiver而来,问题就出在这里,把ISO -8859-1改成UTF-8就可以了...

public abstract class MultiLineReceiver implements IShellOutputReceiver {
     /* (non-Javadoc)
      * @see com.android.ddmlib.adb.IShellOutputReceiver#addOutput(
      *      byte[], int, int)
      */
     public final void addOutput(byte[] data, int offset, int length) {
         if (isCancelled() == false) {
             String s = null;
             try {
                 s = new String(data, offset, length, "ISO-8859-1"); //問題在這,把所有輸出的字串都使用ISO-8859-1 decode
             } catch (UnsupportedEncodingException e) {
                 // normal encoding didn't work, try the default one
                 s = new String(data, offset,length);
             }

             // ok we've got a string
             if (s != null) {
                 // if we had an unfinished line we add it.
                 if (mUnfinishedLine != null) {
                     s = mUnfinishedLine + s;
                     mUnfinishedLine = null;
                 }

                 // now we split the lines
                 mArray.clear();
                 int start = 0;
                 do {
                     int index = s.indexOf("\r\n", start); //$NON-NLS-1$

                     // if \r\n was not found, this is an unfinished line
                     // and we store it to be processed for the next packet
                     if (index == -1) {
                         mUnfinishedLine = s.substring(start);
                         break;
                     }

                     // so we found a \r\n;
                     // extract the line
                     String line = s.substring(start, index);
                     if (mTrimLines) {
                         line = line.trim();
                     }
                     mArray.add(line);

                     // move start to after the \r\n we found
                     start = index + 2;
                 } while (true);

                 if (mArray.size() > 0) {
                     // at this point we've split all the lines.
                     // make the array
                     String[] lines = mArray.toArray(new String[mArray.size()]);

                     // send it for final processing
                     processNewLines(lines);
                 }
             }
         }
     }
 }

修正前后的比较图:

解决ADT LogCat中文乱码问题 - 乂乂 - 一个人,一支烟  ·~~ 
修正前

解决ADT LogCat中文乱码问题 - 乂乂 - 一个人,一支烟  ·~~ 
修正后

patch我已送到android的gerrit(review system),很快的就收到review的comment了!看的出来他们考虑的比较严仅,但这一点小修改却是会影响大多数非英语系开发者,于是我又不放弃的继续trace,搞清楚adb server、daemon和client之间的关系,我的看法是可以把问题简单化成前端显示资料的编码问题,但我必需说服他们这一个修改是有帮助而且对系统是没有伤害的,所以我得继续努力,希望下一版ADT release时就不会再有这个问题了,如果最后不接受,就改在ADT LogCat的设定加上encoding的选项努力看看...
【from Be Logging(大牛!) http://blog.gasol.tw/2010/12/adt-logcat.html

  评论这张
 
阅读(4267)| 评论(2)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017