
Emoji从最早开始到现在,比较通用的是两种编码方案,分别是Softbank和Unicode,android版微信早期也是使用Softbank编码,然后客户端根据表情对应的Softbank编码使用SpannableString在TextView, EditText中显示成对应的表情,此时Emoji表情的集合还不是很多,微信只打包进去了大概400多个左右,在早期可以满足大部分Emoji表情的显示需求
但是,随着Unicode 60以及Unicode 70的发布,越来越Emoji表情被加入到这个标准当中,iOS系统自行扩展OpenType标准,通过Apple Color Emojittf这个字体来讲Emoji表情直接显示出来(OSX下也有这个字体,在/System/Library/Fonts/Apple Color Emojittf),当时国外也有对这个问题进行过讨论:Color bitmapfonts thanks to Apple! ,但是,由于新加进来的表情都没有对应的Softbank编码,无法转码成Softbank,并且客户端在打包的时候只放进了400多个Emoji表情,所以在显示的时候,只能转换成""来显示
后来,随着越来越多表情不能显示,我们这边曾经尝试过直接在客户端使用unicode编码,并尝试过一次对外的灰度,在灰度的过程中,我们发现了一些crash,占的总量还不低,crash的堆栈大概是这样的:
at androidtextSpannableStringInternalgetChars(SpannableStringInternaljava:102)
at androidtextTextUtilsgetChars(TextUtilsjava:105)
at androidtextLayoutprocessToSupportEmoji(Layoutjava:3747)
at androidtextLayoutsupportTabandEmoji(Layoutjava:3783)
at androidtextLayoutmeasureText2(Layoutjava:3141)
我们注意到了 processToSupportEmoji 这个方法,明显不是属于Android系统原有的方法,应该是某些rom自行更改出现的问题,google一下,果不其然,在某些MTK的rom中有这样的一段代码,是属于processToSupportEmoji中的:
int length = end - start +1;
char[] chs = TextUtilsobtain(length);
TextUtilsgetChars(text, start, end, chs, 0);
for (int i = start ; i < end; i++) {
char c = chs[end-start];
if (c >= 0xD800 && c <= 0xDFFF && i + 1 < length) {
char[] tmp = TextUtilsobtain(2);
TextUtilsgetChars(text, i, i+2, tmp, 0);
可以看出这段代码对数据越界的保护是错误的,很容易就crash,有兴趣可以看下这篇文章:Android程序自动退但是没有提示任何错误
发生这个crash的大部分都是23系统的手机,也有一部分是4x,sony的一些机器也有,估计是复用了同一份代码。
So,问题的答案到这里就很明显了,将部分表情替换成点点的原因主要是这样的:
1 大部分新表情都没有对应的unicode编码,而换了unicode编码,TextView/EditText直接显示在一些机器中就会遇到上面的crash
2 考虑到安装包的大小,目前也没有把太多表情直接打包进去的打算(从目前版本的OSX中提取出来的表情大概有800多个,全部直接打包进去的话,会给安装包增加1~2M的体积)
BTW,Google在44之后也自行扩展了OpenType标准,同时也添加了一套自己的小黄人Emoji表情,可以直接在Google输入法中输入
请检查你这个activity的permission,有没有加上以下的设置。
在AndroidManifestxml里面添加。
<uses-permission android:name="androidpermissionBROADCAST_STICKY" />
<uses-permission android:name="androidpermissionCALL_PHONE" />
<uses-permission android:name="androidpermissionCALL_PRIVILEGED" />
<uses-permission android:name="androidpermissionINTERNET" />
<uses-permission android:name="androidpermissionPROCESS_OUTGOING_CALLS" />
另外帮你贴下android自带拨号程序的核心部分,请自己参照下吧~~
public class OutgoingCallBroadcaster extends Activity {
private static final String PERMISSION = androidManifestpermissionPROCESS_OUTGOING_CALLS;
private static final String TAG = "OutgoingCallBroadcaster";
private static final boolean LOGV = true;//ConfigLOGV;
public static final String EXTRA_ALREADY_CALLED = "androidphoneextraALREADY_CALLED";
public static final String EXTRA_ORIGINAL_URI = "androidphoneextraORIGINAL_URI";
private Phone mPhone;
@Override
protected void onCreate(Bundle icicle) {
superonCreate(icicle);
mPhone = PhoneAppgetInstance()phone;
Intent intent = getIntent();
if (LOGV) Logv(TAG, "onCreate: Got intent " + intent + "");
String action = intentgetAction();
String number = PhoneNumberUtilsgetNumberFromIntent(intent, this);
if (number != null) {
number = PhoneNumberUtilsstripSeparators(number);
}
final boolean emergencyNumber =
(number != null) && PhoneNumberUtilsisEmergencyNumber(number);
boolean callNow;
if (getClass()getName()equals(intentgetComponent()getClassName())) {
// If we were launched directly from the OutgoingCallBroadcaster,
// not one of its more privileged aliases, then make sure that
// only the non-privileged actions are allowed
if (!IntentACTION_CALLequals(intentgetAction())) {
Logw(TAG, "Attempt to deliver non-CALL action; forcing to CALL");
intentsetAction(IntentACTION_CALL);
}
}
/ Change CALL_PRIVILEGED into CALL or CALL_EMERGENCY as needed /
if (IntentACTION_CALL_PRIVILEGEDequals(action)) {
action = emergencyNumber
IntentACTION_CALL_EMERGENCY
: IntentACTION_CALL;
intentsetAction(action);
}
if (IntentACTION_CALLequals(action)) {
if (emergencyNumber) {
finish();
return;
}
callNow = false;
} else if (IntentACTION_CALL_EMERGENCYequals(action)) {
if (!emergencyNumber) {
finish();
return;
}
callNow = true;
} else {
finish();
return;
}
// Make sure the screen is turned on This is probably the right
// thing to do, and more importantly it works around an issue in the
// activity manager where we will not launch activities consistently
// when the screen is off (since it is trying to keep them paused
// and has issues)
//
// Also, this ensures the device stays awake while doing the following
// broadcast; technically we should be holding a wake lock here
// as well
PhoneAppgetInstance()wakeUpScreen();
/ If number is null, we're probably trying to call a non-existent voicemail number or
something else fishy Whatever the problem, there's no number, so there's no point
in allowing apps to modify the number /
if (number == null || TextUtilsisEmpty(number)) callNow = true;
if (callNow) {
intentsetClass(this, InCallScreenclass);
startActivity(intent);
}
Intent broadcastIntent = new Intent(IntentACTION_NEW_OUTGOING_CALL);
if (number != null) broadcastIntentputExtra(IntentEXTRA_PHONE_NUMBER, number);
broadcastIntentputExtra(EXTRA_ALREADY_CALLED, callNow);
broadcastIntentputExtra(EXTRA_ORIGINAL_URI, intentgetData()toString());
broadcastIntentputExtra(EXTRA_INTENT_FROM_BT_HANDSFREE,
intentgetBooleanExtra(OutgoingCallBroadcasterEXTRA_INTENT_FROM_BT_HANDSFREE, false));
if (LOGV) Logv(TAG, "Broadcasting intent " + broadcastIntent + "");
sendOrderedBroadcast(broadcastIntent, PERMISSION, null, null,
ActivityRESULT_OK, number, null);
finish();
}
}
以上就是关于十六进制转字节会有编码影响吗全部的内容,包括:十六进制转字节会有编码影响吗、Android利用ListView做一个电话簿app,求大佬帮助,尽量详细、Android 微信对 emoji 的支持是不是很差为何这样设计等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)