内存泄露,OOM,ANR ,Devik 进程,Framework原理,Activity 生成一个 view,Android 中的动画,SurfaceView和V

简介: 内存泄露,OOM,ANR ,Devik 进程,Framework原理,Activity 生成一个 view,Android 中的动画,SurfaceView和V

什么情况下会导致内存泄露



内存泄露是个折腾的问题。


根本原因:长生命周期的对象持有短生命周期的对象。短周期对象就无法及时释放。


I. 静态集合类引起内存泄露

主要是hashmap,Vector等,如果是静态集合 这些集合没有及时setnull的话,就会一直持有这些对象。


II.remove 方法无法删除set集 Objects.hash(firstName, lastName);

经过测试,hashcode修改后,就没有办法remove了。


III. observer 我们在使用监听器的时候,往往是addxxxlistener,但是当我们不需要的时候,忘记removexxxlistener,就容易内存leak。


广播没有unregisterrecevier


IV.各种数据链接没有关闭,数据库contentprovider,io,sokect等。cursor


V.内部类:

java中的内部类(匿名内部类),会持有宿主类的强引用this。

所以如果是new Thread这种,后台线程的操作,当线程没有执行结束时,activity不会被回收。


Context的引用,当TextView 等等都会持有上下文的引用。如果有static drawable,就会导致该内存无法释放。


VI.单例

单例 是一个全局的静态对象,当持有某个复制的类A是,A无法被释放,内存leak(泄漏)。


如何避免OOM



减少内存对象的占用


I.ArrayMap/SparseArray代替hashmap

II.避免在android里面使用Enum

III.减少bitmap的内存占用


  • inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。
  • decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异。
  • ARGB_8888:分别用8位来记录4个值,所以每个像素会占用32位。
    ARGB_4444:分别用4位来记录4个值,所以每个像素会占用16位。
    RGB_565:分别用5位、6位和5位来记录RGB三色值,所以每个像素会占用16位。
    ALPHA_8:根据注释应该是不保存颜色值,只保存透明度(8位),每个像素会占用8位。


IV.减少资源图片的大小,过大的图片可以考虑分段加载


内存对象的重复利用

大多数对象的复用,都是利用对象池的技术。


I.listview/gridview/recycleview contentview的复用

II.inBitmap 属性对于内存对象的复用ARGB_8888/RBG_565/ARGB_4444/ALPHA_8

这个方法在某些条件下非常有用,比如要加载上千张图片的时候。

III.避免在ondraw方法里面 new对象

IV.StringBuilder 代替+


Android 中如何捕获未捕获的异常



CrashHandler

关键是实现Thread.UncaughtExceptionHandler

然后是在application的oncreate里面注册。


怎么避免ANR



ANR的关键是:处理超时,所以应该避免在UI线程,BroadcastReceiver 还有service主线程中,处理复杂的逻辑和计算而交给work thread操作。


1)避免在activity里面做耗时操作,oncreate & onresume

2)避免在onReceiver里面做过多操作

3)避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。

4)尽量使用handler来处理UI thread & workthread的交互。


如何解决ANR



首先定位ANR发生的log:


04-01 13:12:11.572 I/InputDispatcher( 220): **Application i****s not responding**:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}. 5009.8ms since event, 5009.5ms since waitstarted

CPUusage from 4361ms to 699ms ago ----CPU在ANR发生前的使用情况 04-0113:12:15.872 E/ActivityManager( 220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait 04-0113:12:15.872 E/ActivityManager( 220): CPUusage from 3697ms to 4223ms later:-- ANR后CPU的使用量


从log可以看出,cpu在做大量的io操作。

所以可以查看io操作的地方。

当然,也有可能cpu占用不高,那就是 主线程被block(块)住了。


Devik 进程,linux 进程,线程的区别



Dalvik进程。

每一个android app都会独立占用一个dvm虚拟机,运行在linux系统中。

所以dalvik进程和linux进程是可以理解为一个概念。


描述一下 android 的系统架构



从小到上就是:

linux kernel,lib dalvik vm ,application framework, app


Framework 工作方式及原理,Activity 是如何生成一个 view 的,机制是什么



Framework是android 系统对 linux kernel,lib库等封装,提供WMS,AMS,bind机制,handler-message机制等方式,供app使用。


简单来说framework就是提供app生存的环境。


1)Activity在attch方法的时候,会创建一个phonewindow(window的子类)

2)onCreate中的setContentView方法,会创建DecorView

3)DecorView 的addview方法,会把layout中的布局加载进来。


Activity 创建一个 view 是通过 ondraw 画出来的, 画这个 view 之前呢,还会调用 onmeasure方法来计算显示的大小.


Surfaceview 是直接操作硬件的,因为视频播放对帧数有要求,onDraw 效率太低,不够使,Surfaceview 直接把数据写到显存。


Android FrameWork框架原理之进程是个什么东西



首先在Android中一个进程里只能放一个App。(特殊情况:同一个签名的两个App可以放到一个进程里,这里暂不考虑)。当一个App启动,系统zygote孵化器孵化出一个进程来执行这个App。zygote是个什么东东呢?zygote就是一个鸡,不停的生小鸡。zygote是一个进程,当需要启动一个进程来运行App时,zygote这个进程就把自己复制一份,放在另一个空间,就产生了一个进程给这个App来用。底层就是linux,fork(岔路口,分流)一个新进程。新fork的进程里面都有什么呢?


我们需要考虑的部分就是:里面有一个主线程,一个VM(虚拟机),一个Looper,一个MessageQueue。从这里就可以看出,一个进程里面有一个虚拟机。当然这是在Java层来看的,主线程就是UI线程,用来执行代码的,VM就是虚拟的机器,来执行Java字节码的。Looper和MessageQueue接下来细说。


进程产生主线程开始执行。这个时候先重申下线程是个什么东东。线程是执行一段代码用的,执行完这段代码,线程就死了。就这样。这时候我们想这样一个问题,主线程要执行什么,执行完了,死了,我们程序还运行个卵子。所以进程没死,线程应该永远也执行不完。Android中就是这样的,Android的主线程就是这样的,在一个whlie循环里打转转。怎样打转转的呢?主线程也就是一个普通的线程extends


Thread来的嘛,只不过是由FrameWork写好的。启动它的时候调它的start(),由FrameWork在创建它的时候帮我们调了,它的start又调了run(),执行的代码就在run()里面。我们想让主线程不死,就让它在run()里面执行一个 while(true){ },它就一直傻呆在这儿了。这个时候我们已经确保了主线程不会死,但是它要做事啊,不然要它干什么,他怎么做事也就看while循环里的代码怎样写了,这个时候就要看上一篇文章提到的EIT造型了


它只需要在while循环的时候执行一个接口的某个方法,而这个方法是由我们来实现的,我们给他塞进去什么,他就要执行什么,这样不仅解决了要主线程不死,又能一直做事的要求了嘛。就是这么个理,下面看Google是怎么写的。


前面我们讲了进程进程里面不止有主线程,还有一个Looper,一个MessageQueue。其实Looper类里面个loop();主线程要的执行的while循环就写在loop()里。主线程的run()里只要调用Looper.loop(),就一直在这个loop()方法里走不出来了,一直在while循环里。而MessageQueue就是一个信箱,MessageQueue这个对象里有一个队列,队列里放的就是Message对象。(对这个机制不理解的可以看我前面有一篇写的关于Handler的博客),每个Message类里定义的有一个Runnable的属性,用来放代码段的。


loop()里的每次循环就是到MessageQueue的Message队列里取一个Message对象,如果这个Message对象的Runnable属性不为null,就执行Runnable.run()里面的代码。就是这样咯。主线程的执行就是在Looper.loop()里面,循环的每一次都是去MessageQueue里面取一个Message,执行Message.Runnable.run()里面的代码。\

这个讲完了再说说Message从哪里来的问题。这个Message是由FrameWork放到MessageQueue里面的。再从进程创建开始讲,主线程,MessageQueue和Looper都有了,主线程执行到loop()里一直打转转,MessageQueue还是空的没有消息给它处理,然后根据上一篇说的由FrameWork框架的AMS(ActivityManagerService)来new出Activity对象,具体new出的是哪个Activity的实例,是根据Manifest文件里标明的那个启动的Activity。然后FrameWork给这个App的进程发出一个Message,放到MessageQueue里面,这个Message.runnable.run()里面的代码就是Activity.onCreate();


这个Activity的引用是刚new出来的那个作为启动的myActivity(假设在Manifest里面写明的第一个启动的Activity是myActivity)。它的onCreate()方法是我们已经重写了,主线程这个时候就执行到我们写在myActivity的onCreate()中的代码咯。


上面已经解释了怎么从App启动执行到我们写在myActivity.onCreate()中代码。现在再申明一个事情,myActivity的生命周期都不是由它自己控制的,而是由框架控制的。执行顺序并不是简单的执行完onCreate()直接去执行onResume()的。onResume也是框架来通过传Message来让主线程执行的。一般情况下一on开头的函数都是主线程来执行的。比如onCreate(),onResume()。。。再简单说下从onCreate()怎样执行到onResume()的。\


我们在myActivity.onCreate()里面有一行,setContentView(View),这行是要我们把自己写的布局传进去。无论是布局id还是直接一个view都是一样的,不做过多解释。(setContentView时究竟做了什么事,可以参见我的Activity的UI结构的那篇博客)我们知道有个View叫ContentView,我们把自己写的布局交给它,让他去显示。


由setContentView这个方法我们可以明显看出这里我们是调用基类的Activity的setContentView(),而Activity这个基类是框架定义的(参见上篇Acticity是EIT中的E&I由框架定义)。也就是说myActivity.onCreate()告诉框架我要setContentView(),然后框架把我们写的布局投射到屏幕上。这个调框架把布局投射到屏幕的动作,交由框架执行,框架中执行这些动作,到一个合适的时间,框架再发出Message,告诉主线程,现在是显示界面的时候了。然后主线程循环走到取Message,取出来发现框架让他执行myActivity.onResume(),他再去执行myActivity.onResume(),就这样框架决定了什么时候发出执行onResume的动作,主线程才去执行。这就保证了框架的主导权和控制权。由此我们也可以看出App执行的过程中,框架是全程参与的,而且处于主导地位,所以我在上篇说我们写的App只是一个套件组。至于怎么从onResume()再执行到其他的方法,和这个基本一样,不过多叙述。


由上面的分析我们可以看出,其实myActicity中的onCreate()和onResume等并不是真正的myActivity在这个时候创建和显示,这只是框架给App开发者留的接口,让App开发者去处理一些时机要做什么样的处理。其实像点击事件的响应也大致是这么一个流程,后面讲UI的时候再详细描述(其实点击事件就是一个订阅者模式,点击事件是由框架捕获交由主线程去处理的)。到此应该对Android整个App的启动有个基本的认知了吧。


Android 中的动画有哪几类,它们的特点和区别是什么



视图动画,或者说补间动画。只是视觉上的一个效果,实际view属性没有变化,性能好,但是支持方式少。


属性动画,通过变化属性来达到动画的效果,性能略差,支持点击等事件。android 3.0

帧动画,通过drawable一帧帧画出来。


Gif动画,原理同上,canvas画出来。


如何修改 Activity 进入和退出动画



overridePendingTransition


SurfaceView和View的区别



View在UI线程去更新自己;

SurfaceView则在一个子线程中去更新自己

SurfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面在UI的主线程中更新动画,时间一旦太长就会出现问题


SurfaceView在新的线程中更新画面所以不会阻塞你的UI主线程,但是涉及到线程同步,需要SurfaceView中 thread处理.

SurfaceView(表面)优点:

可以在另一个线程中更新界面

不会阻碍界面的交互


View和SurfaceView的区别



基于View的绘图效率不高,主要用于动画变化较少的程序

SurfaceView 绘图效率较高,用于界面更新频繁的程序,如相机预览。

SurfaceView 可以在另一个线程中更新界面。


四、SurfaceView 使用方式:


1.布局中放入SurfaceView

2.实现SurfaceHolder.Callback

3.绘制画布更新画布到SurfaceView(本例是在主线程中更新,可以另起一个线程更新)


通过lockCanvas()将返回绘制的canvas

绘制的过程中,对canvas的绘制不会立刻反应在界面上,直到执行unlockCanvasAndPost()提交刚才修改的界面

相关文章
|
9月前
|
Android开发 开发者
Android利用SVG实现动画效果
本文介绍了如何在Android中利用SVG实现动画效果。首先通过定义`pathData`参数(如M、L、Z等)绘制一个简单的三角形SVG图形,然后借助`objectAnimator`实现动态的线条绘制动画。文章详细讲解了从配置`build.gradle`支持VectorDrawable,到创建动画文件、关联SVG与动画,最后在Activity中启动动画的完整流程。此外,还提供了SVG绘制原理及工具推荐,帮助开发者更好地理解和应用SVG动画技术。
418 30
|
9月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
602 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
10月前
|
机器学习/深度学习 存储 算法
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
反向传播算法虽是深度学习基石,但面临内存消耗大和并行扩展受限的问题。近期,牛津大学等机构提出NoProp方法,通过扩散模型概念,将训练重塑为分层去噪任务,无需全局前向或反向传播。NoProp包含三种变体(DT、CT、FM),具备低内存占用与高效训练优势,在CIFAR-10等数据集上达到与传统方法相当的性能。其层间解耦特性支持分布式并行训练,为无梯度深度学习提供了新方向。
493 1
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
|
9月前
|
API Android开发 开发者
Android颜色渐变动画效果的实现
本文介绍了在Android中实现颜色渐变动画效果的方法,重点讲解了插值器(TypeEvaluator)的使用与自定义。通过Android自带的颜色插值器ArgbEvaluator,可以轻松实现背景色的渐变动画。文章详细分析了ArgbEvaluator的核心代码,并演示了如何利用Color.colorToHSV和Color.HSVToColor方法自定义颜色插值器MyColorEvaluator。最后提供了完整的源码示例,包括ColorGradient视图类和MyColorEvaluator类,帮助开发者更好地理解和应用颜色渐变动画技术。
299 3
|
9月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
289 0
|
9月前
|
Android开发 开发者
Android SVG动画详细例子
本文详细讲解了在Android中利用SVG实现动画效果的方法,通过具体例子帮助开发者更好地理解和应用SVG动画。文章首先展示了动画的实现效果,接着回顾了之前的文章链接及常见问题(如属性名大小写错误)。核心内容包括:1) 使用阿里图库获取SVG图形;2) 借助工具将SVG转换为VectorDrawable;3) 为每个路径添加动画绑定属性;4) 创建动画文件并关联SVG;5) 在ImageView中引用动画文件;6) 在Activity中启动动画。文末还提供了完整的代码示例和源码下载链接,方便读者实践操作。
444 65
|
9月前
|
XML Java Maven
Android线条等待动画JMWorkProgress(可添加依赖直接使用)
这是一篇关于Android线条等待动画JMWorkProgress的教程文章,作者计蒙将其代码开源至GitHub,提升可读性。文章介绍了如何通过添加依赖库使用该动画,并详细讲解了XML与Java中的配置方法,包括改变线条颜色、宽度、添加文字等自定义属性。项目已支持直接依赖集成(`implementation 'com.github.Yufseven:JMWorkProgress:v1.0'`),开发者可以快速上手实现炫酷的等待动画效果。文末附有GitHub项目地址,欢迎访问并点赞支持!
277 26
|
9月前
|
XML Android开发 数据格式
Android中SlidingDrawer利用透明动画提示效果
本文介绍了在Android中使用`SlidingDrawer`实现带有透明动画提示效果的方法。通过XML布局配置`SlidingDrawer`的把手(handle)和内容(content),结合Activity中的代码实现动态动画效果。最终实现了交互性强、视觉效果良好的滑动抽屉功能。
131 1
Android中SlidingDrawer利用透明动画提示效果
|
算法 JavaScript 前端开发
新生代和老生代内存划分的原理是什么?
【10月更文挑战第29天】新生代和老生代内存划分是JavaScript引擎为了更高效地管理内存、提高垃圾回收效率而采用的一种重要策略,它充分考虑了不同类型对象的生命周期和内存使用特点,通过不同的垃圾回收算法和晋升机制,实现了对内存的有效管理和优化。
|
9月前
|
XML Java Android开发
Android 动画之帧动画 + 补间动画 + 属性动画
本文介绍了Android开发中的三种动画类型:帧动画、补间动画和属性动画。帧动画通过依次播放一系列静态图片实现动态效果,支持Java代码与XML两种实现方式。补间动画基于起始和结束位置自动生成过渡效果,涵盖透明度、位移、旋转、缩放及组合动画等多种形式,并可搭配插值器优化动画过程。属性动画则通过改变对象属性实现动画,支持透明度、位移、旋转、缩放及组合动画,灵活性更高且适用于更复杂的场景。文中提供了详细的代码示例,帮助开发者快速上手。
473 15