App优化

1介绍

App经过优化后好处多多。优化会使app加载快、打开快、响应快、占内存变小、省电等等等。

2 分析工具

1)Memory Monitor(后改名Profiler)

Memory Monitor(Profiler)是Android studio自带的一个内存监视工具,他可以很好的帮助我们进行内存实时分析。通过点击as下方的Memory Monitor(Profiler)标签**(或者View->Tool Windows->Profiler)**,打开工具:较浅蓝色代表free的内存、深色代表使用的内存用内从变换的走势图变换,可以判断关于内存的使用状态,例如当内存持续增高时,可能发生内存泄漏;当内存突然减少时,可能发生GC等。

2)Memory Analyzer

MAT是一个快速,功能丰富的Java Heap分析工具,通过分析Java进程的内存快照HPROF分析,从众多的对象中分析,快速计算出在内存中对象占用的大小,查看哪些对象不能被卡及收集器回收,并可以通过试图直观的查看可能造成这种结果的对象。

3)LeakCanary

LeakCanary是一个内存检测工具。github文档

4)Android Lint

Android Lint是安装继承的一个代码提示工具,它可以给布局、代码提供非常强大的帮助。比如在布局文件中写了三层冗余的LinearLayout布局就会在编辑器右边看到提示。
使用:

  1. 工具栏 -> Analyze -> Inspect Code
  2. 弹出窗的Custom scope可以选择对哪一指定部分进行扫描,whole project是整个项目。

含义:

  • Accessibility(便利性)
  • Correctness (正确性)
  • Internationalization(国际化或标准化)
  • Performance(性能)
  • Security(安全)
  • Usability(复用/适用)
  • issues(争议)
  • Imports(类中导入没有用到的资源。点击目录右键,选择Optimize Imports就能快速把整个项目多余的Imports给删除)
  • Declaration redundancy(声明冗余)
  • Spelling(拼写)
  • probable bugs(可能出现BUG的地方)
  • error(错误)
  • blocker(阻碍)

5)other

如腾讯的perfdog、阿里的mobileperf等等。

3优化方式

3.1布局优化

3.1.1介绍

布局优化就是减少界面的卡顿、提高流畅度,造成界面卡顿的最重要的原因就是丢帧。

丢帧:比如现在很多手机都是60帧,在一秒中画面需要更新60帧,但是如果着一秒钟只更新了50帧,那么就是丢帧,在人的感觉当中就是卡顿。引起丢真的原因非常多,有硬件层面,有软件层面,也有App自身的问题。

3.1.1.2性能问题
1App主线程执行时间长。
  1. Measure \ Layout 耗时\超时 (或者没有调度到)
  2. Draw 耗时
  3. Animation回调耗时
  4. View 初始化耗时 (PlayStore)
  5. List Item 初始化耗时(WeChat)
  6. decodeBitmap 耗时 (或者没有调度到)
2uploadBitmap 耗时

这里的 uploadBitmap 主要是 upload bitmap to gpu 的操作 , 如果 bitmap 过大 , 或者每一帧内容都在变化 , 那么就需要频繁 upload , 导致渲染线程耗时.

3BuildDrawingCache 耗时

应用本身频繁调用 buildDrawingCache 会导致主线程执行耗时从而导致卡顿 , 从下图来看, 主线程每一帧明显超过了 Vsync 周期
微信对话框有多个动态表情的时候, 也会出现这种情况导致的卡顿

4使用 CPU 渲染而不是 GPU 渲染

如果应用在 Activity 中设置了软件渲染, 那么就不会走 hwui , 直接走 skia, 纯 cpu 进程渲染, 由于这么做会加重 UI Thread 的负载, 所以大部分情况下这种写法都会导致卡顿

5主线程 Binder 耗时

Activity resume 的时候, 与 AMS 通信要持有 AMS 锁, 这时候如果碰到后台比较繁忙的时候, 等锁操作就会比较耗时, 导致部分场景因为这个卡顿, 比如多任务手势操作

6游戏 SurfaceView 内容绘制不均匀

这一项指的是游戏自身的绘制问题, 会导致总是不能满帧去跑, 如下图, 红框部分是SurfaceFlinger 显示掉帧, 原因是底下的游戏在绘制的时候, 刚好这一帧超过了 Vsync SF 的信号.这种一般是游戏自身的问题

7WebView 性能不足

应用里面涉及到 WebView 的时候, 如果页面比较复杂, WebView 的性能就会比较差, 从而造成卡顿

8帧率与刷新率不匹配

如果屏幕帧率和系统的 fps 不相符 , 那么有可能会导致画面不是那么顺畅. 比如使用 90 Hz 的屏幕搭配 60 fps 的动画

9应用性能跟不上高帧率屏幕和系统

部分应用由于设计比较复杂, 每一帧绘制的耗时都比较长 , 这么做的话在 60 fps 的机器上可能没有问题 , 但是在 90 fps 的机器上就会很卡, 因为从 60 -> 90 , 每帧留给应用的绘制时间从 16.6 ms 变成了 11.1 ms , 如果没有在 11.1 ms 内完成, 就会出现掉帧的情况.

10主线程 IO 操作

主线程操作数据库
使用 SharedPerforence 的 Commit 而不是 Apply

11WebView 与主线程交互

与 WebView 进行交互的时候, 如果 WebView 出现问题, 那么也会出现卡顿

12RenderThread 耗时

RenderThread 自身比较耗时, 导致一帧的时长超过 Vsync 间隔
渲染线程耗时过长阻塞了主线程的下一次 sync

13多个 RenderThread 同步导致主线程卡顿

有的 App 会产生多个 RenderThread ,在某些场景下 RenderThread 在 sync 的时候花费比较多的时间,导致主线程卡顿

2.1.3解决方法

  1. 使用ConstraintLayout(谷歌默认根布局)或RelativeLayout来代替多层LineraLayout嵌套(避免overdraw)
  2. Google Api文档中建议View树的高度不大于10(减少view树的层数,较少渲染布局压力)
  3. 使用<include>标签重用layout(布局复用)
  4. 使用<viewstub>延时加载(提高显示速度)
  5. 使用<merge>标签替换父布局(merge用于删除不必要的布局,即可用来减少层级)
  6. 使用<SurfaceView>实现布局变化较快的界面。
  7. 注意使用warp_context(会增加measure计算成本)
  8. 删除控件中无用的属性

2.2内存优化

2.1.1介绍

Android手机对于每个APP可用的内存是有一定限制的,同时每部手机的运行内存也是不一样的,所以当有的手机出现内存泄漏的时候会产生OOM导致APP崩溃。

内存优化原因:
  1. app运行内存限制,OOM导致APP崩溃。
  2. APP性能:流畅性、响应速度和用户体验

2.1.2查看APP内存方法和工具

1通过getSystemService

我们就要传入ACTIVITY_SERVICE这个参数,这样我们就可以通过ActivityManager中的getMemoryClass方法获取到该APP在该部手机上能获取到的最大的内存空间,单位是M,或者可以通过getLargeMemoryClass方法获取到设置了最大堆的应用的能获得到的最大的内存空间。但是这两个获取到的值一般都是相同的,因为一般的应用都不支持最大堆的申明,而且也不这么去做。

StringBuilder str = new StringBuilder();
ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
int memClass = activityManager.getMemoryClass();//以m为单位
int LargememClass = activityManager.getLargeMemoryClass();//以m为单位
str.append("memClass:"+memClass+"\n");
str.append("LargememClass:"+LargememClass+"\n");
mTv.setText(str.toString());//最大内存数。(M为单位)

生命最大堆:在清单文件中application标签下定义

android:largeHeap="true"
2Android studio

通过Android Studio的Android Profiler来动态的查看我们APP的内存使用情况

2.1.3优化方法

1)数据结构优化
  1. 频繁使用字符串拼接用StringBuilder(String使用+拼接会产生中间字符串,耗时,内存浪费)
  2. ArrayMap、SparseArray替换HashMap(内存使用更少,并且在数据量大的时候效率会比较高,HashMap的一个entry需要额外占用32B)
  3. 防止出现内存抖动(就是在短时间之内申请了很多空间,但是使用一下子就不用了,之后过了一会以后又申请很多的空间,类似的反复下去,这样就会当空间不足的时候,不断的让GC被调用,导致APP卡顿)
  4. 防止添加多余的class(再小的Class都耗费0.5KB)
  5. Bitmap使用结束后需要手动回收,通过调用其recycle方法来进行回收(Bitmap是最容易造成内存泄漏的)
  6. 使用静态方法,静态方法的速度比普通方法快15%(工具类或者常量表可使用静态方法)
  7. 减少成员变量,使用局部变量替换掉只使用过一次的成员变量
  8. 尽量不要使用枚举类和迭代器(枚举类占用内存远大于常量表)
  9. 对于部分需要回收的类,使用后一定要关闭、回收或者解除注册,例如Cursor、Receiver、Sensor、File、IO等对象
  10. 避免使用IOC框架,大量使用反射依然会造成性能下降,内存消耗较大
  11. 使用RenderScript、OpenGL来进行非常复杂的绘图操作
  12. 尽量使用Holder对视图进行缓存,而不是重复执行inflate方法解析视图
  13. 除非必要尽量少使用Activity的context,实用Application的Context替代,避免Activity被其他类持有造成无法回收从而导致内存泄漏
  14. 静态类中应该避免持有Activity的context,导致context无法回收
  15. Task及其子类(TimerTask,AsyncTask等)无论是否用于循环,都需要在执行结束后或者Activity生命周期结束后被Cancle掉,否则会造成内存泄漏
  16. 动画在Activity生命周期结束后也需要cancle
  17. WebViwe在加载网页后会长期占有内存,需要在Activity生命周期结束后调用其destroy方法来进行销毁
  18. 线程在执行结束后需要对其进行关闭,且线程数量不易过多,必要时通过线程池来管理线程
  19. 通过Activity的Recreate方法来重启Activity时应该先移除之前的Fragment避免创建重复的Fragment导致内存泄漏
  20. 使用较少的工具类尽量使用单例模式,少用static类,以减少不必要的类加载
  21. 在AndroidMainifest中为主Activity加上clearTaskOnLaunch标签,这样一旦返回到主Activity时就销毁其他所有Activity,避免内存泄漏
  22. 对于一些不必要长期持有的类,我们可以通过弱引用和软引用来减少内存占用
  23. 避免在主线程中使用Thead.sleep方法来休眠,这样会造成页面卡顿
  24. 耗内存操作应该放在新进程,避免oom超内存异常
  25. 使用WakeLock时一定要及时释放锁,因为如果未释放锁导致屏幕常亮会非常耗电,像视频类APP我们需要在暂停时就释放掉锁,而不是等到停止播放或销毁Activity时才释放锁
  26. AlarmManager使用闹钟唤醒也很耗电,在不使用时应该马上关闭,两次唤醒间隔不应太短
2)对象复用
  1. 复用系统中自带的资源
  2. ListView/GridView的ConvertView复用
  3. 避免在onDraw方法里面执行对象的创建(因为onDraw在界面,图像或者View一有变化的化就会重新调用,如果在里面执行对象的创建的话,就会影响绘制的时间)
3)内存泄漏

内存泄漏:由于代码的瑕疵,导致这块内存虽然是停止不用的,但是依然还是被其他东西引用着,使得GC没法对它进行回收。

  1. 内存泄漏会导致剩余可以使用的Heap(堆)越来越少,以至于频繁的触发GC。
  2. 尤其是Activity泄漏。
  3. 上下文对象最好是使用Application Context而不是Activity Context,因为context会经常被调用,假如我们使用了Activity Context,就导致了GC认为Activity的引用还是在的,所以不会进行回收,但是其实那时候Activity已经销毁了。
  4. 注意Cursor(指针)对象是否及时关闭
4)OOM

OOM:内存溢出
OOM的必然性:Android手机对于每个APP可用的内存是有一定限制的。
OOM的可解决性:Android手机的生产厂家对于手机内存的设置是有过考量的,一般来说只要是有对内存的优化是不会出现OOM问题的。
OOM问题绝大部分发生在图片上。
1)强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。
如下:

Object o=new Object();   //  强引用

当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。如果不使用时,要通过如下方式来弱化引用,如下:

o=null;     // 帮助垃圾收集器回收此对象

显式地设置o为null,或超出对象的生命周期范围,则gc认为该对象不存在引用,这时就可以回收这个对象。具体什么时候收集这要取决于gc的算法。
举例:

public void test(){
    Object o=new Object();
    // 省略其他操作
}

在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object会被回收。
但是如果这个o是全局的变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。
强引用在实际中有非常重要的用处,举个ArrayList的实现源代码:

private transient Object[] elementData;
public void clear() {
	modCount++;
	// Let gc do its work
	for (int i = 0; i < size; i++){
		elementData[i] = null;
	}
	size = 0;
}

在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。
2)软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

String str=new String("abc");                                     // 强引用
SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用

软引用在实际中有重要的应用,例如浏览器的后退按钮。按后退时,这个后退时显示的网页内容是重新进行请求还是从缓存中取出呢?这就要看具体的实现策略了。
(1)如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建
(2)如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出

这时候就可以使用软引用

Browser prev = new Browser();               // 获取页面进行浏览
SoftReference sr = new SoftReference(prev); // 浏览完毕后置为软引用    
if(sr.get()!=null){ 
	rev = (Browser) sr.get();           // 还没有被回收器回收,直接获取
}else{
	prev = new Browser();               // 由于内存吃紧,所以对软引用的对象回收了
	sr = new SoftReference(prev);       // 重新构建
}

这样就很好的解决了实际的问题。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
其实对应的还有弱引用和虚引用,这个对于内存的优化没有什么用处就不在这里说了。
优化OOM

  1. 注意临时Bitmap对象的及时回收
  2. 避免Bitmap的浪费
  3. Try catch某些大内存的分配的操作
  4. 加载Bitmap:缩放比例、解码格式、局部加载
    我们其实可以发现上面这几点大部分和Bitmap图片操作有关系,接下来我们来说下怎么进行图片压缩,主要有三种方法一是把图片缩小,二是把图片的每个像素压缩(一个像素由4个字节压缩到2个字节),最后一种就是显示部分完整图片。

1)缩小图片

private void changePicOpti() {
    if (file == null) {//file图片文件
        return;
    }
    try {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;//只获得文件的宽和高
        BitmapFactory.decodeStream(new FileInputStream(file), null, o);
        int width_tmp = o.outWidth;
        int height_tmp = o.outHeight;
        int scale = 2;
        while (true) {
            if (width_tmp / scale < SCREEN_WIDTH && height_tmp / scale < SCREEN_HEIGHT) {//SCREEN_WIDTH屏幕宽度,SCREEN_HEIGHT屏幕宽度
                break;
            }
            scale += 2;
        }
        scale /= 2;//inSampleSize=1会将原始图片放大2倍
        o.inJustDecodeBounds = false;
        o.inSampleSize = scale;
        FileInputStream fin = new FileInputStream(file);
        Bitmap bitmap = BitmapFactory.decodeStream(fin, null, o);
        img.setImageBitmap(bitmap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2)压缩像素

private void changeRGB() {
    if (file == null) {//file图片文件
        return;
    }
    try {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inPreferredConfig = Bitmap.Config.RGB_565;
        FileInputStream fin = new FileInputStream(file);
        Bitmap bitmap = BitmapFactory.decodeStream(fin, null, o);
        img.setImageBitmap(bitmap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3)显示部分高清图片

private void partLoad() {
    if (file == null) {//file图片文件
        return;
    }
    try {
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;//只获得文件的宽和高
        FileInputStream fin = new FileInputStream(file);
        BitmapFactory.decodeStream(fin, null, o);
        int width_tmp = o.outWidth;
        int height_tmp = o.outHeight;
        fin = new FileInputStream(file);
        BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(fin, false);
        BitmapFactory.Options options = new BitmapFactory.Options();
        //SCREEN_WIDTH屏幕宽度,SCREEN_HEIGHT屏幕宽度,nextPx垂直方向变动的,nextPy水平方向的变动,默认中心点
        int x = width_tmp / 2 - SCREEN_WIDTH / 2 + nextPx;
        int y = height_tmp / 2 - SCREEN_HEIGHT / 2 + nextPy;
        //保证在图片范围以内
        if (x < 0) {
            x = 0;
        } else if (x > width_tmp - SCREEN_WIDTH) {
            x = width_tmp - SCREEN_WIDTH;
        }
        if (y < 0) {
            y = 0;
        } else if (y > height_tmp - SCREEN_HEIGHT) {
            y = height_tmp - SCREEN_HEIGHT;
        }
        Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(x, y, x + SCREEN_WIDTH, y + SCREEN_HEIGHT), options);
        img.setImageBitmap(bitmap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2.3 启动优化

2.3.1 应用启动介绍

2.3.1.1 流程

启动流程
应用启动过程中,最重要的两个进程就是 SystemServer 和 App Process . 其职责划分如下:

  1. SystemServer 负责应用的启动流程调度、进程的创建和管理、窗口的创建和管理(StartingWindow 和 AppWindow) 等
  2. 应用进程被 SystemServer 创建后,进行一系列的进程初始化、组件初始化(Activity、Service、ContentProvider、Broadcast)、主界面的构建、内容填充等
2.3.1.2 启动方式
  1. 冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,然后再根据启动的参数,启动对应的进程组件,这个启动方式就是冷启动
  2. 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台),所以在已有进程的情况下,这种启动会从已有的进程中来启动对应的进程组件,这个方式叫热启动

2.3.2 优化

1 将Application中的一些初始化服务的方法写入IntentService
public class StartIntentService extends IntentService {
    private static final String ACTION_INIT_WHEN_APP_CREATE = "SERVICE_ACTION_INIT";
    public StartIntentService() {
        super("StartIntentService");
    }
    public static void start(Context context) {
        Intent intent = new Intent(context, StartIntentService.class);
        intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
        context.startService(intent);
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
            	//初始化
                init();
            }
        }
    }

Application中的onCreate添加:InitializeService.start(this);

2 添加启动屏(闪屏)

splash_layer.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 底层白色 -->
    <item android:drawable="@color/white" />
    <!-- 顶层Logo居中 -->
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_splash" />
    </item>
</layer-list>

添加一个主题:

<style name="SplashTheme" parent="AppTheme">
    <item name="android:windowBackground">@drawable/splash_layer</item>
</style>

添加一个Activity:SplashActivity。

public class LogoSplashActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startActivity(new Intent(this,MainActivity.class));
        finish();
    }
}

在AndroidManifest.xml中的application下添加

<activity
  android:name=".SplashActivity"
  android:screenOrientation="portrait"
  android:theme="@style/SplashTheme">
  <intent-filter>
      <action android:name="android.intent.action.MAIN"/>
      <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
</activity>
3 线程优化

线程优化主要是减少 CPU 调度带来的波动,让启动时间更稳定。如果启动过程中有太多的线程一起启动,会给 CPU 带来非常大的压力,尤其是比较低端的机器。过多的线程同时跑会让主线程的 Sleep 和 Runnable 状态变多, 增加了应用的启动速度,优化的过程中要注意:

  1. 控制线程数量 – 线程池
  2. 检查线程间的锁 ,防止依赖等待
  3. 使用合理的启动架构
    • 微信内部使用的 mmkernel
    • 阿里 Alpha
4 GC优化

启动过程中减少 GC 的次数

  1. 避免进行大量的字符串操作,特别是序列化和反序列化
  2. 频繁创建的对象需要考虑复用
  3. 转移到 Native 实现
5 IO优化

将一些IO操作写进子线程中

2.4 响应优化

在App使用过程中,你可能会遇到App没有响应您是否关闭它的提示。这就是ANR

2.4.1ANR介绍

ANR全名(Application Not Responding), 也就是"应用无响应". 当操作在一段时间内系统无法处理时, 系统层面会弹出上图那样的ANR对话框.

2.4.2 如何产生的ANR

在Android里, App的响应能力是由Activity Manager和Window Manager系统服务来监控的. 通常在如下两种情况下会弹出ANR对话框:

  1. 5s内无法响应用户输入事件(例如键盘输入, 触摸屏幕等)
  2. BroadcastReceiver在10s内无法结束
    造成以上两种情况的首要原因就是在主线程(UI线程)里面做了太多的阻塞耗时操作, 例如文件读写, 数据库读写, 网络查询等等

2.4.3 如何避免ANR

不要在主线程里面做繁重的操作

  1. 使用线程或线程池的方式
  2. 使用AsyncTask异步任务
  3. HandlerThread
  4. IntentService(Service是运行在主线程的, 然而IntentService是运行在子线程的.实际上IntentService就是实现了一个HandlerThread + ServiceHandler的模式.)
  5. Loader(Android 3.0引入的数据加载器, 可以在Activity/Fragment中使用. 支持异步加载数据, 并可监控数据源在数据发生变化时传递新结果. 常用的有CursorLoader, 用来加载数据库数据)

特别注意:
使用Thread和HandlerThread时, 为了使效果更好, 建议设置Thread的优先级偏低一点:

Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);

因为如果没有做任何优先级设置的话, 你创建的Thread默认和UI Thread是具有同样的优先级的, 同样的优先级的Thread, CPU调度上还是可能会阻塞掉你的UI Thread, 导致ANR的.

2.4.4那些是运行在主线程上的

  1. Activity的所有生命周期回调都是执行在主线程的
  2. Service默认是执行在主线程的
  3. BroadcastReceiver的onReceive回调是执行在主线程的
  4. 没有使用子线程的looper的Handler的handleMessage,post(Runnable)是执行在主线程的
  5. AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的
  6. View的post(Runnable)是执行在主线程的

2.5电量优化

2.5.1原因

Android应用开发中,需要考虑的情况是,如何优化电量使用,让我们的app不会因为电量消耗过高被用户排斥,或者被其他安全应用报告
对于移动设备而言,有以下几种行为会导致设备电量的消耗增加

  1. 屏幕保持开启状态,尽量设置休眠时间
  2. 蜂窝网络的频繁启动与关闭
  3. 定位频繁使用,使用完后请及时关闭

2.6网络优化

1工具

分析工具:Network Monitor
网络代理工具:Wireshark, Fiddler, Charles等

2优化

  1. 接口数据传输图片或文件,使用Gzip等压缩工具来减少数据量
  2. 适当使用缓存可以减少流量的消耗
  3. WebView使用腾讯X5WebView
  4. 有些高概率需要获取的数据可以提前获取。
  5. 当网络差的时候,可以减少图片的加载,某些特定的界面可以先反馈,再延时请求

3JobScheduler

任务调度JobScheduler,该工具继承了常见的集中运行方式,开发者只需添加少数几行代码,即可完成原来要多种组件配合的工作

相关:JobScheduler: 任务调度器、JobInfo : 任务概要信息、JobService: 任务服务,描述具体逻辑
具体介绍请看:官网文档,使用请看:官方Demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值