Android高级之十二讲之内存、电量、卡顿、流量

简介: 本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 安卓应用的内存往往是有限的,从开始的8M到16M,24M,32M,48M,64M等逐步变大,但内存的变大是由于分辨率的提高导致,并不意味着内存的可使用量随之增加,而不及时回收(即使Java有自己的垃圾回收机制),容易造成内存过高,引起手机变卡,体验流畅性下降)。


本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!


安卓应用的内存往往是有限的,从开始的8M到16M,24M,32M,48M,64M等逐步变大,但内存的变大是由于分辨率的提高导致,并不意味着内存的可使用量随之增加,而不及时回收(即使Java有自己的垃圾回收机制),容易造成内存过高,引起手机变卡,体验流畅性下降)。

降低应用内存消耗的办法有以下几种常见办法:

1、图片声明使用的context使用Application,回收时清除ImageView的drawable

但是如果使用context.startActivity会报一个错

 android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

因此如果确定用application启动activity,要注意加个FLAG_ACTIVITY_NEW_TASK这个flag

同时ProgressDialog的生成也不能用application,因为它依赖着当前页面

2、使用viewStub占位,避免经常使用gone方法,减少对象的加载和初始化

3、使用merge把能合并的布局统统合并,在hierachyviewer里面可以看到布局的复杂度

如果使用include,给布局加margin的话,需要同时设置include标签的宽高

4、去掉decorView和window的背景,往往由于应用有自身的色调搭配

5、通过canvas的clip方法,避免在看不到的地方画图,通过quickReject方法来在确定的区域比如矩形内绘制,

跳过非既定区域内绘制

6、使用9path文件和自定义图片,以及透明背景,来防止过度绘制

7、列表可以给定一个高度(根据item的高度来动态设置),来防止重复计算高度和执行布局方法

8、合理选择组件,选择简单的而非复杂的组件(原因,如果你自定义过复杂组件自己就会明白)

9、开启新进程作为服务进程和工具进程-最大招,有效降低当前应用的内存消耗

10、避免在onDraw频繁调用。

11、 在动画结束或onPause方法里,清除控制的动画效果:mImageView.clearAnimation()


避免内存泄露的几个办法:

1、及时清除对象或回调引用的context(或使用Application),降低引用链长度

    /**
     * 清除页面的ImageView的引用链
     * @param view
     */
    public static void unbindDrawables(View view) {
        if (view.getBackground() != null) {
            view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
            ((ViewGroup) view).removeAllViews();
        }
    }


2、Bitmap用前根据屏幕dpi或自定义要求进行压缩,过后及时回收;使用inBitmap复制前面图片的内存,使整个屏幕

只展示当前页面图片所占的内存。

使用inBitmap需要注意几个限制条件:

  • 在SDK 11 -> 18之间,重用的bitmap大小必须是一致的,例如给inBitmap赋值的图片大小为100-100,那么新申请的bitmap必须也为100-100才能够被重用。从SDK 19开始,新申请的bitmap大小必须小于或者等于已经赋值过的bitmap大小。
  • 新申请的bitmap与旧的bitmap必须有相同的解码格式,例如大家都是8888的,如果前面的bitmap是8888,那么就不能支持4444与565格式的bitmap了。 我们可以创建一个包含多种典型可重用bitmap的对象池,这样后续的bitmap创建都能够找到合适的“模板”去进行重用。如下图所示:

android_perf_2_inbitmap_pool

另外提一点:在2.x的系统上,尽管bitmap是分配在native层,但是还是无法避免被计算到OOM的引用计数器里面。这里提示一下,不少应用会通过反射BitmapFactory.Options里面的inNativeAlloc来达到扩大使用内存的目的,但是如果大家都这么做,对系统整体会造成一定的负面影响,建议谨慎采纳。


3、Cursor对象及时关闭,避免对数据库对象的长期引用

4、关键地方做空判断,页面关闭时及时回收对象

5、context尽量使用application,避免页面关闭时,由于引用存在而不能及时回收对象,尤其getResource功能,

在fragment中特别容易引起泄露,出现not attach的问题

6、避免在for循环中声明对象(一下子无数个对象产生,内存暴增),引用能写在外面最好,如array.length,直接用

int size获取值,再遍历

7、打开开发者模式中的CPU绘制选项,根据屏幕显示的红黄蓝来辨别页面的绘制情况

8、handler(等内部类)往往引用context,使用弱引用的方式处理

    public WeakHandler handler = new WeakHandler(this);

    public class WeakHandler extends Handler {
        WeakReference mContextWeakReference;

        public WeakHandler(Context context) {
            mContextWeakReference = new WeakReference(context);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mContextWeakReference.get() == null || msg == null) {
                return;
            }
            boolean handled = !handleMessageDelegate(msg.what, msg.obj);
            if (handled) {
                if (msg.what < 0) {
                    handleErrorMessage(msg);
                } else {
                    handlePtrMessage(msg);
                }
            }
        }
    }

9、一般webView也会有内存泄露的问题出现,往往由于引用未删除,自身的view仍然存在,在进程一系列操作后,仍可以使用开启新进程来降低应用内存(通过Aidl进行通信。)

    /**
     * 优化内存最后一招-开启新进程
     */
    @Override
    protected void onDestroy() {
        if (mWebView != null) {// remove webView, prevent chromium to crash
            ViewParent parent = mWebView.getParent();
            if (parent != null) {
                ((ViewGroup) parent).removeView(mWebView);
            }
            // 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
            mWebView.getSettings().setJavaScriptEnabled(false);
            // 解决Receiver not registered:
            // android.widget.ZoomButtonsController
            mWebView.setVisibility(View.GONE);
            mWebView.removeAllViews();
            mWebView.clearCache(false);
            mWebView.stopLoading();
            mWebView.destroy();
            mWebView = null;
            setConfigCallback(null);
        }
        super.onDestroy();
    }

    /**
     * 删除引用
     * @param windowManager
     */
    public void setConfigCallback(WindowManager windowManager) {
        try {
            Field field = WebView.class.getDeclaredField("mWebViewCore");
            field = field.getType().getDeclaredField("mBrowserFrame");
            field = field.getType().getDeclaredField("sConfigCallback");
            field.setAccessible(true);
            Object configCallback = field.get(null);
            if (null == configCallback) {
                return;
            }
            field = field.getType().getDeclaredField("mWindowManager");
            field.setAccessible(true);
            field.set(configCallback, windowManager);
        } catch(Exception e) {
        }
    }

10、静态匿名内部类相比内部类来说,后者会直接引用父类,而前者不会,因此前者不会引起内存泄露后者则会。

11、注册的组件要在生命周期结束时要注销掉。



检查内存泄露的工具有:Lint(inspect code-performance)、Mat(case gc-分析hprof文件)、LeakMemory(Log日志弹窗)、As自带(Monitor-Dump Java Heap),更多介绍

图片更多:Android ImageView设置图片原理(下)


电量:

1、一般情况下耗电可能是死循环引起的,不断的请求,不断的失败,又不断的重试,总之业务引起的占多数。

2、其次系统加入低电耗的模式,如果你的应用不断唤醒cpu,执行一些耗时操作,那自然电量消耗过多

3、接口和产品设计不合理,一般情况下能一个接口返回的数据不要两个,请求数据包的封装也要占一大部分流量,另外产品的YY需求,而非用户真实需求,往往会造成实现的复杂度。

4、同步数据尽量在用户充电时或电量较多时


流量:

1、同步数据尽量在wifi下

2、接口能合一则合,产品设计简单极致

3、做好本地数据缓存,以及和服务端的同步机制;例如get请求和cache-control

4、webview做好本地缓存,加载时优先加载本地资源,当然也需要服务端支持

修改http服务器中的配置,使其支持text/cache-manifest,我使用的是apache服务器,是windows版本的,在apache的conf文件夹中找到mime.types文件,打开后在文件的最后加上“text/cache-manifest   mf  manifest”,重启服务器

5、压缩H5的图片大小,以及改变图片格式为webp,或者把背景图改为jpg,将纯色图用xml来写。

关于流量再讲下IOS吧,一般应用安装后都会开启后台刷新功能,导致流量耗用的特别快,开着移动流量三四天一百兆一点也不夸张(应用安装上百个),在设置-通用-后台应用刷新,关掉后台刷新,只把微信打开就够了。


卡顿:

1、ANR的出现在于在UI线程操作过久(Activity5s,BroadReceiver10s),则耗时操作尽量放在子线程处理,完毕后通知主线程

2、页面重绘多次,划定绘画区域如canvas.clipRect;控制的宽高不定多次计算,可以设置定值

3、页面复杂度过高,产品或自己的原因,内存不注意回收

4、点击后的背景尽量用透明,减少图片绘制的复杂度

5、避免onDraw频繁调用


使用leakCanary来监控泄露,并上传

https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/

https://github.com/square/leakcanary

使用ProGuard做apk压缩

https://developer.android.com/studio/build/shrink-code.html

其他工具:MAT、Emmagee


页面渲染时,被绘制的元素最终要转换成矩阵像素点(即多维数组形式,类似安卓中的Bitmap),才能被显示器显示。

硬件加速的主要原理,就是通过底层软件代码,将CPU不擅长的图形计算转换成GPU专用指令,由GPU完成。


目录
相关文章
|
6月前
|
数据采集 JSON 网络安全
移动端数据抓取:Android App的TLS流量解密方案
本文介绍了一种通过TLS流量解密技术抓取知乎App热榜数据的方法。利用Charles Proxy解密HTTPS流量,分析App与服务器通信内容;结合Python Requests库模拟请求,配置特定请求头以绕过反爬机制。同时使用代理IP隐藏真实IP地址,确保抓取稳定。最终成功提取热榜标题、内容简介、链接等信息,为分析热点话题和用户趋势提供数据支持。此方法也可应用于其他Android App的数据采集,但需注意选择可靠的代理服务。
260 11
移动端数据抓取:Android App的TLS流量解密方案
|
5月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
204 1
|
存储 前端开发 Java
Android MVVM架构模式下如何避免内存泄漏
Android采用MVVM架构开发项目,如何避免内存泄漏风险?怎样避免内存泄漏?
322 1
|
11月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
422 16
|
10月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
11月前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
335 31
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
877 4
Android性能测试——发现和定位内存泄露和卡顿
|
编解码 Android开发 UED
构建高效Android应用:从内存优化到用户体验
【10月更文挑战第11天】本文探讨了如何通过内存优化和用户体验改进来构建高效的Android应用。介绍了使用弱引用来减少内存占用、懒加载资源以降低启动时内存消耗、利用Kotlin协程进行异步处理以保持UI流畅,以及采用响应式设计适配不同屏幕尺寸等具体技术手段。
175 2