Android面试基础二-原理及常见问题

46 篇文章 2 订阅
3 篇文章 1 订阅

Android 面试基础一

目录


有些问题只有题目,没有参考答案的,后续补充,请自行学习了解,有学习心得评论区留下,以传后人。

Android源码相关分析

1、Android属性动画实现原理

工作原理:在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果。

差值器
实现Interpolator接口,根据时间来计算当前属性需要改变的百分比值。设置值的变化趋势,SDK中包含了匀速插值器LinearInterpolator、加速插值器、减速插值器DecelerateInterpolator、先加速再减速AccelerateDecelerateInterpolator。
估值器
根据属性变化的百分比值来计算改变后的属性值。需要实现TypeEvaluatior接口

  1. ValueAnimator:通过不断控制值的变化(初始值->结束值),将值手动赋值给对象的属性,再不断调用View的invalidate()方法,去不断onDraw重绘view,达到动画的效果。
    主要的三种方法:

    • ValueAnimator.ofInt(int values):估值器是整型估值器IntEaluator
    • ValueAnimator.ofFloat(float values):估值器是浮点型估值器FloatEaluator
    • ValueAnimator.ofObject(ObjectEvaluator, start, end):将初始值以对象的形式过渡到结束值,通过操作对象实现动画效果,需要实现Interpolator接口,自定义估值器

估值器TypeEvalutor,设置动画如何从初始值过渡到结束值的逻辑。插值器(Interpolator)决定值的变化模式(匀速、加速等);估值器(TypeEvalutor)决定值的具体变化数值。

    // 自定义估值器,需要实现TypeEvaluator接口

    public class ObjectEvaluator implements TypeEvaluator{  

    // 复写evaluate(),在evaluate()里写入对象动画过渡的逻辑

        @Override  

        public Object evaluate(float fraction, Object startValue, Object endValue) {  

            // 参数说明

            // fraction:表示动画完成度(根据它来计算当前动画的值)

            // startValue、endValue:动画的初始值和结束值

            ... // 写入对象动画过渡的逻辑

            return value;  

            // 返回对象动画过渡的逻辑计算后的值

        }
  1. ObjectAnimator:直接对对象的属性值进行改变操作,从而实现动画效果

ObjectAnimator继承自ValueAnimator类,底层的动画实现机制还是基本值的改变。它是不断控制值的变化,再不断自动赋给对象的属性,从而实现动画效果。这里的自动赋值,是通过调用对象属性的set/get方法进行自动赋值,属性动画初始值如果有就直接取,没有则调用属性的get()方法获取,当值更新变化时,通过属性的set()方法进行赋值。每次赋值都是调用view的postInvalidate()/invalidate()方法不断刷新视图(实际调用了onDraw()方法进行了重绘视图)。

//Object 需要操作的对象; propertyName 需要操作的对象的属性; values动画初始值&结束值,
//如果是两个值,则从a->b值过渡,如果是三值,则从a->b->c

ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String propertyName, float ...values);

如果采用ObjectAnimator类实现动画,操作的对象的属性必须有get()和set()方法。

其他用法:

  1. AnimatorSet组合动画
    AnimatorSet.play(Animator anim) :播放当前动画
    AnimatorSet.after(long delay) :将现有动画延迟x毫秒后执行
    AnimatorSet.with(Animator anim) :将现有动画和传入的动画同时执行
    AnimatorSet.after(Animator anim) :将现有动画插入到传入的动画之后执行
    AnimatorSet.before(Animator anim) :将现有动画插入到传入的动画之前执行
  1. ViewPropertyAnimator直接对属性操作,View.animate()返回的是一个ViewPropertyAnimator对象,之后的调用方法都是基于该对象的操作,调用每个方法返回值都是它自身的实例
View.animate().alpha(0f).x(500).y(500).setDuration(500).setInterpolator()
  1. 设置动画监听
    Animation.addListener(new AnimatorListener() {

              @Override
              public void onAnimationStart(Animation animation) {
                  //动画开始时执行
              }

               @Override
              public void onAnimationRepeat(Animation animation) {
                  //动画重复时执行
              }

             @Override
              public void onAnimationCancel()(Animation animation) {
                  //动画取消时执行
              }

              @Override
              public void onAnimationEnd(Animation animation) {
                  //动画结束时执行
              }
          });

2、补间动画实现原理

主要有四种AlpahAnimation\ ScaleAnimation\ RotateAnimation\ TranslateAnimation四种,对透明度、缩放、旋转、位移四种动画。在调用View.startAnimation时,先调用View.setAnimation(Animation)方法给自己设置一个Animation对象,再调用invalidate来重绘自己。在View.draw(Canvas, ViewGroup, long)方法中进行了getAnimation(), 并调用了drawAnimation(ViewGroup, long, Animation, boolean)方法,此方法调用Animation.getTranformation()方法,再调用applyTranformation()方法,该方法中主要是对Transformation.getMatrix().setTranslate/setRotate/setAlpha/setScale来设置相应的值,这个方法系统会以60FPS的频率进行调用。具体是在调Animation.start()方法中会调用animationHandler.start()方法,从而调用了scheduleAnimation()方法,这里会调用mChoreographer.postCallback(Choregrapher.CALLBACK_ANIMATION, this, null)放入事件队列中,等待doFrame()来消耗事件。

当一个 ChildView 要重画时,它会调用其成员函数 invalidate() 函数将通知其 ParentView 这个 ChildView 要重画,这个过程一直向上遍历到 ViewRoot,当 ViewRoot 收到这个通知后就会调用ViewRoot 中的 draw 函数从而完成绘制。View::onDraw() 有一个画布参数 Canvas, 画布顾名思义就是画东西的地方,Android 会为每一个 View 设置好画布,View 就可以调用 Canvas 的方法,比如:drawText, drawBitmap, drawPath 等等去画内容。每一个 ChildView 的画布是由其 ParentView 设置的,ParentView 根据 ChildView 在其内部的布局来调整 Canvas,其中画布的属性之一就是定义和 ChildView 相关的坐标系,默认是横轴为 X 轴,从左至右,值逐渐增大,竖轴为 Y 轴,从上至下,值逐渐增大。

Android 补间动画就是通过 ParentView 来不断调整 ChildView 的画布坐标系来实现的,在ParentView的dispatchDraw方法会被调用。

    dispatchDraw() {
    ....
    Animation a = ChildView.getAnimation()
    Transformation tm = a.getTransformation();
    Use tm to set ChildView's Canvas;
    Invalidate();
    ....
    }

这里有两个类:Animation 和 Transformation,这两个类是实现动画的主要的类,Animation 中主要定义了动画的一些属性比如开始时间、持续时间、是否重复播放等,这个类主要有两个重要的函数:getTransformation 和 applyTransformation,在 getTransformation 中 Animation 会根据动画的属性来产生一系列的差值点,然后将这些差值点传给 applyTransformation,这个函数将根据这些点来生成不同的 Transformation,Transformation 中包含一个矩阵和 alpha 值,矩阵是用来做平移、旋转和缩放动画的,而 alpha 值是用来做 alpha 动画的(简单理解的话,alpha 动画相当于不断变换透明度或颜色来实现动画),调用 dispatchDraw 时会调用 getTransformation 来得到当前的 Transformation。某一个 View 的动画的绘制并不是由他自己完成的而是由它的父 view 完成。

补间动画TranslateAnimation,View位置移动了,可是点击区域还在原来的位置,为什么?

View在做动画是,根据动画时间的插值,计算出一个Matrix,不停的invalidate,在onDraw中的Canvas上使用这个计算出来的Matrix去draw view的内容。某个view的动画绘制并不是由它自己完成,而是由它的父view完成,使它的父view画布进行了移动,而点击时还是点击原来的画布。使得它看起来变化了。

参考文章:Android 动画框架详解,第 1 部分

3、Android各个版本API的区别

Android API版本对照表及各个版本特性简单描述

主要记住一些大版本变化:

android3.0 代号Honeycomb, 引入Fragments, ActionBar,属性动画,硬件加速

android4.0 代号Ice Cream,API14:截图功能,人脸识别,虚拟按键,3D优化驱动

android5.0 代号Lollipop API21:调整桌面图标及部件透明度等

android6.0 代号M Marshmallow API23,软件权限管理,安卓支付,指纹支持,App关联,

android7.0 代号N Preview API24,多窗口支持(不影响Activity生命周期),增加了JIT编译器,引入了新的应用签名方案APK Signature Scheme v2(缩短应用安装时间和更多未授权APK文件更改保护),严格了权限访问

android8.0 代号O API26,取消静态广播注册,限制后台进程调用手机资源,桌面图标自适应

android9.0 代号P API27,加强电池管理,系统界面添加了Home虚拟键,提供人工智能API,支持免打扰模式

4、Requestlayout,onlayout,onDraw,DrawChild区别与联系

requestLayout()方法 :会导致调用measure()过程 和 layout()过程 。 说明:只是对View树重新布局layout过程包括measure()和layout()过程,如果view的l,t,r,b没有必变,那就不会触发onDraw;但是如果这次刷新是在动画里,mDirty非空,就会导致onDraw。

onLayout()方法(如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局)

onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)

drawChild()去重新回调每个子视图的draw()方法

5、invalidate和postInvalidate的区别及使用

View.invalidate(): 层层上传到父级,直到传递到ViewRootImpl后触发了scheduleTraversals(),然后整个View树开始重新按照View绘制流程进行重绘任务。

invalidate:在ui线程刷新view

postInvalidate:在工作线程刷新view(底层还是handler)其实它的原理就是invalidate+handler

View.postInvalidate最终会调用ViewRootImpl.dispatchInvalidateDelayed()方法

public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
	Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); 
	mHandler.sendMessageDelayed(msg, delayMilliseconds);
}

这里的mHandler是ViewRootHandler实例,在该Handler的handleMessage方法中调用了view.invalidate()方法。

	 case MSG_INVALIDATE:
	 	((View) msg.obj).invalidate();
		break;

6、Activity-Window-View三者的差别

Activity:是安卓四大组件之一,负责界面展示、用户交互与业务逻辑处理;

Window:就是负责界面展示以及交互的职能部门,就相当于Activity的下属,Activity的生命周期方法负责业务的处理;

View:就是放在Window容器的元素,Window是View的载体,View是Window的具体展示。

三者的关系: Activity通过Window来实现视图元素的展示,window可以理解为一个容器,盛放着一个个的view,用来执行具体的展示工作。

7、谈谈对Volley的理解

待补充:

8、如何优化自定义View

  1. 在要在onDraw或是onLayout()中去创建对象,因为onDraw()方法可能会被频繁调用,可以在view的构造函数中进行创建对象;

  2. 降低view的刷新频率,尽可能减少不必要的调用invalidate()方法。或是调用带四种参数不同类型的invalidate(),而不是调用无参的方法。无参变量需要刷新整个view,而带参数的方法只需刷新指定部分的view。在onDraw()方法中减少冗余代码。

  3. 使用硬件加速,GPU硬件加速可以带来性能增加。

  4. 状态保存与恢复,如果因内存不足,Activity置于后台被杀重启时,View应尽可能保存自己属性,可以重写onSaveInstanceState和onRestoreInstanceState方法,状态保存。

9、低版本SDK如何实现高版本api?

使用@TargetApi注解·

当代码中有比gradle中设置的targetSdkVersion版本更高的方法,此时编译器会提示警告,解决方法是在方法上加上@SuppressLint(“NewApi”)或者@TargetApi()。但它们仅是屏蔽了android lint错误,在方法中还要判断版本做不同的操作。

@SuppressLint(“NewApi”)屏蔽一切新api中才能使用的方法报的android lint错误

@TargetApi() 只屏蔽某一新api中才能使用的方法报的android lint错误,如@TargetApi(11)如果在方法中用了只有API14才开始有的方法,还是会报错。

10、描述一次网络请求的流程

  1. 域名解析
    浏览器会先搜索自身DNS缓存且对应的IP地址没有过期;若未找到则搜索操作系统自身的DNS缓存;若还未找到则读本地的hotsts文件;还未找到会在TCP/IP设置的本地DNS服务器上找,如果要查询的域名在本地配置的区域资源中,则完成解析;否则根据本地DNS服务器会请求根DNS服务器;根DNS服务器是13台根DNS,会一级一级往下找。
  1. TCP三次握手
    客户端先发送SYN=1,ACK=0,序列号seq=x报文;(SYN在连接建立时用来同步序号,SYN=1,ACK=0代表这是一个连接请求报文,对方若同意建立连接,则应在响应报文中使SYN=1,ACK=1)
    服务器返回SYN=1,ACK=1,seq=y, ack=x+1;
    客户端再一次确认,但不用SYN了,回复服务端, ACK=1, seq=x+1, ack=y+1

  2. 建立TCP连接后发起HTTP请求
    客户端按照指定的格式开始向服务端发送HTTP请求,HTTP请求格式由四部分组成,分别是请求行、请求头、空行、消息体,服务端接收到请求后,解析HTTP请求,处理完成逻辑,最后返回一个具有标准格式的HTTP响应给客户端。

  3. 服务器响应HTTP请求
    服务器接收处理完请求后返回一个HTTP响应消息给客户端,HTTP响应信息格式包括:状态行、响应头、空行、消息体

  4. 浏览器解析HTML代码,请求HTML代码中的资源
    浏览器拿到html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,向服务器发起一个http请求,如果返回304状态码,浏览器会直接读取本地的缓存文件。否则开启线程向服务器请求下载。

  5. 浏览器对页面进行渲染并呈现给用户

  6. TCP的四次挥手
    当客户端没有东西要发送时就要释放连接(提出中断连接可以是Client也可以是Server),客户端会发送一个FIN=1的没有数据的报文,进入FIN_WAIT状态,服务端收到后会给客户端一个确认,此时客户端不能发送数据,但可接收信息。

11、HttpUrlConnection 和 okhttp关系

两者都可以用来实现网络请求,android4.4之后的HttpUrlConnection的实现是基于okhttp

12、自定义View如何考虑机型适配

在onMeasure()的getDefaultSize()的默认实现中,当view的测量模式是AT_MOST或EXACTLY时,View的大小都会被设置成子View MeasureSpec的specSize.子view的MeasureSpec值是根据子View的布局参数和父容器的MeasureSpec值计算得来。当子view的布局参数是wrap_content时,对应的测量模式是AT_MOST,大小是parentSize.
自定义View的事件

13、IntentService原理及作用是什么?

原理:IntentService是继承Service的一个抽象类,它在onCreate()方法中创建了一个HandlerThread,并启动该线程。HandlerThread是带有自己消息队列和Looper的线程,根据HandlerThread的looper创建一个Handler,这样IntentService的ServiceHandler的handleMessage()方法就运行在子线程中。handleMessage中调用了onHandleIntent()方法,它是一个抽象方法,继承IntentService类需要实现该方法,把耗时操作放在onHandleIntent()方法中,等耗时操作运行完成后,会调用stopSelf()方法,服务会调用onDestory()方法消毁自己。如果onHandleIntent()中的耗时操作未运行完前就调用了stopSelf()方法,服务调用onDestory()方法,但耗时操作会继续运行,直至运行完毕。如果同时多次启动IntentService,任务会放在一个队列中,onCreate()和onDestory()方法都只会运行一次。

作用:用来处理后台耗时操作,如读取数据库或是本地文件等。

常见的一些原理性问题

1、Handler机制和底层实现

2、Handler、Thread和HandlerThread的差别

1)Handler线程的消息通讯的桥梁,主要用来发送消息及处理消息。

2)Thread普通线程,如果需要有自己的消息队列,需要调用Looper.prepare()创建Looper实例,调用loop()去循环消息。

3)HandlerThread是一个带有Looper的线程,在HandleThread的run()方法中调用了Looper.prepare()创建了Looper实例,并调用Looper.loop()开启了Loop循环,循环从消息队列中获取消息并交由Handler处理。利用该线程的Looper创建Handler实例,此Handler的handleMessage()方法是运行在子线程中的。即Handler利用哪个线程的Looper创建的实例,它就和相应的线程绑定到一起,处理该线程上的消息,它的handleMessage()方法就是在那个线程中运行的,无参构造默认是主线程。HandlerThread提供了quit()/quitSafely()方法退出HandlerThread的消息循环,它们分别调用Looper的quit和quitSafely方法,quit会将消息队列中的所有消息移除,而quitSafely会将消息队列所有延迟消息移除,非延迟消息派发出去让Handler去处理。

HandlerThread适合处理本地IO读写操作(读写数据库或文件),因为本地IO操作耗时不长,对于单线程+异步队列不会产生较大阻塞,而网络操作相对比较耗时,容易阻塞后面的请求,因此HandlerThread不适合加入网络操作。

3、handler发消息给子线程,looper怎么启动?

4、关于Handler,在任何地方new Handler 都是什么线程下?

5、请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系

6、ThreadLocal原理,实现及如何保证Local属性?

7、请描述一下View事件传递分发机制

8、Touch事件传递流程

9、事件分发中的onTouch 和onTouchEvent 有什么区别,又该如何使用?

10、说说Activity、Intent、Service 是什么关系

11、ApplicationContext和ActivityContext的区别

12、SP是进程同步的吗?有什么方法做到同步?

13、谈谈多线程在Android中的使用

14、进程和 Application 的生命周期

15、封装View的时候怎么知道view的大小

16、RecycleView原理和使用

17、AndroidManifest的作用与理解

18、序列化的作用,以及Android两种序列化的区别

19、AstncTask+HttpClient 与 AsyncHttpClient有什么区别?

20、LaunchMode应用场景

21、AsyncTask 如何使用?

22、SpareArray原理

23、请介绍下ContentProvider 是如何实现数据共享的?

24、Android Service与Activity之间通信的几种方式

25、Bitmap对象的理解

26、looper架构

27、ActivityThread,AMS,WMS的工作原理

28、View和ViewGroup分别有哪些事件分发相关的回调方法

29、View刷新机制

30、View绘制流程

31、自定义控件原理

32、自定义View如何提供获取View属性的接口?

33、Android代码中实现WAP方式联网

34、AsyncTask机制

35、AsyncTask原理及不足

36、如何取消AsyncTask?

37、为什么不能在子线程更新UI?

38、ANR产生的原因是什么?

39、ANR定位和修正

40、oom是什么?

oom(Out Of Memory)内存溢出。

41、什么情况导致oom?

42、有什么解决方法可以避免OOM?

43、Oom 是否可以try catch?为什么?

可以,当发生OOM的时候会抛出Error,Error是Throwble的子类,可以用tryc catch来捕获。

44、内存泄漏是什么?

内存泄露就是指该被GC垃圾回收的,但被一个生命周期比它长的对象仍然在引用它,导致无法回收,造成内存泄露,过多的内存泄露会导致OOM。

什么情况导致内存泄漏?

  1. 非静态内部类、匿名内部类:非静态内部类、匿名内部类 都会持有外部类的一个引用,如果有一个静态变量引用了非静态内部类或者匿名内部类,导致非静态内部类或者匿名内部类的生命周期比外部类(Activity)长,就会导致外部类在该被回收的时候,无法被回收掉,引起内存泄露, 除非外部类被卸载。
    解决办法:将非静态内部类、匿名内部类 改成静态内部类,或者直接抽离成一个外部类。 如果在静态内部类中,需要引用外部类对象,那么可以将这个引用封装在一个WeakReference中。

  2. 静态的View:当一个Activity经常启动,但是对应的View读取非常耗时,我们可以通过静态View变量来保持对该Activity的rootView引用。这样就可以不用每次启动Activity都去读取并渲染View了。但View attach到我们的Window上,就会持有一个Context(即Activity)的引用。而我们的View有事一个静态变量,所以导致Activity不被回收。
    解决办法: 在使用静态View时,需要确保在资源回收时,将静态View detach掉。

  3. Handler:在Activity中定义Handler对象,那么Handler持有Activty的引用。而每个Message对象是持有Handler的引用的(Message对象的target属性持有Handler引用),从而导致Message间接引用到了Activity。如果在Activty destroy之后,消息队列中还有Message对象,Activty是不会被回收的。
    解决办法: 将Handler放入单独的类或者将Handler放入到静态内部类中(静态内部类不会持有外部类的引用)。如果想要在handler内部去调用所在的外部类Activity,可以在handler内部使用弱引用的方式指向所在Activity,在onDestory时,调用相应的方法移除回调和删除消息。

  4. 监听器(各种需要注册的Listener,Watcher等):当我们需要使用系统服务时,比如执行某些后台任务、为硬件访问提供接口等等系统服务。我们需要把自己注册到服务的监听器中。然而,这会让服务持有 activity 的引用,如果程序员忘记在 activity 销毁时取消注册,那就会导致 activity 泄漏了。
    解决办法:在onDestory中移除注册

  5. 资源对象没关闭造成内存泄漏:当我们打开资源时,一般都会使用缓存。比如读写文件资源、打开数据库资源、使用Bitmap资源等等。当我们不再使用时,应该关闭它们,使得缓存内存区域及时回收。
    解决办法:使用try finally结合,在try块中打开资源,在finally中关闭资源

  6. 属性动画:在使用ValueAnimator或者ObjectAnimator时,如果没有及时做cancel取消动画,就可能造成内存泄露。因为在cancel方法里,最后调用了endAnimation(); ,在endAnimation里,有个AnimationHandler的单例,会持有属性动画对象的引用。
    解决办法:在onDestory中调用动画的cancel方法

  7. RxJava:在使用RxJava时,如果在发布了一个订阅后,由于没有及时取消,导致Activity/Fragment无法销毁,导致的内存泄露。
    解决办法:使用RxLifeCycle

内存泄漏和内存溢出区别?

(1)内存泄漏

1)内存泄漏:指程序中已动态分配的堆内存由于某种原因未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统奔溃等严重后果。

2)一次内存泄漏似乎不会有大的影响,但内存泄漏后堆积的结果就是内存溢出。

3)内存泄漏具有隐蔽性,积累性的特征,比其他内存非法访问错误更难检测。这是因为内存泄漏产生的原因是内存块未被释放,属于遗漏型缺陷而不是过错型缺陷。此外,内存泄漏不会直接产生可观察的错误,而是逐渐积累,降低系统的整体性性能。

4)如何有效的进行内存分配和释放,防止内存泄漏,是软件开发人员的关键问题,比如一个服务器应用软件要长时间服务多个客户端,若存在内存泄漏,则会逐渐堆积,导致一系列严重后果。

(2)内存溢出

指程序在申请内存时,没有足够的内存供申请者使用,或者说,给了一块存储int类型数据的存储空间,但是却存储long类型的数据,就会导致内存不够用,报错OOM,即出现内存溢出的错误。

45 LruCache默认缓存大小 4MB

46 ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)

47 如何通过广播拦截和abort一条短信?

48 广播是否可以请求网络?

49 广播引起anr的时间限制是多少?

50 计算一个view的嵌套层级

51 Activity栈

52 Android线程有没有上限?

理论上是没有上限的,但按一般写法一般是线程最多开到2*CPU个数+1

53 线程池有没有上限?

要根据用户调用不同的线程池构造函数。

54 ListView重用的是什么?

55 Android为什么引入Parcelable?

56 有没有尝试简化Parcelable的使用?

开发中常见的一些问题

1 ListView 中图片错位的问题是如何产生的?

2 屏幕适配的处理技巧都有哪些?

3 服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?

4 动态布局的理解

5 怎么去除重复代码?

6 画出 Android 的大体架构图

7 Recycleview和ListView的区别

8 ListView图片加载错乱的原理和解决方案

ListView item缓存机制:为了使得性能更优,ListView会缓存行item(某行对应的View)。ListView通过adapter的getView函数获得每行的item。
滑动过程中:

  1. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存;

  2. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView。

出现的问题:

  1. 行item图片显示重复,当前行item显示了之前某行item的图片。

比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,加载过程中listView已经滑动到了第14行,且滑动过程中该图片加载结束,第2行已不在屏幕内,根据上面介绍的缓存原理,第2行的view可能被第14行复用,这样我们看到的就是第14行显示了本该属于第2行的图片,造成显示重复。

  1. 行item图片显示闪烁

如果第14行图片又很快加载结束,所以我们看到第14行先显示了第2行的图片,立马又显示了自己的图片进行覆盖造成闪烁错乱。

解决方法

通过上面的分析我们知道了出现错乱的原因是异步加载及对象被复用造成的,如果每次getView能给对象一个标识,在异步加载完成时比较标识与当前行item的标识是否一致,一致则显示,否则不做处理即可。

9 动态权限适配方案,权限组的概念

10 Android系统为什么会设计ContentProvider?

11 下拉状态栏是不是影响activity的生命周期

12 如果在onStop的时候做了网络请求,onResume的时候怎么恢复?

13 Bitmap 使用时候注意什么?

14 Bitmap的recycler()

15 Android中开启摄像头的主要步骤

16 ViewPager使用细节,如何设置成每次只初始化当前的Fragment,其他的不初始化?

17 点击事件被拦截,但是想传到下面的View,如何操作?

18 微信主页面的实现方式

19 微信上消息小红点的原理

20 CAS介绍

混合开发面试题

除了技术深度之外,还要求具备一些广度的知识,比如前端知识,会混合开发,会一种脚本语言,C ++。

1. Hybrid做过吗?

2. Hybrid通信原理是什么,有做研究吗?

3. react native有多少了解?讲一下原理。

4. weex了解吗?如何自己实现类似技术?

5. flutter了解吗?内部是如何实现跨平台的?

6. Dart语言有研究贵吗?

7. 快应用了解吗?跟其她方式相比有什么优缺点?

8. 说说你用过的混合开发技术有哪些?各有什么优缺点?

9. Python会吗?

10. 会不会PHP?

11. Gradle了解多少?groovy语法会吗?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值