Android 上的 制表符(tab) —— 一个奇妙的字符 (cocos2dx crash)

今天測试发现了游戏的一个问题,系统邮件,假设发了tab,在android上一打开邮件内容就会crash。并且他们非常确定是tab的问题。

凭我多个月的经验(确实没多年。

。)来看。从来没听说在android上会由于一个tab崩溃。并且假设有这个问题。肯定会有非常多人遇到,预计早就吵翻天了,搜索了一下,什么可用信息都没有。

于是写个測试project測试了一下。分别在mac下和windows下,用文本编辑工具编辑了4个txt文档。utf有bom和无bom,内容是“ tab abcd ”,发现都能正常显示,也不会crash。

例如以下:

    unsigned long fSize = 0;
    unsigned char *data = CCFileUtils::sharedFileUtils()->getFileData("tab.txt", "rb", &fSize);

    CCLabelTTF *label = CCLabelTTF::create((const char*)data, "abc", 30);
    label->setPosition(ccp(visibleSize.width/2, visibleSize.height/2));

    addChild(label);

然后開始怒跟代码,发现project中使用了一个自己定义控件,是为了实现一个富文本框的功能。

所谓富文本框就是能显示各种颜色,能显示url,有的东西还能点的那种。可是这个东西的实现,当中有一步。是把一个utf8字符串拆开,拆成单个字符,把每一个字符的纹理做出来。然后来拼图,拼成一个文本框。那么tab肯定会被拆成单个字符,最后发现就是在生成这个tab的纹理的时候。crash了。堆栈例如以下:

顺便科普一下labelTTF显示的原理,大致就是。通过字体和字号,然后调用对应平台的api。生成一张图(image),注意是一张图啊,然后作为纹理,设置给一个精灵。从上面的堆栈来看,就是在生成这个image的时候crash了。

然后找代码,在CCTexture2D下找到上面堆栈的最后一步。例如以下:

bool CCTexture2D::initWithString(const char *text, const char *fontName, float fontSize, const CCSize& dimensions, CCTextAlignment hAlignment, CCVerticalTextAlignment vAlignment)
{
       … … … …
        do
        {
            CCImage* pImage = new CCImage();
            CC_BREAK_IF(NULL == pImage);
            bRet = pImage->initWithString(text, (int)dimensions.width, (int)dimensions.height, eAlign, fontName, (int)fontSize);
            CC_BREAK_IF(!bRet);
            bRet = initWithImage(pImage);
            CC_SAFE_RELEASE(pImage);
        } while (0);

    … … … …
        return bRet;
}

这里第一步是。new一个image出来。然后用文字去init这个image,然后再用这个image去init这个texture。

我们接着看init这个image这里。android下的代码是这种:

bool CCImage::initWithString(
                               const char *    pText,
                               int             nWidth/* = 0*/,
                               int             nHeight/* = 0*/,
                               ETextAlign      eAlignMask/* = kAlignCenter*/,
                               const char *    pFontName/* = nil*/,
                               int             nSize/* = 0*/)
{
    bool bRet = false;

    do
    {
        CC_BREAK_IF(! pText);

        BitmapDC &dc = sharedBitmapDC();
        CC_BREAK_IF(! dc.getBitmapFromJava(pText, nWidth, nHeight, eAlignMask, pFontName, nSize));

        m_pData = dc.m_pData;
        CC_BREAK_IF(! m_pData);

        m_nWidth    = (short)dc.m_nWidth;
        m_nHeight   = (short)dc.m_nHeight;
        m_bHasAlpha = true;
        m_bPreMulti = true;
        m_nBitsPerComponent = 8;

        bRet = true;
    } while (0);

    return bRet;
}

当中重点是getBitmapFromJava这个函数,例如以下

    bool getBitmapFromJava(const char *text, int nWidth, int nHeight, CCImage::ETextAlign eAlignMask, const char * pFontName, float fontSize)
    {
    	return  getBitmapFromJavaShadowStroke(	text, nWidth, nHeight, eAlignMask, pFontName, fontSize );
    }

从这里就知道了。肯定是把文字。字体。字号这些东西,叫给java层,让它们调用系统相关的东西,返回一个bitmap回来。然后就是下一步,把这个返回的image去初始化texture。可是不须要下一步了。由于到这就crash了。得到例如以下log:

从这个log看,大概意思就是java层在创建bitmap的时候。须要一个图片的宽高。可是这个大小等于0了。

可是之前測试是能够显示tab的,细致想想,之前的測试有一个问题,就是之前的測试都是tab加其它字符的混合,这个地方由于富文本框的处理,是单个tab字符,那么再用单个tab測试一下。果然就和上面一样crash了。

再回到这个crash log本身,这个要生成的图,就是写了字的那个图,那么这个图片的宽高应该取决于字符的内容和字符的大小,怎么会是0呢。难道是由于tab在android上面会被自己主动忽略。

立即再写个project測试:

    unsigned long fSize = 0;
    unsigned char *data = CCFileUtils::sharedFileUtils()->getFileData("tab.txt", "rb", &fSize);

    CCLabelTTF *label = CCLabelTTF::create((const char*)data, "abc", 30);
    label->setPosition(ccp(visibleSize.width/2, visibleSize.height/2));

    CCLayerColor *col = CCLayerColor::create(ccc4(123, 255,0 , 255));
    col->setContentSize(label->getContentSize());
    col->ignoreAnchorPointForPosition(false);
    col->setAnchorPoint(ccp(0.5, 0.5));
    col->setPosition(ccp(label->getPosition().x,label->getPosition().y));
    addChild(col);

    addChild(label);

这个測试和之前那个的差别,主要在于在文字后面加了一个同大小的色块,这样我们就能看到纹理的实际范围(早该如此,事实上是開始2了没想到。。

。),果然发现无论怎样加tab。tab都不会显示,纹理的大小和不加tab的大小是一样的。

假设在cocos2dx上是这样。可是他最后会调用到android系统的java层去生成这个bitmap,说明这个不是cocos2dx的问题,那么在android应用上。tab会不会被忽略呢,果断开个project再測试,例如以下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

        <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        android:background="#FFFF0000"/>
</LinearLayout>
<resources>
    <string name="app_name">tabTest</string>
    <string name="hello_world">		Hello world!</string>
    <string name="action_settings">Settings</string>
</resources>

果然还是没显示tab,哈哈哈哈哈,收工~~

总结:android系统会忽略tab,在cocos2dx里面用CCLabelTTF的时候。假设文本内容仅仅有一个tab字符,会crash。

时间: 2024-08-14 09:42:37

Android 上的 制表符(tab) —— 一个奇妙的字符 (cocos2dx crash)的相关文章

Android 上的 制表符(tab) —— 一个神奇的字符 (cocos2dx crash)

今天测试发现了游戏的一个问题,系统邮件,如果发了tab,在android上一打开邮件内容就会crash.而且他们很确定是tab的问题. 凭我多个月的经验(确实没多年...)来看,从来没听说在android上会因为一个tab崩溃,而且如果有这个问题,肯定会有很多人遇到,估计早就吵翻天了,搜索了一下,什么可用信息都没有. 于是写个测试工程测试了一下,分别在mac下和windows下,用文本编辑工具编辑了4个txt文档,utf有bom和无bom,内容是" tab abcd ",发现都能正常显

Android 上的 制表符(tab) —— 一个神奇的字符 (二)

接到上回的说,主要是上回那个问题,我觉得是android的bug,黎叔觉得是cocos2dx的bug,叫我去提交bug.所以我又继续研究了下. 上回说到会调用java层的函数去创建一个image,然后作为纹理设置给精灵,在那个地方crash了,此处代码如下: public static void createTextBitmapShadowStroke(String pString, final String pFontName, final int pFontSize, final float

Android上的HttpURLConnection

在Android上应该优先使用HttpURLConnection而不是HttpClient. conn.connect() 这句不需要显式调用,后面的方法会自动调用,但是显式调用了也不会怀孕. disconnect() 在其他的JVM实现中会关闭闲置的连接.所以一般不显示调用,但是Android的实现不同,需要调用 Once the response body has been read, the HttpURLConnection should be closed by calling dis

android上libevent dns解析的一个bug修复

在测试我们开发的一个 APK(使用了 libevent-2.1.3-alpha 作为网络库) 时发现一个奇怪的问题,域名解析有时报错 Non-recoverable name resolution failure .在公司偶尔报错,后来程序改动了一下,出错时重试几次,问题没再出现,以为好了.昨天换了个网络环境,结果报错几率变得非常大. 互联网搜索到这个错误的一个处理办法,说在使用 getnameinfo() 函数时需要显式指定其第二个参数 salen 为 sizeof(struct sockad

Android 上使用 iconfont 的一种便捷方案

最近在学习 AIOSO(Alibaba Internal Open Source Organization,即阿里巴巴内部开源组织) 的一个子项目MMCherryUI,这是一个流式布局,可以在运行时做动态改变子元素的个数(增删查改), 并内建动画效果,先贴一张效果图出来 我们学习代码,最重要的就是动手实践.于是,我想自己去实现一个类似上面效果的页面.首先,我需要页面上的几张 icon 图标,去哪里找?上 iconfont.cn 找,里面的 icon 最全了.这时候我脑子里浮现了一个问题,我是使用

Android 上千实例源码分析以及开源分析

Android 上千实例源码分析以及开源分析(百度云分享) 要下载的直接翻到最后吧,项目实例有点多. 首先 介绍几本书籍(下载包中)吧. 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android的GUI系统 07_Android的Audio系统 08_Android的Video 输入输出系统 09_Android的多媒体系统 10_

Unity3D之AssetBundle学习:Android上运行笔记

路径统一 在Android上加载StreamingAssets文件夹下的AssetBundle文件,首先需要对加载地址进行处理,注意PC.Android和IOS的地址不一致需要针对不同的平台不同的处理,通用代码如下: 1 //统一不同平台下 StreamingAssets 路径 2 public static readonly string STREAMING_ASSETS_PATH = 3 #if UNITY_ANDROID 4 "jar:file:///" + Applicatio

观察者模式在android 上的最佳实践

在上一篇文章中介绍了介绍了观察者模式的定义和一些基本概念,观察者模式在 android开发中应用还是非常广泛的,例如android按钮事件的监听.广播等等,在任何类似于新闻-订阅的模式下面都可以使用.从某种意义上面来说android有点像JAVA EE的WEB页面,在都需要提供View层用于进行操作,在多个页面之间传递数据发送通知都是一件很麻烦的事情. 在android中从A页面跳转到B页面,然后B页面进行某些操作后需要通知A页面去刷新数据,我们可以通过startActivityForResul

SharePanel – Android上简单的一键分享,可分享到微信QQ和新浪微博

SharePanel – Android上简单的一键分享,可分享到微信QQ和新浪微博 SharePanel Android上简单的一键分享可分享到微信QQ和新浪微博 简介 效果图 代码块 简介 最近在写一个小程序长微博工具,效果就是编辑长微博,然后一键分享到微信.QQ和新浪微博. 一开始是想直接用Intent.createChooser(target, title)来做,后来一想,这样做不是很好啊,会有许多乱七八糟的应用弹出来,我想优先分享到微信.QQ和微博,于是找了点资料,将一键分享这个部分做