HABIT IS POWER

习惯就是力量

0%

===========

问题原因

绝大部分的中文乱码是因为文件编码不对导致的:

  1. 使用了GBK的文件编码方式在Xcode下是无法识别的
  2. 老版本的Xcode对带BOOM头的UTF8文件编码也是无法识别的(我的Xcode 5.0.2已经支持带BOM头的UTF8文件了)

出现上述情况一般都是因为跨平台共用文件导致的,Windows,Mac共同使用的代码文件会出现乱码的问题。

最好的解决方案

Windows和Mac下统一使用UTF8带BOM头的文件编码格式。

特别解释下

以前是这样的:

UTF8不带BOM头的文件,在xcode和eclipse下显示正常,但Windows下会中文乱码;

UTF8带BOM头的文件,Windows下显示正常,但Xcode和eclipse下会中文乱码;

现在是这样的:

Xcode 5.0.2和ADT 22.3.0都已经支持显示带BOM头的UTF8格式。

Mac下遇到这种乱码怎么解决

方法一:使用Sublime的解决办法

Sublime Text 2下,使用Package Control 安装 ConvertToUTF8 这个插件:

  1. 使用Sublime打开乱码文件,正常是可以自动识别出来是GBK还是GB2312等编码的
  2. 如果识别不出来,那么就手动选择下菜单File-》Reload With Encoding,选择GBK,应该也能正确显示中文了
  3. 正确显示中文后,就可以把文件保存成UTF8格式了,但是直接Save是不行的,保存之前必须先做一件事情:

    File -> Set File Encoding to -> UTF8

  4. 保存文件

方法二:Xcode的File inspector属性窗口

  1. 在工程中打开乱码的文件,选择File inspector属性窗口

  2. 选择Text Encoding,比如我选择“GB 2313”(不对的话可以换着试试看)

  3. 弹出提示,选择“Reinterpret”,如果中文显示正确,就下一步,否则就再换个编码试试

    Do you want to convert the text to ‘Simplified Chinese (GB 2312)’?

    Choose ‘Convert’ if you want to change the contents of the file to be encoded as ‘Simplified Chinese (GB 2312)’.

    Choose ‘Reinterpret’ if you believe the file has been opened with an incorrect encoding and you want to reopen it as ‘Simplified Chinese (GB 2312)’.

  4. 把成功显示中文后的文件保存成UTF8格式:

再选择下Text Encoing->UTF8,这次出现的提示选择Convert

  1. 搞定

问题

Xcode 5.0.2下编译Cocos2d-x工程,工程中使用了jsoncpp-0.5.0,编译的时候出现这个问题,找了半天不知道怎么解决:

semantic issue
Variable has incomplete type ‘Json::StyledWriter’

解决方案

升级jsoncpp-0.6.0后解决,我用的是这个版本:github jsoncpp

目标

把Wikidot的Blog数据迁移到Jekyll

目标分解:

  • Blog原文从之前的Wiki格式转换成Markdown
  • 保持原有的文章发布时间,标题,文章的Url,tag信息

PS.

为什么把博客从Wikidot迁移出来?
为什么选择Github Pages + Jekyll 而不是Farbox或者其他?
这个先沉淀下,同时也用段时间验证下,过段时间再和大家分享。

问题分析

基本情况介绍

  • Wikidot支持Backup,但是备份出来的数据压缩包解压出来就是些纯文本,文件名是url名字,文件内容就是Wiki格式的文章内容,没有文章发布的时间,没有tag信息;
  • 想拿到全的RSS,但试了半天RSS还是只导出了22篇文章,不知道怎么拿到老的数据RSS。

尝试 1:能不能直接使用 Jekyll-import

  • 我也想用,但是没找到直接对Wikidot的支持,对Wiki格式的支持也没有;
  • 如果想从RSS导入的话,Wikidot导出的RSS又不全
  • 无奈放弃

尝试 2:能不能曲线救国,先转成Wordpress再转

看了下,有位哥们脚本实现了:wikidot-to-markdown,但是他只是对格式的转换,这个代码我可以复用,但是……

但是来了:

  • 前提是我得先有数据给他转换,从上面介绍Wikidot直接提供给我们的数据是不够的

  • 我的目的是放到Jekyll上,也就是说我的文件头需要加上Jakyll的配置,这个我还得另外写个脚本来做

  • 需求描述变成了:

    1
    2
    1. 从Wikidot拿到所有文章的索引信息(Title,Url,tags,Date),和backup中的文件关联起来;
    2. 再处理下backup中的文件,加上文件头,把正文从Wiki转成Mardown

到此,问题分析的七七八八了,结论是我要写个脚本来做这个事情。

解决方案

拿到WIkidot所有文章的索引

没能拿到全的RSS,但是全的索引还是可以拿到的,但是需要再wikidot下页面单独来做这个事情,比如我的:

http://www.linyehui.com/misc:rss

这个Wikidot页面的源码如下:

1
2
3
[[module ListPages category="_default" perPage="500" date="@URL" separate="false" prependLine="||~ Page||~ Date created||~ Tags ||"]]
|| %%linked_title%% || %%date%% || %%tags%% ||
[[/module]]

从Wikidot后台Backup并下载Zip包

解压后的文件路径类似:

~/backup_linyehui_20140705_1759UTC/source/system_recent-changes.txt

写脚本

有了上面两步,我就能拿到全索引,并用索引把backup目录下的文件关联起来了
对脚本感兴趣的可以直接看代码:

https://github.com/linyehui/migrating-from-wikidot-to-jekyll

这里说下脚本的使用方式:

  1. git clone 得到两个脚本文件

    git clone https://github.com/linyehui/migrating-from-wikidot-to-jekyll

  2. 从Wikidot 管理后台备份Blog,并下载下来,解压后得到source目录,放到脚本下的wikidot根目录(是的,我的脚本不对文件进行处理)

  3. 新建一个Wikidot页面,用于生成所有文章的RSS(我这文章数上限设置的是500,你可以自己调整),生成的RSS保存成rss.html,把文件复制到脚本下的wikidot根目录

    我新建了这个页面:

    http://www.linyehui.com/misc:rss

    页面代码如下(点击Edit就能编辑):

    1
    2
    3
    [[module ListPages category="_default" perPage="500" date="@URL" separate="false" prependLine="||~ Page||~ Date created||~ Tags ||"]]
    || %%linked_title%% || %%date%% || %%tags%% ||
    [[/module]]
  4. 现在的脚本目录结构如下:

    1
    2
    3
    4
    5
    6
    7
    |----wikidot
    | |-convert.py
    | |-wikidot.py
    | |-rss.html
    | |-source
    | |- xxxx-xxx1.txt
    | |- xxxx-xxx2.txt
  5. 执行convert.py,不带参数会使用默认的目录结构进行执行,执行后你就能再脚本旁边的./jekyll目录下得到你所需要的转换后的.markdown文件们

  6. 把.markdown文件全选,复制到github pages对应git目录下的_post目录,git commit,git push

  7. 迁移工作搞定。

需求描述

  1. 我们的产品分为大厅和游戏两大模块,大厅使用iOS或Android SDK直接开发,游戏内嵌在大厅中,但是使用cocos2dx开发;
  2. 我们希望把大厅和游戏从project上分开来,省的代码缴在一起编译,看着都恶心
  3. Andoird下已经实现上述需求,大厅使用SDK开发,游戏作为Library提供给大厅直接调用
  4. 现在我们需要把iOS下的cocos2dx工程也改造成一个Library提供给大厅调用。

前提

Mac下已经配置好了cocos2dx的开发环境,Sample中的HelloCpp工程可以在Xcode下成功编译并运行

操作步骤

1. 把HelloCpp工程从Cocos2dx目录下复制出来

问题:复制出来后会提示cocos2d.h文件找不到

原因

原因是Sample工程设置的include路径是按照工程再cocos自己的目录下来设置的,把工程复制出来后路径就变了

解决方案
  1. 先添加一个SourceTrees变量

    Perferences->Locatons->Source Trees
    添加一个COCOS2DX_HOME变量,并把path设置成本机的cocos2dx根目录

  2. 修改工程Targets中的Header Search Paths

    点击工程->Targets->HelloCpp->Build Settings->Search Paths->Header Search Paths
    把值修改成这个:

    “$(SDKROOT)/usr/include/libxml2/“ “$(COCOS2DX_HOME)/cocos2dx/include” “$(COCOS2DX_HOME)/cocos2dx” “$(COCOS2DX_HOME)/cocos2dx/platform/ios” “$(COCOS2DX_HOME)/cocos2dx/kazmath/include” “$(COCOS2DX_HOME)/external/chipmunk/include/chipmunk”

  3. Clean工程,然后再次Build,成功

2. iOS工程启动先进入UIView,再跳转到Cocos2d场景,并可以跳转回来

先把HelloCpp工程调整成这样

发现这个文章做了我想做的事情的一部分:
Cocos2d-x UIView和Coco2d-x场景之间的相互跳转切换

如何结合使用Cocos2d和UIKit 第一部分

3. 新增HelloCpp Target:Static Library

在Library的Target中有几个点需要参考默认Target的配置:

  1. 不使用ARC

    Object-C Automatic Reference Counting —–> NO

  2. Search Path,直接复制默认Target的配置即可

    “$(SDKROOT)/usr/include/libxml2/“ “$(COCOS2DX_HOME)/cocos2dx/include” “$(COCOS2DX_HOME)/cocos2dx” “$(COCOS2DX_HOME)/cocos2dx/platform/ios” “$(COCOS2DX_HOME)/cocos2dx/kazmath/include” “$(COCOS2DX_HOME)/external/chipmunk/include/chipmunk”

  3. 修改预编译宏定义 Preprocessor Macros,也是直接复制默认的Target配置就可以了

    USE_FILE32API CC_TARGET_OS_IPHONE COCOS2D_DEBUG=1
    USE_FILE32API CC_TARGET_OS_IPHONE

  4. 添加对libcocos2dx.a的依赖

    Build Phases->Link Binary With Libraries

  5. 新的Target配置成功后会编译出.a文件

4. 新增工程GamesHall用于调用library

  • 把HelloCpp工程添加到GamesHall下
  • 在Target中添加对libhellocpp.a的依赖
  • 不添加任何代码,编译工程,可以运行
  • 如果不能运行要按照错误提示进行修改,很有可能是libhellocpp.a没有编译出来,那就要检查下上面的步骤,看新增的Static Library的Target是不是配置的有问题
  • 配置正确的话,GamesHall编译后可以再调试目录(Debug-iphonesimulator)下看到libhellocpp.a和libcocos2dx.a还有include目录都正确复制过来了

/Users/linyehui/Library/Developer/Xcode/DerivedData/GamesHall-ezsoyplchjjurfeznsedhgwywbkr/Build/Products/Debug-iphonesimulator

5. 添加代码调用

  • 添加后发现link失败,找了好多原因,最后有效的是这个:
    IOS7 (only) stdlibc++ linking issue
  • 改完stdlib后又提示zlib相关的几个函数找不到
    工程依赖加上libz.dylib

6. 调用成功,独立成Static Library没问题

7. 尝试多个游戏一起加入进来

  • 单个HelloCpp是OK的

  • 两个一起加会编译失败但没有具体失败的项,只有Warning,很奇怪

  • 两个分别成功加进去,并正确运行后,再把两个加到一起,可以运行,但是第二个游戏错乱了,还要再找下原因

  • 第二个游戏不是乱了,而是显示了第一个游戏的场景;原因是:

    注册cocos2d::CCApplication用的是一个全局静态变量,而不是注册上去的,我们有两个游戏,其实有两个这个全局变量的实现,用来处理cocos的启动跟暂停;
    而且我们的runWithScene是在这个里面调用的,所以导致了,两个游戏启动的时候都调用到了同样的场景。

  • 尝试自己runWithScene,看看能不能把两个游戏分开
    CCApplication的之类全局自定义一个,然后runWitSenne拿到cocosView中来分别处理,可以做到,但是这个方案并不好,下面单独解释。

两个工程合在一起的问题

结论:

不要把两个独立的游戏座位Library整合在一个应用内。
技术上可以实现,但是Cocos架构不支持,勉强自己改来用的话出现莫名其妙问题的风险很大。

非要实现的细节和缺陷

  1. Cocos本身的设计没有考虑这种一个进程多个游戏的架构,我们使用会有架构风险
    比如cocos2d::CCApplication的事件注册并不是Add上去,而是定义一个全局变量来实现,这个设计本身就没考虑多个实例同时存在

    // cocos2d application instance
    // 两个游戏加到一个工程的时候只能保留一个,否则会从Cocos内部直接异常退出
    // 变量名不同也没用,因为实际起作用的是父类CCApplication的成员变量
    // static CCApplication * sm_pSharedApplication;


    //static CocosAppDelegate s_sharedApplication;
    解决的办法,是多个游戏只保留一个CCApplication之类的全局变量的定义。

  2. 本来应该每个游戏自己响应CCApplication事件并做出处理,现在这个点不能做了,架构上本身就有问题,和把游戏整个在一个Cocos实例下没有本质的区别,未知的问题还更多

  3. Xcode对于这种多个Library依赖同一个Library的编译支持有时候会出错
    会出现上面提到的:提示编译失败,但是没有列出具体失败的地方,如果这个时候把其中一个游戏工程删掉,错误的地方就能正确被提示

关于静态库对安装包大小的影响

以下三个包,资源都是一样的,只是库文件上有差异

只有大厅,不包含游戏库,.app大小235KB

just_hall.png

大厅+一个cocos2dx游戏Library,.app大小3.5MB

one_game.png

大厅+两个cocos2dx游戏Library,.app大小3.2MB

two_games.png

科学吗?差不多是这个意思

其他参考文章

iOS 静态类库项目的建立与使用

1. 新建一个Empty Application的工程

Xcode->New Project->Empty Application

2. 填上工程的名字,比如HelloWorld,其他的保持默认,然后点击“Next”

3. 选择工程保存的路径,然后点击“Create”

4. File->New File->左边的导航选择Cocoa Touch->右边选择Objective-C Class->点击“Next”

5. 配置下类的信息如下:

Subclass of:UIViewController (这个先填,Xcode会帮你生成Class的值)
Class:HelloWorldUIViewController
Targeted for iPad:不勾选
With XIB for user interface:勾选
然后点击“Next”

6. 选择路径后,点击“Create”

你会发现工程下新增了三个文件:
HelloWorldUIViewController.h
HelloWorldUIViewController.m
HelloWorldUIViewController.xib

7. 把新建的UIViewController显示到界面上

7.1 打开AppDelegate.m文件,并在

#import “AppDelegate.h”
之后加上一句
#import “HelloWorldUIViewController.h”

7.2 在这句注释之后添加两行我们的代码

// Override point for customization after application launch.
修改后的代码如下:

// Override point for customization after application launch.
    HelloWorldViewController *hvc = [[HelloWorldViewController alloc] init];
    [[self window] setRootViewController:hvc];

8. 编译,运行

===The End===

问题

Android工程不小心点击了Android Tools->Add Native Support,怎么还原

还原步骤

1. 删除工程根目录的 .cproject文件

2. 删除.project中的cdt部分

  • Add Native Support后的工程会在下多出一个XML段,找到包含cdt的buildCommand XML段删除
  • Add Native Support后的工程会在下多出几个包含cdt的XML段,删除

3. 回到Eclipse,刷新,右键工程->Android Tools->Add Native Support又回来了

#不折腾不舒服斯基

—–The End—–

遇到了好多异常,逐一介绍解决方案如下。

java.lang.RuntimeException: autoFocus failed at android.hardware.Camera.native_autoFocus

autoFocus 时机不对导致的Crash,异常信息:

java.lang.RuntimeException: autoFocus failed at android.hardware.Camera.native_autoFocus

得到的用户反馈描述:

Sony s39h 一点拍摄视频就crash,从他们上传上来的log看是autoFocus的时候crash了,找了下资料,这个比较接近:Android Camera.autoFocus() failed

参考上面的文章在我们的代码中发现了一个调用时机不对的autoFocus(),去掉,搞定。

java.lang.RuntimeException: startPreview failed

老的系统版本需要调用SurfaceView的 setType,异常信息:

06-19 21:25:28.730: E/AndroidRuntime(1082): FATAL EXCEPTION: main
    06-19 21:25:28.730: E/AndroidRuntime(1082): java.lang.RuntimeException: startPreview failed
    06-19 21:25:28.730: E/AndroidRuntime(1082): 	at android.hardware.Camera.startPreview(Native Method)
    06-19 21:25:28.730: E/AndroidRuntime(1082): 	at com.duowan.huanjuwan.app.truthordare.MediaActivity$1.surfaceChanged(MediaActivity.java:413)

解决方案

只需要加上setType这个修改就可以了,但是代码加的位置有讲究,要在getHolder().addCallback之后加才可以

getHolder().addCallback(this);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

心路历程

解决问题的过程比结果更优价值 :)

搜索到描述最接近的一文章:

Android Camera will not work. startPreview fails
试了下里面的代码,没有解决

其他的参考文章:

Issue 7909:Camera preview does not work on HTC Desire
java.lang.RuntimeException: startPreview failed

再试下这个:

#34 paul.won...@gmail.com
Hi everyone,


I'm new to Android but encountered the same problem.  Could it be the case that the width and height parameters are not called properly?  I added the following two lines before parameters.setPreviewSize and it now seems to work fine.


w = parameters.getPreviewSize().width;
h = parameters.getPreviewSize().height;
        

For the record, I am using a HTC Desire too.


Cheers,


Paul

还是不行

尝试下用Demo来调试

Demo加了两个地方,成功跑起来了,要看下能不能具体到只加一个就可以

@SuppressWarnings("deprecation")
        public void initCameraManager(Context paramContext) {
            cameraManager = ((MainActivity) paramContext).getCameraManager();
            getHolder().addCallback(this);
            getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }



int preview_width = parameters.getPreviewSize().width;
                int preview_height = parameters.getPreviewSize().height;
                parameters.setPreviewSize(preview_width, preview_height);
                Log.e("video", "Width: " + preview_width + ", height: " + preview_height);
                //parameters.setPreviewSize(640, 480);
                camera.setParameters(parameters);

确认了:只需要加上setType这个修改就可以了,比较奇怪的是我昨天在我们的产品工程加了,但还是crash了,可能是加的位置不对

getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

回我们的产品工程再验证下

果然是加的位置不对,要在getHolder().addCallback之后加才可以

getHolder().addCallback(this);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

java.lang.NoSuchFieldError: android.os.AsyncTask.THREAD_POOL_EXECUTOR

THREAD_POOL_EXECUTOR在Level 11后才有,需要做系统版本判断再调用,异常信息:

06-20 12:36:06.410: E/AndroidRuntime(1613): FATAL EXCEPTION: main
    06-20 12:36:06.410: E/AndroidRuntime(1613): java.lang.NoSuchFieldError: android.os.AsyncTask.THREAD_POOL_EXECUTOR
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at com.duowan.huanjuwan.app.camera.AutoFocusManager.onAutoFocus(AutoFocusManager.java:67)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at android.hardware.Camera$EventHandler.handleMessage(Camera.java:559)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at android.os.Handler.dispatchMessage(Handler.java:99)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at android.os.Looper.loop(Looper.java:130)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at android.app.ActivityThread.main(ActivityThread.java:3703)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at java.lang.reflect.Method.invokeNative(Native Method)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at java.lang.reflect.Method.invoke(Method.java:507)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
    06-20 12:36:06.410: E/AndroidRuntime(1613): 	at dalvik.system.NativeStart.main(Native Method)

参考这个文章解决了:Android 2.3.3 AsyncTask call throws NoSuchFieldError

@TargetApi(11)
  static public <T> void executeAsyncTask(AsyncTask<T, ?, ?> task,
                                          T... params) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    }
    else {
      task.execute(params);
    }
  }

可以启动并预览,但是一开始录制视频,画面就卡住,没Crash

异常信息:

06-20 12:53:07.766: E/AndroidRuntime(1682): FATAL EXCEPTION: main
    06-20 12:53:07.766: E/AndroidRuntime(1682): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:419)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:432)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at com.duowan.huanjuwan.app.truthordare.MediaActivity$9.onPictureTaken(MediaActivity.java:446)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.hardware.Camera$EventHandler.handleMessage(Camera.java:529)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.os.Handler.dispatchMessage(Handler.java:99)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.os.Looper.loop(Looper.java:130)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at android.app.ActivityThread.main(ActivityThread.java:3703)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at java.lang.reflect.Method.invokeNative(Native Method)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at java.lang.reflect.Method.invoke(Method.java:507)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
    06-20 12:53:07.766: E/AndroidRuntime(1682): 	at dalvik.system.NativeStart.main(Native Method)
    06-20 12:53:08.207: W/AutoFocusManager(1682): Unexpected exception while focusing
    06-20 12:53:08.207: W/AutoFocusManager(1682): java.lang.RuntimeException: autoFocus failed
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at android.hardware.Camera.native_autoFocus(Native Method)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at android.hardware.Camera.autoFocus(Camera.java:650)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at com.duowan.huanjuwan.app.camera.AutoFocusManager.start(AutoFocusManager.java:82)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at com.duowan.huanjuwan.app.camera.AutoFocusManager$AutoFocusTask.doInBackground(AutoFocusManager.java:118)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at android.os.AsyncTask$2.call(AsyncTask.java:185)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
    06-20 12:53:08.207: W/AutoFocusManager(1682): 	at java.lang.Thread.run(Thread.java:1019)
    06-20 12:53:10.198: I/Process(1682): Sending signal. PID: 1682 SIG: 9
    06-20 12:53:10.539: I/dalvikvm(1884): Could not find method android.view.Display.getSize, referenced from method com.duowan.huanjuwan.app.common.Utils.getDisplaySize
    06-20 12:53:10.549: W/dalvikvm(1884): VFY: unable to resolve virtual method 7806: Landroid/view/Display;.getSize (Landroid/graphics/Point;)V
    06-20 12:53:10.549: D/dalvikvm(1884): VFY: replacing opcode 0x6e at 0x0017

结论是老的机器内存不足,使用之前清理下内存就好了,这个就不是单纯一两行代码的问题,整个应用的内存使用都要Review下。

———-The End———–

产品名称 同步到Evernote 同步到Dropbox 整体描述 链接

| 马克飞象|支持|不支持|目前体验最好的一个,但是服务器不是很稳定,作者说是Evernote的问题,需要再观察下,这也是为什么我会写这篇文章的原因:马克飞象出问题的时候,我需要一个临时的替代品|链接 |

| stackedit.io|不支持|支持|除了不支持Evernote,其他的功能和马克飞象比起来是最类似的(编辑体验,快捷键等);支持Dropbox,Google Drive自动同步,但需要自己指定下保存的文件路径;还有个缺点是没有Evernote分享那么强大的功能,只能是先保存成HTML然后再分享HTML文件的链接;整体看stackedit的功能和配置更多,但不支持Evernote确实减分不少,可以作为一个备选方案|链接 |
| Farbox|不支持|支持|Dropbox+Markdown的可加密Blog系统,还是很好用的,但是不能实时预览,文件名等会自动保存,算数没有实时预览的在线编辑器中最好的一个,可以作为一个备选方案|链接 |
| Markable|支持|支持|编辑的时候,输入法的体验不好,保存的时候需要自己输入文件名,这个体验很不好|链接 |
| 小书匠|支持|不支持|编辑的体验还可以,但是保存和同步到Evernote的体验比较差,每次同步都需要自己选择文件名|链接 |
| Sublime + 插件Evernote + 插件Markdown Preview| 支持 | 支持 | 可以做到双向同步,但是体验上没有实时预览,保存的时候到时可以不用自己写文件名,但是快捷键调用命令行来保存还是稍微麻烦了一点,另外保存下来的文本CSS不好看,需要自己再调整;整体来说这个组合是非常强大的,但是就是需要自己做太多的事情|本地方案 |
| Markdown Here | 可以再Evernote页面中使用 | 不支持 | 比较灵活的一个方案,缺点是不能实时预览(HTML和Markdown可以切换,但需要全选文字,右键-》Markdown Toggle)| Chrome插件 |
| 简书Markdown编辑器 | 不支持 | 不支持 | 这编辑器确实漂亮,要是能同步到Evernote就好了 | 链接 |

Android下对应用进行抓包分析,有很多文章已经介绍过了,大家可以参考:

我的实际操作参考的是这篇:
Android利用Fiddler进行网络数据抓包

其他的参考文章:
android应用安全——(数据抓包)跟踪监控android数据包

Android抓包方法(一)之Fiddler代理
Android抓包方法(二)之Tcpdump命令+Wireshark
Android抓包方法(三)之Win7笔记本Wifi热点+WireShark工具

我们今天的问题是:

Android怎么对cURL进行抓包?
或者说为什么普通的抓包方法不能抓到cURL的网络数据包?

原因

cURL不会直接使用系统的代理设置,所以使用HTTP代理来抓包的方式,默认情况下都是无法抓取到cURL的数据包的

解决方案

cURL设置下代码就好了(我嚓咧,这么简单……)

以我的Fiddler2为例,代码中设置下这个代理就能顺利抓取到cURL的数据包了

curl_easy_setopt(m_pCurlHandle, CURLOPT_PROXY, "192.168.123.1:8888");
curl_easy_setopt(m_pCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);

cURL超时怎么处理

处理的原则是:

  1. CURLOPT_TIMEOUT和CURLOPT_CONNECTTIMEOUT都必须设置!
  2. 需要的话可以把CURLOPT_DNS_CACHE_TIMEOUT 设置长一点;
  3. 多线程使用cURL,需要设置CURLOPT_NOSIGNAL

我们的代码一开始没有设置CURLOPT_CONNECTTIMEOUT,结果偶尔会遇到服务器返回502超时,看log最长的一次竟然卡了93秒……

cURL参数说明

CURLOPT_TIMEOUT 设置cURL允许执行的最长秒数。  

CURLOPT_TIMEOUT_MS 设置cURL允许执行的最长毫秒数。 


CURLOPT_CONNECTTIMEOUT 在发起连接前等待的时间,如果设置为0,则无限等待。  

CURLOPT_CONNECTTIMEOUT_MS 尝试连接等待的时间,以毫秒为单位。如果设置为0,则无限等待。 


CURLOPT_DNS_CACHE_TIMEOUT 设置在内存中保存DNS信息的时间,默认为120秒。

C++代码

curl_easy_setopt(_handler,CURLOPT_TIMEOUT,_timeout);  

        curl_easy_setopt(_handler,CURLOPT_CONNECTTIMEOUT_MS,_connect_timeout_ms);  

        curl_easy_setopt(_handler,CURLOPT_DNS_CACHE_TIMEOUT,_dns_cache_timeout);  

        curl_easy_setopt(_handler,CURLOPT_NOSIGNAL,1);

关于cURL的超时处理,这几篇文章值得参考:

curl超时问题追查
初窥curl(上)
Libcurl多线程crash问题
小谈libcurl

—–End—–

关于养宠物,一直想表达点什么,但总是话在嘴边却说不出个所以然。


做了三个月爸爸之后,我开始有点明白:
喜欢小猫小狗,和养一只小猫小狗……
喜欢小孩,和养育一个小孩……


两者有个相同点:
养育,只有喜欢是不够的,需要你满满的爱,满满的。