这些年,我爬过的 Android 坑 | 持续更新


总结目录

  • 视图篇

    • 怎么理解非主线程能够更新UI
    • dialogFragment 全屏时左右留空的处理计划
    • dialogFragment 全屏时状况栏呈现黑色布局的处理计划
    • 多个fragment 切换堆叠的处理计划
    • 多个fragment 保存状况时或许呈现 TranS L a % b W *sactionTooLargeException 的处理计划
    • recyclerview 调用 notifyItemRemoved 办法移除某个 Item 之后因为引证 position 引u k t ` _起 crash 的原因
    • recyclerview 局部改写Item时会因为默许5 ~ ` }动画导致闪耀的处理计划
    • recyclerview 中的 item 呈现莫名的偏移滚动
    • recyclerview 内容g I d超越一屏时,findFistComplet/ ^ [ ZelyVisibleItemPosition 会回来 -1 的原因
    • text4 a d rview 中富文本点击: W n 事情阻拦了长按事情w m 6 & a M 的处理计划
    • 怎么制止 ViewPage w I 0 , K { br 的滑动
    • 怎么仿蘑菇街/马蜂窝 Viewpager 装载图片之后切换时动态变更高度
    • 怎么操控 appbarLayout 随时定位到某个方q s # ~ O
    • 怎么制止 appbarLayout 滚动
    • edittext 未能呼应 onClickLisg j 3 e , 0 W n vtener 事情的处理计划
    • 运用 listview 或gridview 的处理 item 的 state_selected? ^ q | G D v 4 | 事情是无效的处理计划
    • 处理5.0以上Button自带阴影效果的计划
    • 针对 onSingleN j V + @TapUp 和 onSIngleTapConfirmx 8 K A 0 ced 的运用差异
    • 怎么运用layer-list画三角形
    • 关于特点动画中旋转 View 时部分机型呈现Q j # C w View 闪耀的处理计划
    • 关于 Const2 Y W M 0 x / 6 4raintLayout 的代码布局下的注意事项
    • TextView 在 6.0 版别下设置单行尾部缩略的坑
  • 服务篇

    • 后台手动整理运用之后,service中发动的notificati{ u x C H ? F tons并没有消失的处理计T ] G I * S ] I U
    • 大局的Context运用更为高雅的获取计划
  • 线程篇

    • 主张新起线程不要随意调用网络恳求,一般的newThread没有looper行列W h GS Y w } a 1参阅handlerThread
  • 网络篇

    • Retorfit get 恳求参数呈现过错的处理计划
  • 数据篇

    • 怎么高雅处理 sqlio M , S nte 多线程读写问题
    • 怎么理解 Intent 传递数据呈现 TransactionTooLargeException 的问题
  • 机型体系适配篇

    • 怎么处理 Natigati3 + ? * r z ~ 4onBar 被 PopupWindow 遮挡的问题
    • 怎么处理MIUI体系后台无法 toast 的问题
    • 怎么处理封闭告诉栏权限无法弹出 toast 的问题
    • 怎么适配 vivo 等双面屏幕
    • 怎么处理华为设备发生太多 broadcast 导致crash的问题
    • 各种告诉栏的适配计划
    • 处理针对魅族推送内容约束的问题
    • 处理从体系安装起安装运用后发动Q k 4 @ $ r l,Home 躲藏后 Launcher 重复发动的问题
    • 针对有9 H + S F { E J .launcher做为Activity的运用,在彻底没有发动下收V ! 4 u x 1 a W到第三方推送(小米,华为,魅族)/共享拉起的注意事项
    • 针对 App 多场景拉起场景下的场景判别剖析
    • 8.0 部分 ROM 呈现 Only fullscreen opaque activities can re2 f 7 Equest orientation 的处理计划
    • 9.0 android 支撑明文衔接(Http)
  • 编译构建篇

    • travis-ci 高版别androidE Y } ( fO编译遇到 license 没经过编译失利的处理计划
    • Dalvik 支I [ G )撑的 androi! ; & & 8 . & nd 版别下进行分包履行会有一些约束
    • Dalvik 分包构建每一个 dex 文件时或许呈现 java.lang.NoClassDefFoundError
    • Java 8 methods of java.lang.Long and java.lang.Character are not desugared by D8I u ? p ] S } {
    • dat3 ^ F – Q D qabinding 中 findBindU = h r _ing vs getBinding 的场景差异
    • 版别构建呈E ~ +现 Gradlej q Z F o syncz # T z T U P ` z failed: Cannot choose between the following configurations of project
    • gradle 装备本地离线包
    • 处理kvm/jvm 编译时 -classpath 遇到的分割及空格的问E 2 E
    • databinding NoSuchMethodError with buildTool 3.4.0
    • AS衔接真机调试呈现 debug info can be unavailaR $ e U 9 s Pbe 的处理办法
  • 版别操控5 u & s ^ 1

    • git 修正 commit 记录
    • 处理git ignore 文件不收效的问题
  • 其他

    • ExoPlayer在[ s P : C – + # G接听电话之后会导致本来设置的 Source 中静音状况消失了导致或许回来 apL P tp 续播的时分视频突然有声响
    • AndroidStudio] | Eh x $ } : ^ g q示 Please select Android SDK
    • 关于 Java 中字符与字节的编码联系知道
    • 关于 emoji 编码的长度计算问题

<<视图篇>>

  • 9 ~ ; _ = m ] 6 :么理解非主线程能R H 4 Z K够更新UI

    谷歌在 viewRootImpl4 s : 6 中查看更新ui的线程

    void checkThread() {
    if (mThread != Thread.currentThre] E : - a f u Lad(U _ ] E T Q 1 c I)) {
    throw new CalledFromWrongThreadEj U [ 3xception(
    "Only the original thread that created a view hierarchy canJ V C { A 4 J  touch its view- A s q r %s.a w Y d {");
    }
    }h ? ^
    

    在履行onCreate的时分这个判别并没有履行到

  • dialogFrag p J R r igment 全屏m k 4 G } 4 _ B时左右留空的处理计划

    在 fragment#onResume 中从头调整 win, ; q : U ! z 0 Zdow 布局

    android.view.WindowManager.LayoutParams lp = window.getAttributesj f ? c();
    lp.width = WindowManager.LayoutParams.MATCH_PARENT;
    lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
    window.setAttributes(lp);
    
  • dialogFragment8 j s 全屏时状况栏呈现黑色布局的处理计划

    在主题中设置

    <item name="andrk V G @ Q / h 9 coid:windowIsFloating">true</item>
    

    此时 wu ~ 4 %indow 为 wrap_content,假如呈现左右空白,则考虑运用上个问题的计划9 W R

  • 当运用退回后台一段时刻重返后,FragmeD | S U ) 5 B u Qnt 切换堆叠的处理计划

    在线上项目中咱们遇到一个场景:当运用按下 Home 退回后台,K Y * g ` t k j _然后过一段时刻之后从后台r % @ w 0拉起咱们的项目。极少数机型在主页进行多个 fragmentv ~ 5 y @ (切换时呈现了 fragment 的堆叠s p R q , + K。经过定位之后发现,这些机型的运存偏小,性能误差,呈现这种现象的原因是因为内存的压力的原因,体系并不知后台的* Y M W程序哪一个才需求保持运行,就会测验回收内存占用较大的页面,当咱们的页面被体系销毁时,fragmentActic g tvity#onSaveInstanceState 被履行并保存了一些瞬态信息,比方 T ? W X 1 n R界面 fraW ! * x Q J ~ .gment 的视图1 s – * H信息。当咱们再次拉起运用的时分,会让本来的 frq 7 W 5agmentActivity 重建并从头构建了一个新的 fragmz ` I } W 0 k s bent ,此时会叠加到现已被恢复的 fraX d 5 k i –gment 之上导致堆叠。

    比较暴力的做法是不让 activity 保存状况,比方

     @Override
    public void onSavi R L veInstanceState(Bundle outState) {
    //直接不调用 super.onSaveInstanceSta! F ? #te(outState);
    //或许直接传递U _  Y空数据
    super.onSaveInstanceState(new Bundle());
    }
    

    比较高雅的做法是,比方

     @Override
    pu^ 8 Oblic voids  3 E onSaveInstanceState(Bundle outS~ ~ 3 Y 2 L rtate) {
    getSupportFragme Z 3 m ~ entManager().putFragment(outStaG K Bte, you_key, CusFragment);
    super.onSaveInstanceState(outState);
    }
    //在onCreate的时分判别是否现已存在保存的信息
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.lL ) I sayout.activity_main)B t d | [;
    if (savedInstanceState != null) {
    CusFragment fragment =  (CusFragA 5 a : 9 5 Rment)getS+ ~ w f Z Y k | vupportFragmentManager().getFragment(savedInstanceH  J P . u a ( 3State, you_key+ O c /);
    } else {
    //init CusFragment
    }
    }
    
  • 多个fragment 保存状况时或许呈现 TransactionTR % 4 j % m i &ooLargeExcep| t ( x B Dtion 的处理计划

    呈现 TransactionTooLargeException 反常时,因为线上咱们运用了 FB _ DragmentStatePagU + T u ~ % ) 5 9erAdapter 作为 fragmentN X 4 I O y配器为了尽或许过缓存下阅读过的7 ? t fragment 以获得更好的体会,承载多个 FragmentStatePagerAdapter#saveState 会被调用并对每一个 fragmentbundle 数据进行保存。因为咱们的 bundle 较大,而且保存下来的 bundle 并不会因为m W d ^ c Y T – fragment 被销J K – e R } &毁而销毁,所以需求保存的 bundle 数据会一向增加,2 8 z N直到呈现Tran# ^ M 6 NsactionTooLargeException 反常. 咱们参阅1 r = 6stac) F 5koverflow相关问题 直接重载 saveState 丢掉 statesF l ` D c容。

    public Parcelable saveState() {
    Bundle bundle = (Bundle) super.saveState();
    bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
    return bundle;
    }
    

    另外推荐 toolargetool 工具能够在开发中实时观测页面内存变化。

  • recyclerview 调1 D $ m D + L用 notifyItemRemoved 办法a M A H } ( M ^ ;移除某个 Itea L o ) Gm 之后因为引证 position 引起 crash 的原因

    notifyItemRemoved办法并不会移除列表的数据源的数据项导致数据源中的数据与列表Item数目不一致,需求同步改写数据源。

  • recyclerview 局部改写Item时会因为默许动画R 6 n导致闪耀的处理计划

    因为recyclerview存在ItemAnimator,且在删去/更新/插入Item时会触发,可设置不支撑该动画即可。

    ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
    
  • recyclerview 中的 ite7 2 | h t w sm 呈现莫名的偏移滚动

    这个问题经过定位存在于 viF 0 3 7 0ewholder 中的某个 viewZ * $ _ 5 | 或许提早获取到焦点。 一起在。alibaba-vlayout 库中也发现有L j %人反应改问题。 issues-255 处理的办法是在 Recyclerview中外层父布局中增加 android:descen0 i + s idantFocusability="blocksDescendants" 用于X y 3 s a t父布局覆盖 Rec0 3 a G ` hyclerview 优先抢占焦点。

  • recyclerview 内容超越一屏时,findFistCompletelg T W D c 6 k w kyVisibleItemPosition 会回来 -1 的原因

    原因是在 findOneVisibleChild 计算出来的 start 和 end 现已超越了 recI y _lclerview 的 sU K G Btart 和 end.经过研– R u 2 { 5究源码得到以下。

    findFirstCompletelyVisibleItemPosition -> -1
    findLastComd l = } =pleR L P 8 1 f ltelyVisibleItemPosition -> -1
    findFirsy 8 k c 5tVisibleItemPosition -> 正常
    findLast
    
  • textview 中富文本点击事情阻拦了长按事情的处理/ , z e + 4 ~ c计划

    这个问题常见于音讯列表中,某条音讯运用了ClickableSpan用于处理富媒体的点击事情,一起这个音讯又V ? c E R t d k需求支撑长按复制。因为LinkMovementMethod办法在onTouchEvent一向回来true,能够经M Y # G w + O过自定义ViJ O $ {ew.onTouchListener来, $ h (替换setMovenmentMethod达到效果。

    public class Clicq z p C A l , a 4kMovB * c %ementMethod implemeH  9nts View.OnTouchListener {
    private LongClickCallback longY M 3 f t - ? X [ClickCallback;
    public static ClickMovementMethod newInstance() {
    returnV ) H ! C  p new ClickMovementMethod();
    }
    @Overridev M f V d 9 z p
    public boolean onTouch(final View v, MotionEvent even! % = O Et) {
    if (longClickCallback == null) {
    longClickCallback = new LongClickCallback(v);
    }
    TextView widget = (TextView) v;
    // Mov? @ `ementMethod设为空,防止消费长按事情
    widget.setMovementMethod(null);
    CharSequence text = widget.getText();
    Spannable span$ d D ! . - ; ! 0naQ u m -ble = Spannable.Factory.getInsZ } F { s . 6 stank F dce().newSpannable(text);
    in7 _ o X G ft action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN || action == Mot2 2 v B hionEvent.ACT& ` % b h wION_UP) {
    int x = (int) event.getX();
    int y = (int) event.getY();
    x -= widget.getTotalM 8 O ! r d ] 7PaddingLeft();
    y -= widget.getTotalPaddingTop();
    x += widget.getScrollX();
    y += widget.g@ = + ietScro: : 4 C l HllY();
    Layout layoW X K 5 ) xut = widget.getLayout();
    int line = layout.getLineForVertical(y);
    int off = layout.getOffsetForHorizontal(line, x);
    ClickableSpan[] link = spannable.getSpans(ofi - f N z J .f, off, ClickableSpan.class);
    if (link.length != 0) {
    if (action == MotionEvent.ACTION_DOWN) {
    v.postDelayed(longClickCallback, ViewConfiguration.getLongPressTimeout());
    } else {
    v.removeCallb) ^ 1 U N Q Q yacks(longClickCallback);
    link[0].onClick(widget);
    }
    return true;
    }
    } else if (action == MotionEvent.ACTION_CANCEL) {
    v.removeCallbacks(longClicn c e &kCallback);
    }
    return false;
    }
    private static class LongClickCallback implements Runnable {
    private Viewc & / } view;
    LongClickCallback(View view) {
    this.view = view;
    }
    @Override
    public void runW ` l  f * d I() {
    // 找到能够消费长按事情的View
    View v = view;
    boolean consumed = v.performLongClick();
    w` m &hi, 9 J U ~le (!consumed) {
    v = (View) v.getParentg 4 k N h /();
    if (v == null) {
    break;
    }
    consumed = v.performLongClick();
    }
    }
    }
    }
    text/ [ } F q B #View.setOnTouchListener(ClickMovemeV q { C , H D rntMethod.newInstance());
    
  • j % R么制止 ViewPager 的滑动

    重写ViewPager onTouchEven` Q ] V x . & ft 和 onInterceptTouchEvent[ F , W 并回来false,不处理任何滑动事情

    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
    return false;
    }s E ~ 3 J b D b
    @Override
    public boolea3 ] n Z 4n onInterceptTouchEvent(b I i t 5 @MotionEvent arg0) {
    return false;
    }
    
  • 怎么仿蘑菇街/马蜂窝 Viewpager 装载图片之后切换时动态变更高度

    imaS ] UgeViewPager 为普通的 Viel L = & V A p Qwpager 方针

    imageListInfo为存放图片信息的list,imageShowHeight为事务需求显现高度,经过切换时动态计算调整

            imageViewPageb # i Lr.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLay6 a m |outListener() {
    @Override
    public void onGloba) E J .lLayout() {} ) H f + s r M Y
    imageViewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    //根据viewpager的高度,拉伸显现图片的宽度调整高度。
    ViewGroup.LayoutPa7 8 i z g 9 - =rams layoutParams = imageViewPa/ g : |gerc ~ I n , + ~ d.getLayoutParams();
    layoutParams.height = imageListInfo.imageShowHeight[0];
    imageViewPager.setLayoutParams(layoutPara/ ` ? Q i + ^ms);
    }
    });
    imageViewPager.setAdapter(imagePagerAdapter);
    imageViewPagZ n q S Xer.addOnPageChange- a h ` .Listener(ne5 n ;w ViewPager.OnPageChangeListener() {
    @OverriA w I de
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    if (position == imageListInfo.getImageListSize() - 1) {
    retS ( * ?urn;
    }
    int height = (int) (imageListInfo.imageShowHeight[position] * (1 - positionOffset) + imageListInfo.imageShowHeight[position + 1] * positionOffset8 ) p + r S);
    ViewGroup.Lo [ m I S 8 X FayoutParams params = imageViewPager.getLayoutParams();
    params.height = height;
    imageViewPager.setLayoutParams(params);
    }
    @Over3 p H U I zride
    public void onPageSelected(int position) {
    if (!clickListBySelf) {
    toSelectIndex(imageListInfo.selected, position);
    }
    }
    @& E E e 0 C M ` yOverride
    public vo* I N A J ` DidS [ r J 5 onPageScrA W | }  @ !ollStateChanged(int state) {
    }
    });
    
  • 怎么操控 appbarLayout 随时定位到某个方位

    CoordinatorLayout.Behavior behavior =((Coordi4 h TnatorLayout.LayoutParams)mAppBarLa9 : ) q ( q h f 1yout.getLayoutPaO p +rams()).getBehv T h ] D W Davior();
    if (behavior instanceof AppBarLayout.Behavior) {
    AppBarLayout.Beh/ r l W 4 I d s (avior appBarLayoutBehavior = (AppBarLayout.Behavior) behavior;
    int topAndBottom) # g r 7 6 V L 3Offset = appBarLayoutBehavior.getTopAL 7 g h G X H } PndBottomOffset();
    if (topAndBottomOffset != 0) {
    appBI W k m n JarLayoutBehavior.setTO + 3 z uopAndBottomOffset(0);
    }
    
  • 怎么制止 appbarLayoud 2 ] 2 B s l – :t 滚w | / N

    CoordinatorLayout.LayoutP. a , V !arams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
    A+ M 2ppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
    behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
    @Override
    public boolean cT l _  aanDrag(@NonNY j ;ull Apo - q , 7 BpBarLayout appBarLayout) {
    retP E h j = yurn false;
    }
    });
    
  • edittext 未能呼应 onClickLi: A Y M ? 6 _stener 事情的处理计划

    Edittext监听未获取焦点的Edittext的点击事情,第一次点击触发OnFoc3 & f U ~ } l . Vus] k + g d ChangeLi^ ] J 8 _ e Lstener,在获取焦点的情况下才干呼应onClickListener

  • 运用 listview 或gridview 的处理 item 的 state_selected 事情是无效的处理计划

    在xml布局中对listview6 D % +或gridview设置Android:choiceMode=”singleChoice”,并运用state_activated状况来替代state_selected状况。(2016.+ d R 6 e O A v12.10)

  • 处理5.0以上Butto% ` W R / Qn自带阴影效果的计划

    在x| U z ` 4 d nml定义的Button中,增加以下样式定义

    style="?android:attr/borderlessButtonStyle"
    
  • 针对 onSingleTapUp 和 onSIngleTapConfirm l n F ( a C z }ed 的运用差异

    前者在按下并抬d t `起时发作,后者有一个附加条件时Android会d 4 W保证点击之后在D , O短时刻内没有再次点击才会触发。常用于假如需求监听单击和双击事情。

  • 怎么运用layer-V / P 1 R R @ alist画三角形

    <layer-list xmlns:android="http://schemas.android.com/~ ` ) } Tapk/res/android" >
    //左
    <item>
    <rotate
    android:fromDegrees="4n _ L G c 8  {5"
    android:pivotX="85%_ = 5"
    android:pivotY="135%">
    <shape android:shape="rectangle">
    <size
    android:width="16dp"
    andrs 4 % 1 _ 8 Toid:height="16dp" />
    <so! n ] ] ! 9 z )lid android:color="#7d72ff"D E , i 0 Q v g K />
    </shape>
    </rotate>
    </item>
    //右
    &lF @ * D N Q [  3t;item>
    <rotate
    android:fromDegrees="45"
    android:pivo^ ^ ,tX="15%"
    android:pivotY="-35%">
    <shape android:shape="rectangle">
    <size
    android:width="16dp"
    android:height="16dp" />
    <solid android:color="#7L c , ` 2 1 `d72ff" />
    </shk ` p x V r a Uape>
    </rotate>
    </item>
    //上/正
    <item>
    <# r I;rotate
    android:fromDegrees="45"
    android:pivotX="-40% ^ )  ?"
    andt A L * t | d croid:pivotY="80%">
    <shaZ Y I L xpe android:shape="rectangle">
    <size
    android:width="16dp"6 j h { Q I w F B
    android:height="16dp"/>
    <solid android:color="#7d72ff"/>
    </shape>
    </rotate>
    <x o D x !/item>
    //下
    <itC p hem>
    <rotate
    android:fromDegrees="45( [ /  H"
    android:pib 9 o m % u u 1 =votX_ O D Y j="135%"
    android:pivotY="15%">
    <shape[ P ; $ = android:shape="rectangle"5 n P W z @>
    <size
    android:width="16dp"
    android:height="16dp"/>
    <solid android:color="#7d72ff"/>
    </shape>
    </rotate>
    </item>
    

“`

  • 关于特点动画中旋转2 g % . { Y N View 时部分机型呈现 View 闪耀的处理计划

    在大神 app 信K = k 7 Q 5 r息流方便评论模块中,在交给方便评论动画的时分发现,运用特y t c r Y l u点动画完成的颤动效N n Z R果在部分机型上呈现闪耀。而咱们的完成颤动效果是经过 View.ROTATIONh i V 来完成的。经过研究,部分机型因为硬件加速的原因导致的。为动画Y = C view 进行以下设置

    view.setLayerType(View.LAYER_TYPE_HARDWARE,null);
    
  • 关于 ConstraintLayout 的代码布局下的注意事~ 3 Z 3 3

    不同于其他 ViewGroup 操控子 Vi Q 4 A : . % kew 的排版,ConstraintLayout 需求构建 ConstraintSet 方针来粘合。 在手动增加子 View 的场景下,能够经过 ConstraintSet#clone(C/ L y t J [onstraintLayout constraintLayout) 来克隆当时已有 ConstraintLayout 的排版信息,然后终究调用 ConstraintSet#applyTo(ConstraintLayout constraintLayout) 承认D s 1 D I @ B终究的排版信息。

  • Tei ] v } U e D D 5xtView 在 6.0 版z j 8 Y 9别下设置单行尾部缩略的坑

    在大神信息流中,有一些卡片信息需求设置单行缩略。在 MTL 兼容测验过程中发现有一些机型显现反常,经过归纳及校验,这部分机型的版别都是 < 6.0。 经过在 stackoverflow 也找到了相同的问题场景 text ellipsize behaviX ; Q k ! Yor in android veL B 6 k 1 *rsion < 6.0 . 针对这部分版别的手机,咱们需求在设置单行的时分把 android:maxLines="1" 改成 android:singleLine="true"。即便j / w IDE 提示该 API 现已过期了!

<<服务篇>>

  • 后台手动整理运用之后,service中发动的notifications并没有消失% { b m的处理计划

    从 How to remove all notifications when an android app (aU 2 h m C 0 ; 0 Zctiviv u ] I f S X mty or service) is killed? 的诸多评论中学习到, Service#onT. g l { C } q IaskRemoved 是咱们的App被整理之后Service的回调。测验过一下办法并不能达到清除的效果。

    @Override
    pubR 0 |lic void onTaskRemoved(Intent rootIntent) {
    super.onTaskRemoveu e L b O $ [d(rootIntent);
    NotificationManager nManager = ((NotificationManager1 p = ` [ L z G z) getSystemService(Context.NOTIFICATION_SERVICE));
    nManager.cancelAll();
    }
    

    在线上运用中,因为咱们的告诉类似于将军令这种有守时更新的功用,需求彻底干掉一切seri, B + 9 ` wvce承载的功用,下面办法可行& : ` P H h p ) f

     @Over* @ X ^ S e 5 1ride
    public void onTaskRemoved(Int^ J F rent rootIntent) {
    super.onTaskRemoved(rootIntent);
    sb H X atopSelf();
    stopForeground(true);
    }
    
  • 大局的Context运用O ` I A s Z ) d 1更为高雅的获取计划v K H $ ` ` q

    因为咱们在优化 Application 发动时p ! 1 ? } c U | 8刻时,计划移O i _applciation 一切有关静态声明的变量,其中就包括大局 context 这个变量} % j 6 t / | #。咱们参阅的是 leakCaD 7 R 6naD + v N d %ry 库的做法,运用 ContentProvider 来承e ; ~ O载大局 context 的获取,原因是在 ActivityThread 的初始化流程中,ContentP5 x $ E Xrovider#onCreate() 是在 Application#attachBaseContext(Context. + ? 4)Application#onCreate() 之间的。所以获取的 context 是有效的

    class ContextProvider : ContentProvidQ h A h x i =er() {
    companion oe , t P J m _ qbject {
    private lateinit var mContext: Context
    private la= } Dteinit var mApplication: Application
    fun getGlobalContext(): Co? ? G E n & . kntext = mContext
    fun getGlobalApplication([ ] c e | I G q a): Application = mApplication
    }
    override fun onC& q 4 Y D Preate(): Boolean {
    mContext = context!!
    mContextS # A = context!!.applicationContext as E j D $ : d Application
    return false
    }
    override funB % J  3 ? Q u insert(uH = [ p D Z ? lri: Uri, values: ContentValues?): Uri? = null
    override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrdeA ` J N J F Vr: String?): Cursor? = null
    override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Arra- ? R : D yy<out String>E _ 7 l 5 s ; v?): Int = -1
    override fuG { KnM b { delete(uri: Uri, selu [ R . O Rection: SL = I [ d b X Ttring?, selectH F MionArgs: Array<out String>?): Int = -1
    override fun getType(uri: Uri): String? = null
    }
    //manifest声明
    <!-- Co/ 0 s 6ntext供给者 -->
    <provider
    android:name=".ContextProvider"
    android:authorities=7 w 3 G K a U 8"${your_applic$ = c k sation_id}.contextprovider"
    android:eV G w ( j uxported="false" />
    

<<1 { !线程篇>>

  • 主张q J . 2 ! C新起线程不要随意调用网络恳求,一般的newThread没有l6 s v a Y 5ooper行列,参阅handlerThread

<<网络篇>>$ 0 r = a B ] e

  • Retorfit get 恳求参数呈现过错的处理x 4 % L W }计划

    @GET( BASE_URL + "index/login" )
    Observable< LoginResult > requestLogin( @QueryMap(encoded = true) Maq O Vp< String, StriR x Wng > params );
    final Map< Strint E }g, String > paramsMap = new ParamsProvider.Builder().
     append( "username", accoun@ u U qt ).
     append( "password",C 0 { e l 5  - JURLEncoded(password) ).
    

    比方登陆,encode = true 表明未对特别字符进行url编码,默许是false。

<<数据篇>>

  • 怎么高雅处理 sqlite 多线程读写问题! # 7 c D [ t /

    • 一个helper实例对应一个 db connectton,这个衔接能供给读衔接和写衔接,假如只是调用 read-only,则默许也会有写衔接。
    • 一个helper实例能够在多个线程中运用,4 + ! O q –java层会运用锁机制D X 9 : : i保证线程同步,i n 8哪怕有100个线程,对数据度的调用也会被序列化
    • 假如测验从不同 connection 一起对数据库进行写操作,则有一个会失利。并不会按照第一个写完再轮到第二个写,有一些sqlite版别甚至不会有过错c 4 # V d S提示。

    一般而言,假如要在多线程环境下运用数据库,则保证多个线v ? p % l 4 _ – I程中运用的是同一e Z 8 w个SQLP W 2 S .iteDataBase方针,该方针对应一个db文件。

    特别情况,假如多个 SQLiteDataBase 翻开同一个 db 文件,一起运用不同线程一起写(insert,update,exexSQL)会导致在 SQLiteStatement.native_exM ] S h # T tecute 办法时或许导致反常。这个反常来自本地办法里边,仅仅在Java对有对 SQLiteDataBase 进行同步锁保护。可是多线程读(query)回来的事1 V m # q SQLiteCursor保存查询条件并没有马上履行查询,仅仅在需求时加载部分数据,能够多线程不同 SQLiteDataBase 进行读。

    假如要处理上述问题,能够运用 “一个C 6 {线程写,多个线程一起读,每个线程都用各自SQLiteOpenHel1 o K N tper。”

    在android 3.0版别以上 翻开 enableWriteAheadLogging。当翻开时,它允许一个写线程与多个读线程一起在一个SQLiteDatabase上起效果。完成原理是写操作其实是在一个单独的文件,不是原数据库文件。所以写在履行时,不会影响读操作,读操作读的是原数据文件,是写操作开始之前的内容。在写8 # F 4 G Q O操作履行成功后,会把修正合并会原数据库文件。# V 3 V W b 4此时读操作才干读h D J B G g到修正后的内容。可是这样将花费更多的内存。

  • 怎么理解 Intef g ) Z 2 Snt 传递数据呈现 `TraR v N $ ynsactionTooLargeException`的问题

    Intent 传输数据的e [ M H [机制中,用到了 Binder。Intent 中的数据,会作为 Parcel 被存储在 Binder 的事务缓冲区(Binder transaction buffer)中的方针进行传输.而这个 Binder 事务缓冲区具有一个有限的固定巨细,当时为 1MB。你可别认为传递P 0 3 0 3 1MB 以下的数据就安全了,这里的 1MB 空间并不是当时操作独享的,而是由当时进程所共享。也就是说 Intent 在 Activity 间传输数据,本身也不适合传递太大的数据.

    参阅% V – 8 m E Y c阿里 《Android 开发者手册》 对于Activity间数据通讯数据较大,防止运用Intent+P| 4 Z T { }arcelab{ M V $ #le的方式,能够考虑运用EventBus等替代计划,防止 Transag F 4 U S ]ctionTooLargeExceptiont { ^ 3EventBus运用黏性事情来处理,可是针对Activity重建又能拿到Intent而EventBus则不能够,所以需求根据事务来调整。

<<机型体系适配篇>>

  • 怎么处理 NatigationBar 被 PopupWindow 遮挡的问题

    popupWindow.setSoftInputModeY 3 ,(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    
  • 怎么f U ! e _ 8 {处理MIUI体系后台无法 toae y fst 的问题

    参阅 github.com/zhitaocai/T… 项目,可是在小3 g K 5 n y米3或许小米Note(4.4.4)手机上

    mWindowManag( r P [ ] 6 5 ker =t # ) 2 (WindowM2 } K K ] s y o Zanager) mContexV C q H m a it.getSystemService(Context.WINDOW_SERVICE);
    

    mContexA 6 Ot 需求运用 ApplicationContext 才干收效$ ) l 1 A

  • 怎么处理封闭告诉栏权限无法弹出 toast 的问题

    因为谷歌把J f I 4 Toast 设置为体系音讯权限,能够参阅 Anf w @ j S Ddroid封闭告诉音讯权限无法弹出Toast的处理计划 保护自己的音讯行列.

  • 怎么适配S B h | l & a L vivo 等双面屏幕

    在 AndroidManifest.xml 中声明一下 meta-data

    <meta-data
    android:name="andriod.max_aspect" android:value="ratio_float"/>
    

    或许运用 android:maxAspectRatio="ratio_floaB t = & O t 1 6t"(API LEVEL 26)
    ratio_float 一般为屏幕分辨率高宽比。
    其他比方凹槽区域,圆v g i角切开等问题能够参阅市面上最新的vK V – Y b h f Uivo机型对应的 vivo敞开途径 文档。

  • 怎么处理华为设备发生太多 broadcast 导致crash的问题

    因为部分华为中,假如app注册超越500个BroadcastReceiver就会抛出 “ Register too many Broado w H ? Y : y Ucast Receivers ” 反常。经过剖析发现其内部有一个白名单,自己能够经过创立a ! H # A @ =一个新的app,运用微信包* ^ k名进行测验,发现并没& X w T 0 N E有这个约l ` v N Y 5 h束。经过反射 LoadedApk 类拿到 mReceiverResource 中的 mWhiteList 方针增加咱们的包名就能够了。 能够参阅 github.com/llew2011/Hu… 这个项目。

  • 各种告诉栏的适配计划

    参阅 网易考拉完成的适配办法

  • 处理针对魅n j Q j –@ 6 Z N S Q 推送内容约束的问题

    今日收到魅族途径的警报称“推送内容e G : w或许过长”。IM功用针对离线设备走设备商的推送,魅族推送约束了title标题1-32字符,content内容1-100字符。假如频频推送超越约束的告诉,魅族推送服务器或许不会下发推送到魅族设备。故服务端约束发送到魅族服务器的音讯标题和内容长度处理。

  • 处理从体系安装起安装运用后发动,Home 躲藏后 Launcher 重复发动的问题

    判别发动页面是否是根节点(推荐)

    if(!isTaskRoot()){
    finish();
    rl - leturn
    }
    

    或许判别Activ2 h O f ity是否多了 FLAG_ACTIVITY_BROUGHT_TO_FRONT ,这个tag是该场景导致的

    if ((getIntent().getFlags() & Intent.FLAG_# d I B J y 1ACTIVITY_BROUGHT_TO_FROP @ {NT) != 0) {
    finish();
    return;
    }
    
  • 针对有launcher做为Activity的运~ 3 F ^ $ 6 g 8 W用,在彻底没0 ( 9有发动下收到– z 4 `第三方推送(小米,华为,魅族)/共享拉起的注意事项

    因为咱们的运用LauncherActip L Pvity用于分发不同场景的入口,A逻辑进入特别场景页面A,B逻辑进入主页面B。

    • onCreate . # . 8 X ( r中优先阻拦 intent 判别拉起参数,假如有拉起参数则直接进入主页面B,intent交给给主页面B处理
    • 部分场景d n } R v下,比方第三方音讯推送,华为和小米拉起闪屏或 launcher intent无法区别,针对该做法是,约束进入闪屏/launcher的逻辑,剩下场景一致进入主页面B
    if (后端操控是否需求进入特别场景页面) {
    boolean goToA = false;
    if (getIntent() != null)e 5  * g O  {
    String action = getIntent().getAction();
    Set<String> category = getIntent().getCategories();
    if (TextUtQ 1 ( 3 s : cils.eq+ B A b Vuals(action, "and[ y ` z 7roid.intent.action.MAIN")) {
    if (category != null && category.contains("android.intent.c` R kategory.LAUNCHER"))6 M ` {
    Intent intent = new Intent(this, 页面A.class);
    intent.setData(getIntent().getData());
    startActivity(intent);
    goToA = true;
    }
    }
    }
    if (! goToA) {* j 7 n
    goToMainActW g * U [ Nivity();
    }
    } else {
    goToMainActivity();
    }
    
  • 针对 App 多场景拉起场景下的场景判别剖析

    可参阅我另一篇文章 对线; H 1 3 t 7 ^ *7 O l i ! L 8项目拉起运用场景的考虑总结

  • 8.0 部分 ROM 呈现 Only fulR l t B r ilscreen opaque activities can request orientation 的处理计划

    因为咱们项目需求处理沉溺式,所以针对 android:windowIsTranslucent 的特点默许翻开的。G @ P 2 , 5 T y b可是线上发现部分 8d m Z &.0设备呈现诡异的 crash,原因是咱们对于页面的 orientation 声明都一致为 portN t nrait 。查阅 android 源码的更新发现在 8.0 源码的逻辑里边这两个逻辑竟然不兼容,随后在 8.0 版别后谷歌进行了修正。可是国内部分 RF b ,OM 看起来并没有修正这个问题。后面同事供给了一个比较取巧的计划,经过为页面指定 android:screenOrientation=”behind” 来防止 8.0 版别的问题一起兼容一切 android 版别。

  • 9.0 android 支撑明文衔接(Http)

    Android 9(API级别28)开始,默许情况下禁用明文支撑

    <?xml version="1.0" encoding="utf-8"?>
    <manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    &l{ 2 k t;application
    ...
    android:usesCleartextTraffic="true"
    ...>
    ...
    </applicad T ) E W D 9 *tion>
    </manifest>
    

<<编译构建篇>>

  • travis-ci 高版别androidO编译遇到O 1 g o $ license 没经过编译失利的处理计划

    参阅 CI 评论区 增加 dist: precisebefore% _ d_install 项中新增 sdkmanager指令。具体可参阅我的 开源项目装备

  • Dalvik 支撑的 android 版别下进行分包履行会有一些约束

    • 冷发动时需求安装dex文件,假如dex文件太大则或许导& E | _致处理时刻太长导致 ANR
    • 即便运用 multiDex 计划在低于 4.0 体系上或许会} 4 @呈现 Dalvik linearAlloc 的bug,这是因为该计划T l h r t需求请求一个很大的内存,运行时或许的导致程序溃散。这个约束在 4.0 上虽然有所改善了,可是还是或许在低于 5.0 的机器上触w L o ` D发。
  • Dalvik 分包构建每一个 dex 文件时或许呈现 java.lang.NoClassDefFoundError

    这个问题的原因是构建工具制作行比较复_ u n 0 K 7 &杂决议计划来确定主 dex 文件中需求的类以便运用能够正常的发动。假如c ] H . D & Z ~发动期间需求的任E * O ] K 3何类在主 dex 中未能找? , x b {到,则会抛出上述反常。一切必须要 multiDexKeepFile 或 multiDexKeepProguard 特点中声明他们,手动将这些类指定为主 dex 文件中的必需项。

    创立 multidex-new.txt文件,写入以下新增的类

    com/example/Main2.class
    com/example/Main3.class
    

    创立 men : o S #ltz 5 } M C 6idex-new.pro,写入以下 keep 住的类

    -keepp T m class com.example.Main2
    -keep class comL T o _ j [ 6 ).example.Main3
    

    然后在gradle multiDexKeepFile特点C T a ] 8 H 0 F 和 multiDexKeepProguard特点声明上述文件

    android {
    buildTypes {
    release {
    multiDexKeepFile file 'multg I ; ~ : X Tidex-new.txt'
    multi4 } [ G p 3 $ :DexKeepProguard 'multidex-new.pro'
    ...
    }
    }
    }
    
  • Java 8 met; xhods of java.lang.Long and java.lang.Character are not desugared by D8

    这个问题呈现在运用 Kotlin 编译时,从 Koty . h G 4 $ Z G ulin17 O J 9 e Q 2 Q #.3.30 版别开始 ndroid.compileOptf ) Q v z xioF i ] k * i $ 2 Zns中的Java版别推断出JVM方针,假如一起@ : % * 0设置了sourceCompatibilityu 0 | l v a 3和target$ [ i | # 4Compatibility,则挑选“1.8”到那个或更高. 能够经过指定 JavaVersion 1.6 来处理这个问题。

    sourceCompatibility JavaVersion.VERSION_1_6
    targetCompatibility JavaVersion.VERSION_1_6
    

    Issue 中表明,AGP(AndroX o Pid Gradle Plugin)3.4 已处理脱糖问题,可测验晋级处理。

  • databinding 中 findBinding vs getBinding 的场景差异

    不同之处在于,findBinding将遍历父节点,而假如运用getBinding时当view不是跟节点会回来null。

  • 版别构建呈现 Gr0 t S ` iadle synp L ^ ic failed: Cannot choose between the following configR * Y r – w lurations of project

    参阅 issues 的答复

    If you’re using Android plugin for Gradle 3.0.0 or high, . – jer, thY w J j . j E C Pe plugin automatically matches each variant of your app with corresponding variants of its local library module dependencies for you. That is, you should no longer target specific variants of local module dependenc^ l ( $ies, show as below

     dependZ k g r E f 3 *encies {
    // Adds the 'debug' varaint of* * 3 the library to the debug varaint of the app
    debugCompile project(path: ':my-library-modulY U e', configuration: 'debug')
    // Adds the 'release' varaint of the library to the ro z 7 P l Yelease varaint of the app
    releaseCompile project(path: ':my-library-module', configuration: 'release')
    }
    
  • gradle 装备本地离线包

    1. 离线下载 gradle 离线包保存在 url 中
    2. 修正 gradle/wrapper/grad? Z W 3 + (le-wrapper.properties 调整 dU T 5 8 ~ ? T 8istributionUrl 目录指向 url
    3. 修正 build.gradle classpath 版别映射 gradle 版别
  • k u Q W理kvm/jvm 编 Z S f译时 -classpat~ k Qh 遇到的分割及空格的问题

    linux/mac OS 上 . K U Z运用 “:” 分割多个classpath路径,window运用 “;” 分割。

    假如linux/mac OS 路径存在E $ | – O s空格,暂时防止,运用多种方式_ e 0 ; ! 1测验未果=。=。

  • databinding NoSuchMethodError with buildToolx F – / u % 3.4.0

    项目从 gradle 3.1 晋级到 3.4.0 并运用了 androidx 之3 T ,后,发现编译失利了v o r X m D P t #。来项目就是运用 databinding,编译呈现了

    java.lang.NoSu* = 4chMethodError: No direct method <init>
    (Landroidx/databinding/DataBindingComponent;Landroid/view/View;I)V in
    class Landroidx/databin} f C _ 0 xding/ViewDataBinding; or its super classes
    (declaration of 'androidx.databinding.View= Z {DataBinding'
    

    原因咱们运用的 aar 库中运用了旧版别 gradle 编译,新版别主端 gr% ; x T 3 8 gadle 晋级了,导致旧的 ViewDataBinding 构造器签名匹配不上新版 androidx.databinding.ViewDataBinding 的签名。

    //旧版别c _ ; u 9 c ^
    p* 6 C ] } J drotected ViewDataBinding(DataBindingC, o Homponent bindingComponent, View root, int localFieldCount)
    //新版别
    protected ViewDataBinding(Object bindingComponent, View root, int localFieldCount)
    

    幸运的是,3.4.1现已修正了。更改 3.4.0 -> 3.4.1 就能够了。

  • AS衔接真机调试呈现 debug info can be unavailabe 的处理办法

    在运用 AS 衔接华为真机调试的时分,IDE 一向呈现 “Warning: debug info can be unavailable. Please close other application using ADB: Restart ADB/ O _ H [ d X integration and try again” 的过错提示5 } R 5 * [ b ( a。 重启 ADB 很多遍L B # u s i – 9 ~和封闭除 IDE 意外或许衔接 ADB 的软件都无效,终究重启真机处理。原因是ADB衔接的问题,因为有时ADB会在真实/虚拟设备上缓存一个无效的D ` 3 R V s I @衔接,而且因为该衔接繁忙导致也无法衔接到该设备。

<<版别操控篇>>

  • git 修正 commit 记录

    git reset --Q D L v J % tsoft HEAD^
    撤销当时的commit,假如b 2 U | X } J m只是修正提n B ~ b r , ! 3 9示,则运用
    git commit -B W V d M  ~-amend
    
  • 处理git ignore 文件不收效的问题

    git rm -r --cached .
    git add .
    git commit -m 'update .O  h 9 ` k e ! sgitignore'
    

<&l} D M it;其他>>

  • ExoPlayer# m L Z – w B q d在接听电话之后会导致本来设置的 Source 中静音状况消z w f U . n 4 e失了导致或许回来 app 续播的时分视频突然有声响

    原因是W ? $ 7 6 4多媒体焦点被通话争夺之后播放音量被充值,处理办法可参阅 github.com/google/Exo W , u { R M F 8P…

  • AndR 9 – e WroidStudio 提示 PP u Y Flease select Android SDK

    处理手段: FiP ~ b _ ,le->Projectp I S Structure中修正Build tools version

  • 关于 Java 中字符与字节的编码联系知道

        // 1
    Log.d("编码测验-字符","a".lengthN @ : r z D v } #.to7 - O 2  z y P ;Strin? ( q 0 s [ F ug())
    // 1
    Log.d("编码测验-字符","测".leT U G 3 ) a U kngth.toStrO s v a ]inX % Y e M 7g())
    // 5
    Log.d("编码测验-字符",d : O r p R ? y"测验abc".length.toString())
    // 1
    Log.d("编码测验-UTF_8","a".H o k E p 9 !toByteArray(Charsets.UTF_8).si5 8 e  ,ze.toString())
    // 3
    Log.d("编码测验-UTF_8","测k ^ o".toByteArray(Charsets.UTF_8).size.toString())
    // 9 ,UTF_8 支撑运用 1,2,3,4个字节进行编码,一个中文占3个字节,一个英文占1个字节
    Log.d("编码测验-UTF_8","测验~ + 9 O L p ] -abc".toByteArray(Chars, h 8 9ets.UTF_8).size.toString())
    // 1
    Log E +.d("编码测9 3 ( } h W & G验-US_ASCII","a".toByteArray(Charsets.US_ASCII).size.toString())
    // 1
    Log.d("编码测验-US_ASCII","测".toByteArray(Charsets.US_ASCII).s* w qize.toString())
    // 5,一个中文占1个J . e = i 8 % (字节,一个英文占1个字节
    Log.d("编码测验-US_ASCII","测验abc".toByteArray(Charsets.US_ASCII).size.toString())
    // 1
    Log.d("编码测验-ISO_8859_1","a".toByteArray(Charsets.ISO_8859_1).size.toString()] p v b !)
    // 1
    Log.d("编码测验-ISO_8859_1","测".toByteArray(Charsets.ISO_8859_1).size.toString_ A j ] ; { ^ v())
    // 5,一个中文占1个字节,一个英文占1个字节
    Log.d("编码测验-, j ~ISO_8859_1","测验abc".toByteArray(CharL ` e } c i b Qsets.ISO_8859_1).size.toSc 4 = 6 J - K + ~tring())
    // 4,存在代理对 +2个字节
    Log.d("编码测验-UTF_16","a".toByteArray(Charsets.UTF_16).size.toString())
    // 4,存在N l C e m k  G r代理对 +2个字节
    Log.d("编码测验-UTF_16","测".toByteArray(ChE - 3arsets.UTF_16).size.toString()b 0 J ) r 9)
    // 12,UTF_16只支撑2或许4个字节编码,一个中文占2个字节,一个英文占2个字节
    Log.d("编码测验-UTF_16","测验abc- D J @ o & |".toByteArray(Charsets.UTF_16).size.toSh f ^ Jtring())
    /h ^ 2 $ t 6/ 2
    Log.d("编码测验-UTF_16BE","a+ 1 o H I M".toByteArray(Charsets.UTF_16BE).size.toString())
    // 2
    Log.d("编码测验-UTF_16BE","测".toByteArray(Charsets.UTF_16BE).size.toString())
    // 10,一个中文占2个字节,一个英文占2个字节
    Log.d("编码测验-UT] + g 7 e ` X 4F_16BE","测验abc".toByteArrayq  q r P X(Charsets.UTF_16BE).size.toString())
    // 2
    Log.d("编码测验-UTF_16LE"y | ^ _ & d s /,"a".toByteArray(Charsets.UTF_16LE).size.toString())
    // 2
    Log.d("编码测验-UTF_16LE","测".tL N ) P f F t 0o2 p ; vByteArray(Charsets.UTF_16LE).size.toString())
    // 10,一个中文占2个字节,一个英文占2个字节
    Log6 s O  7 L !.d("编码测验-UTF_16LE","测验abc".toByteArray(Chars{ ; U F % B {ets.UTF_16LE).size.toSty K g a r z { Jring())
    // 8
    Log.d("编码测验-UTF_32","a". ~ L 1 # 1toByteArray(Charsets.UTF_32).size.toString())
    // 8
    Log.d("编码测验-UTF_32","测".toByteArray(Charsets.UTF_32t b 0 K 8).size.toString())
    // 24 utf-32支撑 4个字节编码Q - B t ` ~ l S A,同 utf-16 原理,一个中文占4个字节,一个英文占4个字节
    Log.d("编码测验-UTF_32","测验abc".toByteArray(Charse) d m B U lts.UTF_32).size: - ~ O @.toStr Q ~ k ^ing())
    // 4
    Log.d("编码测验-UO | c / . *TF_32LE","a".toByteArray(Charsets.UTF_32LE).size.toStri7 T } * h ^ ( Tng())
    // 4
    Log.d("编码测R 4 +验-UTF_32LE","测".toByteArray(Charsets.UTF_32LE).size.toString())
    //20,一个中文占4个字节,一个英文占4个字节
    Log.d("编码测验-UTF_32LE","测验aB ] N ) m s [ w 6bc".toByteArray(Charsets.UTF_32LE).size.toString())
    // 4
    Log.d("编码测验-UTF_32BE",9 : ; e | x "a".toByteArray(Charsets.UTF_32BE).size.toG ! f | ?String())
    // 4
    Log.d(v 3 H u = ] h"编码测验-UTF_32BE, | w","测".toByteArray(Charsets.UTF_32BE)! w j u 3 u.size.toString())
    // 20,一个中文占4个字节,一个B q n + b英文占4个字节
    Log.d(- ^ { ` E T 6 v Q"编码测验-UTF_32BE","测验af 4 g Rbc".toByteArray(Charsets.UTF_32BE).siz{ | m ^e.Z { / :toString* l Q B g i j())
    
  • 关于 emoji 编码的长度计算问题

    要点熟悉下 Unicode 编码标识] E e C q } A e a的 emoji 下针对多平面 emoji 的拆分逻辑。可参阅这篇文章

关于更细节的Z C 8 A s / =面试阅历,可参阅
这些年,我所阅历的q + m q面试|写给疫情下的应届生及求职者 一文。

发表评论

提供最优质的资源集合

立即查看 了解详情