资讯专栏INFORMATION COLUMN

03.Android之View原理问题

FrozenMap / 3045人阅读

摘要:这种自定义控件在原生控件提供的方法外,可以自己添加一些方法。从顶层父到子递归调用方法,方法又回调。

目录介绍

3.0.0.1 View的绘制需要经过哪些过程?有哪些常用回调方法?View的绘制流程的详细流程是怎样的?

3.0.0.2 View绘制流程,当一个TextView的实例调用setText()方法后执行了什么?请说一下原理……

3.0.0.3 requestLayout()、invalidate()与postInvalidate()有什么区别?

3.0.0.4 DecorView的作用是什么?DecorView中如何获取ContentView以及Activity所设置的View?ViewRootIml如何和DecorView建立联系?

3.0.0.5 getWidth()方法和getMeasureWidth()区别呢?为什么有时候用getWidth()或者getMeasureWidth()得到0?

3.0.0.6 平时写的自定义控件有哪些?如何优化自定义view?View的绘制流程说一下?自定义View的注意点?

3.0.0.7 View的wrap_content和match_parent效果一致的原因分析?getDefaultSize方法的处理逻辑?

3.0.0.8 ViewGroup(抽象类)的measure流程?getChildMeasureSpec获取子元素MeasureSpec的要点?

3.0.0.9 View的layout过程?View的layout()源码分析?LinearLayout的onLayout方法?View的测量宽高和最终宽高有什么区别?

3.0.1.0 draw的过程步骤是什么?View特殊方法setWillNotDraw是干什么用的?

3.0.1.1 View中x,y,translationX,translationY分别是什么?View平移时是否改变了left、top等原始参数?

3.0.1.2 MeasureSpec是什么?MeasureSpec的组成?测量模式SpecMode的类型和具体含义?MeasureSpec和LayoutParams的对应关系?

3.0.1.3 如何获取View的测量宽/高?如何在Activity启动时获得View的宽/高?Activity中获得View宽高的4种办法?

3.0.1.4 Activity启动到最终加载ViewRoot(执行三大流程)的流程是什么?

3.0.1.5 自定义View性能优化有哪些?针对异常销毁,自定义View如何优化?如何避免创建大量对象?

好消息

博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!

链接地址:https://github.com/yangchong2...

如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!所有的笔记将会更新到GitHub上,同时保持更新,欢迎同行提出或者push不同的看法或者笔记!

3.0.0.1 View的绘制需要经过哪些过程?有哪些常用回调方法?View的绘制流程的详细流程是怎样的?

View的绘制需要经过哪些过程?

measure:测量View的宽和高

View的measure方法是final类型方法——表明该方法无法被重载

View的measure方法会调用onMeasure方法,onMeasure会调用setMeasuredDimension方法设置View宽/高的测量值

layout:确定View在父控件中的放置位置

draw:负责将View绘制在屏幕上。技术博客大总结

有哪些常用回调方法?

构造方法

onAttachToWindow:在包含View的Activity启动时调用

onDetachFromWindow:在包含View的Activity退出或者View被remove时回调

onVisibilityChanged:当View的可见状态发生改变时调用

比较重要的概念

ViewRoot:连接WindowManager(外界访问Window的入口)和DecorView(顶级View)的纽带,View的三大流程均是通过ViewRoot来完成的。

DecorView:顶级View

DecorView是顶级View,本质就是一个FrameLayout

包含了两个部分,标题栏和内容栏

内容栏id是content,也就是activity中setContentView所设置的部分,最终将布局添加到id为content的FrameLayout中

View的绘制流程的详细流程是怎样的?技术博客大总结

View的绘制流程是从ViewRoot的PerformTraversals方法开始的。大概的流程如下所示

performTraversals会依次调用performMeasure, performLayout, performDraw三个方法,这三个方法分别完成顶层View的measure,layout,draw方法,onMeasure又会调用所有子元素的measure过程,直到完成整个View树的遍历。同理,performLayout, performDraw的传递流程与performMeasure相似。唯一不同在于,performDraw的传递过程在draw方法中通过dispatchDraw实现,但没有本质区别。

Measure过程后可以调用getMeasureWidth和getMeasureHeight方法获取View测量后的宽高,与getWidth和getHeight的区别是:getMeasuredHeight()返回的是原始测量高度,与屏幕无关,getHeight()返回的是在屏幕上显示的高度。实际上在当屏幕可以包裹内容的时候,他们的值是相等的,只有当view超出屏幕后,才能看出他们的区别。当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的高度。

Layout过程确定View四个顶点的位置和实际的宽高。

Draw过程确定View的显示,只有draw方法完成后View的内容才会出现在屏幕上。

3.0.0.2 View绘制流程,当一个TextView的实例调用setText()方法后执行了什么?请说一下原理……

View的绘制流程主要分为三步:

onMeasure:测量视图的大小,从顶层父View到子View递归调用measure()方法,measure()调用onMeasure()方法,onMeasure()方法完成绘制工作。

onLayout:确定视图的位置,从顶层父View到子View递归调用layout()方法,父View将上一步measure()方法得到的子View的布局大小和布局参数,将子View放在合适的位置上。

onDraw:绘制最终的视图,首先ViewRoot创建一个Canvas对象,然后调用onDraw()方法进行绘制。onDraw()方法的绘制流程为

① 绘制视图背景。

② 绘制画布的图层。 技术博客大总结

③ 绘制View内容。

④ 绘制子视图,如果有的话。

⑤ 还原图层。

⑥ 绘制滚动条。

3.0.0.3 requestLayout()、invalidate()与postInvalidate()有什么区别?requestLayout()何时不会触发onDraw()?

invalidate() postInvalidate()

invalidate()该方法递归调用父View的invalidateChildInParent()方法,直到调用ViewRootImpl的invalidateChildInParent()方法,最终触发ViewRootImpl的performTraversals()方法,此时mLayoutRequestede为false,不会触发onMesaure()与onLayout()方法,有可能会触发onDraw()方法。

共同点:都是调用onDraw()方法,然后去达到重绘view的目的

区别:invalidate()用于主线程,postInvalidate()用于子线程

requestLayout()

该方法会递归调用父窗口的requestLayout()方法,直到触发ViewRootImpl的performTraversals()方法,此时mLayoutRequestede为true,会触发onMesaure()与onLayout()方法,不一定会触发onDraw()方法。

当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view(父类的视图)重新调用他的onMeasure、onLayout来重新设置自己位置。特别是当view的layoutparameter发生改变,并且它的值还没能应用到view上时,这时候适合调用这个方法requestLayout()。requestLayout调用onMeasure和onLayout,不一定调用onDraw技术博客大总结

如何选择

一般说来需要重新布局就调用requestLayout()方法,需要重新绘制就调用invalidate()方法。

requestLayout()何时不会触发onDraw()?

如果没有改变控件的leftrighttopbottom就不会触发onDraw()

invalidate()在什么情况下不会触发onDraw?

在ViewGroup中,invalidate默认不重新绘制子view。

如何让ViewGroup在invalidate时会触发onDraw?技术博客大总结

本质需要将ViewGroup的dirtyOpaque设置为false

1.在构造函数中调用setWillNotDraw(false);

2.给ViewGroup设置背景。调用setBackground。

3.0.0.4 DecorView的作用是什么?DecorView中如何获取ContentView以及Activity所设置的View?ViewRootIml如何和DecorView建立联系?

DecorView的作用是什么?

DecorView是顶级View,本质就是一个FrameLayout

包含了两个部分,标题栏和内容栏,内容栏id是content,也就是activity中setContentView所设置的部分,最终将布局添加到id为content的FrameLayout中技术博客大总结

DecorView中如何获取ContentView以及Activity所设置的View?

获取content:ViewGroup content = findViewById(R.android.id.content)

获取设置的View:content.getChidlAt(0)

ViewRootIml如何和DecorView建立联系?技术博客大总结

Activity对象在ActivityThread中创建完毕后,会将DecorView添加到Window中

同时会创建ViewRootImpl,调用ViewRoot的setView方法将ViewRootImpl和DevorView建立关联

root = new ViewRootImpl(view.getContext(), display);
root.setView(view, wparams, panelParentView);

ViewRoot为什么要和DecorView建立关联

DecorView等View的三大流程需要通过ViewRoot完成

3.0.0.5 getWidth()方法和getMeasureWidth()区别呢?为什么有时候用getWidth()或者getMeasureWidth()得到0?

getWidth()方法和getMeasureWidth()区别呢

getMeasureWidth()

getMeasureWidth()方法在measure()过程结束后就可以获取到了,另外,getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的

这里mMeasuredWidth & MEASURED_SIZE_MASK表示的是测量阶段结束之后,view真实的值。

public final int getMeasuredWidth() {
    return mMeasuredWidth & MEASURED_SIZE_MASK;
}

getWidth()

getWidth()方法要在layout()过程结束后才能获取到,getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。

mRight和mLeft是什么值,是在什么时候被设置的。具体看layout()过程中源码

@ViewDebug.ExportedProperty(category = "layout")
public final int getWidth() {
    return mRight - mLeft;
}

为什么有时候用getWidth()或者getMeasureWidth()得到0

问题描述:使用getMeasuredWidth()和getMeasuredHeight()方法,无论是在onCreate()、onStart()、onResume()中调用,都无法得到控件的长度、和宽度。如下图,测量的结果为0。

解释:技术博客大总结

因为View的Measure过程和Activity的生命周期方法不是同步执行的,所以无法保证Activity执行了onCreate()、onStart()、onResume()时某个View已经测量完毕了,如果View还没有测量完毕,那么获得宽/高就是0。

后来觉得这种解释有点牵强,比如

解决控件测量宽高问题

如下所示

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    test();
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    getWidth(4);
}

private void test(){
    getWidth(1);
    
    marqueeView.measure(0, 0);
    getWidth(2);
    
    marqueeView.post(new Runnable() {
        @Override
        public void run() {
            getWidth(3);
        }
    });
}

private void getWidth(int a){
    int width2 = marqueeView.getWidth();
    int measuredWidth2 = marqueeView.getMeasuredWidth();
    Log.e(a+"MainActivity-----",width2+"-----"+measuredWidth2);
}

//11-28 17:03:17.559 15990-15990/com.yc.cn.ycbanner E/1MainActivity-----: 0-----0
//11-28 17:03:17.567 15990-15990/com.yc.cn.ycbanner E/2MainActivity-----: 0-----760
//11-28 17:03:17.684 15990-15990/com.yc.cn.ycbanner E/3MainActivity-----: 960-----960
//11-28 17:03:17.685 15990-15990/com.yc.cn.ycbanner E/4MainActivity-----: 960-----960

什么时候测量宽高不等于实际宽高?

MeasuredWidth/height!=getWidth/Height()的场景:更改View的布局参数并进行重新布局后,就会导致测量宽高!=实际宽高

3.0.0.6 平时写的自定义控件有哪些?如何优化自定义view?View的绘制流程说一下?自定义View的注意点?

平时写的自定义控件有哪些?

1组合控件。这种自定义控件不需要我们自己绘制,而是使用原生控件组合成的新控件。如标题栏,recyclerView封装控件。

2继承原有的控件。这种自定义控件在原生控件提供的方法外,可以自己添加一些方法。比如图片缩放控件,进度条控件。

3完全自定义控件:这个View上所展现的内容全部都是我们自己绘制出来的。比如百分比进度条控件

如何优化自定义 view

为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。

你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate().因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。技术博客大总结

另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。

如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展示了如何继承ViewGroup作为自定义view的一部分。PieChart 有子views,但是它从来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。

View的绘制流程说一下?

View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw()

第一步:OnMeasure():测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。

第二步:OnLayout():确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。

第三步:OnDraw():绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;⑤、还原图层(Layer);⑥、绘制滚动条。技术博客大总结

自定义View的注意点?

View需要支持wrap_content、padding

ViewGroup需要支持子View的margin和自身的padding

尽量不要在View中使用Handler,View已经有post系列方法

View如果有线程或者动画,需要及时停止(onDetachedFromWindow会在View被remove时调用)——避免内存泄露

View如果有滑动嵌套情形,需要处理好滑动冲突

3.0.0.7 View的wrap_content和match_parent效果一致的原因分析?getDefaultSize方法的处理逻辑?

View的wrap_content和match_parent效果一致的原因分析?

根据View的onMeasure方法中的getDefaultSize方法,我们可以发现在两种模式下,View的测量值等于该View的测量规格MeasureSpec中的尺寸。

View的MeasureSpec本质是由自身的LayoutParams和父容器的MeasureSpec决定的。

当View为wrap_content时,该View的模式为AT_MOST,且尺寸specSize为父容器的剩余空间大小。

当View为match_parent时,该View的模式跟随父容器的模式(AT_MOST/EXACTLY), 且尺寸specSize为父容器的剩余空间大小。

因此getDefaultSize中无论View是哪种模式,最终测量宽/高均等于尺寸specSize,因此两种属性效果是完全一样的(View的大小充满了父容器的剩余空间)技术博客大总结

除非给定View固定的宽/高,View的specSize才会等于该固定值。

getDefaultSize方法的处理逻辑?

getDefaultSize: 根据建议获取的最小宽高和测量规格,决定实际的测量宽高

UNSPECIFIED模式:测量宽高 = 建议的最小宽高

EXACTLY / AT_MOST模式:测量宽高 = specSize技术博客大总结

View的getDefaultSize源码要点(决定了View宽高的测量值)

UNSPECIFIED模式时,宽/高为第一个参数也就是getSuggestedMinimumWidth()获取的建议最小值

AT_MOST(wrap_content)和EXACTLY(match_parent/具体值dp等)这两个模式下,View宽高的测量值为当前View的MeasureSpec(测量规格)中指定的尺寸specsize

3.0.0.8 ViewGroup(抽象类)的measure流程?getChildMeasureSpec获取子元素MeasureSpec的要点?

ViewGroup(抽象类)的measure流程?

ViewGroup没有onMeasure方法,只定义了measureChildren方法(onMeasure根据不同布局难以统一)

measureChildren中遍历所有子元素并调用measureChild方法

measureChild方法中会获取子View的MeasureSpec(getChildMeasureSpec),然后调用子元素View的measure方法进行测量

getChildMeasureSpec获取子元素MeasureSpec的要点?

子View的MeasureSpec是根据自身的LayoutParams和父容器SpecMode生成

当子View的布局参数为wrap_content,且父容器模式为AT_MOST时,效果与子元素布局为match_parent是一样的。因此当子View的布局参数为wrap_content时,需要给指定默认的宽/高

LinearLayout的onMeasure()分析

ViewGroup因为布局的不同,无法统一onMeasure方法,具体内容根据布局的不同而不同,这里直接以LinearLayout进行分析

onMeasure会根据orientation选择measureVertical或者measureHorizontal进行测量

measureVertical本质是遍历子元素,并执行子元素的measure方法,并获得子元素的总高度以及子元素在竖直方向上的margin等。技术博客大总结

最终LinearLayout会测量自己的大小,在orientation的方向上,如果布局是match_parent或者具体数值,测量过程与View一致(高度为specSize);如果布局是wrap_content,高度是所有子元素高度总和,且不会超过父容器的剩余空间,最终高度需要考虑在竖直方向上的padding

3.0.0.9 View的layout过程?View的layout()源码分析?LinearLayout的onLayout方法?View的测量宽高和最终宽高有什么区别?

View的layout过程?

使用layout方法确定View本身的位置

layout中调用onLayout方法确定所有子View的位置

View的layout()源码分析?

调用setFrame()设置View四个定点位置(即初始化mLeft,mRight,mTop,mBottom的值)

之后调用onLayout确定子View位置,该方法类似于onMeasure,View和ViewGroup中均没有实现,具体实现与具体布局有关。

LinearLayout的onLayout方法?

根据orientation选择调用layoutVertical或者layoutHorizontal

layoutVertical中会遍历所有子元素并调用setChildFrame(里面直接调用子元素的layout方法)

层层传递下去完成了整个View树的layout过程

setChildFrame中的宽/高实际就是子元素的测量宽/高(getMeasure…后直接传入)

View的测量宽高和最终宽高有什么区别?技术博客大总结

等价于getMeasuredWidth和getWidth有什么区别

getWidth = mRight - mLeft,结合源码测量值和最终值是完全相等的。

区别在于:测量宽高形成于measure过程,最终宽高形成于layout过程(赋值时机不同)

也有可能导致两者不一致:强行重写View的layout方法,在传参方面改变最终宽/高(虽然这样毫无实际意义)

某些情况下,View需要多次measure才能确定自己的测量宽高,在前几次测量中等到的值可能有最终宽高不一致。但是最终结果上,测量宽高=最终宽高

3.0.1.0 draw的过程步骤是什么?View特殊方法setWillNotDraw是干什么用的?

draw的过程步骤是什么?

绘制背景(drawBackground(canvas))

绘制自己(onDraw)

绘制children(dispatchDraw)-遍历调用所有子View的draw方法

绘制装饰(如onDrawScollBars)

View特殊方法setWillNotDraw是干什么用的?

若一个View不绘制任何内容,需要将该标志置为true,系统会进行相应优化

默认View不开启该标志位技术博客大总结

默认ViewGroup开启该标志位

如果我们自定义控件继承自ViewGroup并且本身不进行绘制时,就可以开启该标志位

当该ViewGroup明确通过onDraw绘制内容时,就需要显式关闭WILL_NOT_DRAW标志位。

3.0.1.1 View中x,y,translationX,translationY分别是什么?View平移时是否改变了left、top等原始参数?

View中x,y,translationX,translationY分别是什么?

x,y是View当前左上角的坐标

translationX,translationY是在滑动/动画后,View当前位置和View最原始位置的距离。

因此得出等式:x(View左上角当前位置) = left(View左上角初始位置) + translationX(View左上角偏移的距离)

View平移时是否改变了left、top等原始参数?技术博客大总结

View平移时top、left等参数不变,改变的是x,y,tranlsationX和tranlsationY

3.0.1.2 MeasureSpec是什么?MeasureSpec的组成?测量模式SpecMode的类型和具体含义?MeasureSpec和LayoutParams的对应关系?

MeasureSpec是什么?

MeasureSpec是一种“测量规则”或者“测量说明书”,决定了View的测量过程

View的MeasureSpec会根据自身的LayoutParamse和父容器的MeasureSpec生成。

最终根据View的MeasureSpec测量出View的宽/高(测量时数据并非最终宽高)

MeasureSpec的组成?

MeasureSpec代表一个32位int值,高2位是SpecMode,低30位是SpecSize

SpecMode是指测量模式

SpecSize是指在某种测量模式下的大小

类MesaureSpec提供了用于SpecMode和SpecSize打包和解包的方法

测量模式SpecMode的类型和具体含义?技术博客大总结

UNSPECIFIED:父容器不对View有任何限制,一般用于系统内部

EXACTLY:精准模式,View的最终大小就是SpecSize指定的值(对应于LayoutParams的match_parent和具体的数值)

AT_MOST:最大值模式,大小不能大于父容器指定的值SpecSize(对应于wrap_content)

MeasureSpec和LayoutParams的对应关系?

View的MeasureSpec是需要通过自身的LayoutParams和父容器的MeasureSpec一起才能决定

DecorView(顶级View)是例外,其本身MeasureSpec由窗口尺寸和自身LayoutParams共同决定

MeasureSpec一旦确定,onMeasure中就可以确定View的测量宽/高

3.0.1.3 如何获取View的测量宽/高?如何在Activity启动时获得View的宽/高?Activity中获得View宽高的4种办法?

如何获取View的测量宽/高?

在measure完成后,可以通过getMeasuredWidth/Height()方法,就能获得View的测量宽高

在一定极端情况下,系统需要多次measure,因此得到的值可能不准确,最好的办法是在onLayout方法中获得测量宽/高或者最终宽/高

如何在Activity启动时获得View的宽/高?

Activity的生命周期与View的measure不是同步运行,因此在onCreate/onStart/onResume均无法正确得到

若在View没有测量好时,去获得宽高,会导致最终结果为0

有四种办法去正确获得宽高

Activity中获得View宽高的4种办法?技术博客大总结

onWindowFocusChanged

View已经初始化完毕,可以获得宽高;Activity得到焦点和失去焦点均会调用一次(频繁onResume和onPause会导致频繁调用)

view.post(runnable)

通过post将一个runnable投递到消息队列尾部;等到Looper调用次runnable时,View已经完成初始化

ViewTreeObserver

使用ViewTreeObserver的接口,可以在View树状态改变或者View树内部View的可见性改变时,onGlobalLayout会被回调;能正确获取View宽/高

view.measure

3.0.1.4 Activity启动到最终加载ViewRoot(执行三大流程)的流程是什么?

Activity启动到最终加载ViewRoot(执行三大流程)的流程是什么?

Activity调用startActivity方法,最终会调用ActivityThread的handleLaunchActivity方法

handleLaunchActivity会调用performLauchActivity方法(会调用Activity的onCreate,并完成DecorView的创建)和handleResumeActivity方法

handleResumeActivity方法会做四件事:performResumeActivity(调用activity的onResume方法)、getDecorView(获取DecorView)、getWindowManager(获取WindowManager)、WindowManager.addView(decor, 1)

WindowManager.addView(decor, 1)本质是调用WindowManagerGlobal的addView方法。其中主要做两件事:1、创建ViewRootImpl实例 2、root.setView(decor, ….)将DecorView作为参数添加到ViewRoot中,这样就将DecorView加载到了Window中

ViewRootImpl还有一个方法performTraveals方法,用于让ViewTree开始View的工作流程:其中会调用performMeasure/Layout/Draw()三个方法,分别对应于View的三大流程。

3.0.1.5 自定义View性能优化有哪些?针对异常销毁,自定义View如何优化?如何避免创建大量对象?

自定义View性能优化有哪些?

避免过度绘制

尽量减少或简化计算

避免创建大量对象造成频繁GC

禁止或避免I/O操作

onDraw中避免冗余代码、避免创建对象

复合View,要减少布局层级。

状态和恢复和保存

开启硬件加速

合理使用invalidate的参数版本。

减少冗余代码:不要使用Handler,因为已经有post系列方法.

使用的线程和动画,要在onDetachedFromWindow中进行清理工作。

要妥善处理滑动冲突。

避免过度绘制

像素点能画一次就不要多次绘制,以及绘制看不到的背景

开发者选项里内的工具,只对xml布局有效果,看不到自定义View的过度绘制,仍然需要注意。

尽量减少或简化计算

不要做无用计算。尽可能的复用计算结果。技术博客大总结

没有数据,或者数据较少的时候应如何处理,没有事件需要响应的时候如何处理。

应该避免在for或while循环中做计算。比如:去计算屏幕宽度等信息。

避免创建大量对象造成频繁GC

应该避免在for或while循环中new对象。这是减少内存占用量的有效方法。

禁止或避免I/O操作

I/O操作对性能损耗极大,不要在自定义View中做IO操作。

onDraw中避免冗余代码、避免创建对象

onDraw中禁止new对象.如:不应该在ondraw中创建Paint对象。Paint类提供了reset方法。可以在初始化View时创建对象。

要避免冗余代码,提高效率。

复合View,要减少布局层级。

复合控件:继承自现有的LinearLayout等ViewGroup,然后组合多个控件来实现效果。这种实现方法要注意减少布局层级,层级越高性能越差。

状态和恢复和保存

Activity还会因为内存不足或者旋转屏幕而导致重建Activity,自定义View也要去进行自我状态的保存和读取。

在onSaveInstanceState()保存状态;在onRestoreInstanceState()恢复状态

开启硬件加速

合理使用invalidate的参数版本。技术博客大总结

避免任何请款下之际调用默认参数的invalidate

调用有参数的invalidate进行局部和子View刷新,能够提高性能。

减少冗余代码:不要使用Handler,因为已经有post系列方法

View已经有post系列方法,没有必要重复去写。

可以直接使用,最终会投递到主线程的Handler中

使用的线程和动画,要在onDetachedFromWindow中进行清理工作。

View如果有线程或者动画,需要及时停止.

View的onDetachedFromWindow会在View被remove时调用,在该方法内进行终止

这样能避免内存泄露

要妥善处理滑动冲突。

View如果有滑动嵌套情形,需要处理好滑动冲突

关于其他内容介绍 01.关于博客汇总链接

1.技术博客汇总

2.开源项目汇总

3.生活博客汇总

4.喜马拉雅音频汇总

5.其他汇总

02.关于我的博客

我的个人站点:www.yczbj.org, www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

简书:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜马拉雅听书:http://www.ximalaya.com/zhubo...

开源中国:https://my.oschina.net/zbj161...

泡在网上的日子:http://www.jcodecraeer.com/me...

邮箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault头条:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72864.html

相关文章

  • 08.AndroidView事件问题

    摘要:内部是调用效果是移动的内容,因此需要在的父控件中调用。和的情况相似,手机屏幕向下移动,为正值手机屏幕向上移动,为负值。 目录介绍 8.0.0.1 简述Android的事件分发机制?dispatchTouchEvent方法的作用是什么?说下View和ViewGroup分发事件? 8.0.0.2 onInterceptTouchEvent方法作用是什么?onTouchEvent的方法的作...

    lavnFan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<