中软卓越java培训支招:如何提升Android性

短标题:

日期:2016-11-29 10:36

俗话说,金杯银杯不如老百姓的口碑!评估一个APP的质量如何,主要在于用户的体验,口碑好了,那就是一个优质的 APP。用户体验主要集中在页面设计的视觉效果、APP启动时间、运行速度、到达目的页的简易程度等等。今天中软卓越java培训为大家支几招,希望从技术角度来讲的这几个tips帮助你提升Android性能。


Activity 泄漏

先来看看内存泄漏是怎么发生的。 Activity 泄漏通常是内存泄漏的一种。为什么会泄漏呢?如果你持有一个未使用的 Activity 的引用,其实也就持有了 Activity 的布局,自然也就包含了所有的 View。最棘手的是持有静态引用。别忘了,Activity 和 Fragment 都有自己的生命周期。一旦持有了静态引用,Activity 和 Fragment 就不会被垃圾回收器清理掉了。这就是为什么静态引用很危险。

m_staticActivity = staticFragment.getActivity()

这样的代码太多了。

另外,泄漏 Listener 也是经常会发生的事情。比如说,有下面的代码。LeakActivity继承自Activity,有一个单例:NastyManager,当通过 addListener(this) 将 Activity 作为 Listener 和 NastyManager 绑定起来的时候,不好的事情就发生了。

public class LeakActivity extends Activity {

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    NastyManager.getInstance().addListener(this);

  }

}

想要修复这样的 bug,其实相当简单,就是在你的 Acitivity 被销毁的时候,将他和NastyManager 取消掉绑定就好了。

@Override

public void onDestroy() {

  super.onDestroy();

  NastyManager.getInstance().removeListener(this);

}

相对上面的解决方案,还有更好的。比如真的需要用到单例吗?通常,并不需要。不过某些时候可能真的很需要,得权衡和设计。不过无论如何,记住,当 Activity 销毁的时候,在单例中移除掉对 Activity 的引用。下面我们讨论下: 如果是内部类,会发生什么?比如说,我们有一个在 Activity 里有一个很简短的非静态 Handler。

尽管它看起来很短,但是只要它还存活着,那么包含它的 Activity 就会存活着。如果你不信我,在 VM 里试试看。这就是另一个内存泄漏的案例:Activity 内部的 Handler。

public class MainActivity extends Activity {

  //...

  Handler handler;

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    //...

    handler = new Handler() {

      @Override

      public void handleMessage(Message msg) {

              }

  }

}

Handler 是个很常用也很有用的类,异步,线程安全等等。如果有下面这样的代码,会发生什么呢?handler.postDeslayed ,假设 delay 时间是几个小时… 这意味着什么?意味着只要 handler 的消息还没有被处理结束,它就一直存活着,包含它的 Activity 就跟着活着。我们来想办法修复它,修复的方案是WeakReference,也就是所谓的弱引用。垃圾回收器在回收的时候,是会忽视掉弱引用的,所以包含它的 Activity 会被正常清理掉。大概代码如下:

private static class MyHandler extends Handler {

  private final WeakReference mActivity;

  // ...

  public MyHandler(MainActivity activity) {

    mActivity = new WeakReference(activity);

    //...

  }

 

  @Override

  public void handleMessage(Message msg) {

  }

  //...

}

 

概括来说:我们有个内部类,就像 Handler,内部非静态类是不能脱离所属类而单独存活的,Android 里通常是 Activity。所以,看看你的代码里的内部类,确保他们没有出现内存泄漏。

相比非静态内部类,最好使用静态内部类。区别就是静态内部类不依赖所属类,他们拥有不同的生命周期。我经常见到类似的原因引起的内存泄露。


如何避免 Activity 泄漏?

移除掉所有的静态引用,考虑用 EventBus 来解耦 Listener。记着在不需要的时候,解除 Listener 的绑定,尽量用静态内部类。做 Code Review。个人经验:Code Review 能很早的发现内存泄漏,了解你程序的结构。用类似 MAT,Eclipse Analyzer,LeakCanary 这样的工具分析内存。在 Callback 里打印 Log。


滑动

实现流畅滑动的技巧:UI 线程只用作 UI 渲染。这一条真谛能够解决 99% 的滑动卡顿问题。不要在 UI 线程做下面的事情:

载入图片

网络请求

解析 JSON

读取数据库

做这些操作是很慢的,像图片,网络,JSON考虑用现成的库,有很多社区提供的解决方案,数据库考虑下用 Loader,支持批量更新和载入。


图片

图片相关的库有很多,比如 Glide, Picasso, Fresco。你可以自己去了解下他们之间的区别,以帮助自己在特定场景下做出取舍。

 

内存

Bitmap 操作是很需要技巧的,图片一般比较大,而且系统对最大内存又有限制和要求。在我面对 4.0 之前的系统的时候,我简直要崩溃了。内存管理也很需要技巧。有的时候需要放到文件里,有的时候需要放到内存里,别忘了,我们还有一个很有用的工具:LRUCache。


网络

首先,Java 的网络请求确实是 Android 的一个阻碍。很多 Java.net 的 API 都是阻断执行的,切记不可在 UI 线程执行网络请求。在线程里执行或者直接使用第三方库吧。

异步 HTTP 其实也挺麻烦的,4.4 起 OkHttp 就成了 Android 代码的一部分了,然而… 如果你需要最新版本的 OkHttp ,可以考虑自己引入。另外有个不错的库叫: Volley,也可以试试 Square 的Retrofit。这些都能让你的网络请求变得更友好。


大 JSON

在 UI 线程,也不做解析 Json 的事情,因为这是一个很耗时的事情。试着用 Google 的 GSON 来做反序列化的操作。

 

对于巨大的 JSON 解析,建议用更快的 Jackson 以及 ig-json-parser,这两个工具在 JSON 的解析上做的非常漂亮。从公司的反馈结果来看 ig-json-parser 的效率是最高的。

Looper.myLooper() == Looper.getMainLooper() 是可以帮助你确定你是否在主线程的代码。


如何优化滑动速度?

UI 线程只做 UI 更新,理解并发 API。开始使用优秀的第三方库,使用 Loader 加载数据库数据。之所以要用第三方库,是因为你自己去完善一个复杂功能是需要花时间的。如果你打算专注在自己的功能性的 App 上,那么用库吧。

对于没有任何经验的程序员来说,要想做出一个高性能的Android APP,实属不易,即使在学校学过再高深的理论,但那只适用于科研,跟企业需求完全脱节,就比如本文提到的用户体验,这是最致命的一点,没有良好的用户体验就不能吸引大量用户的注册,更没有现在各个互联网公司追求的庞大数据,再严重一些的,直接导致项目夭折。

中软卓越java培训,立足于企业需求,与行业知识无缝连接,4个月的磨砺换来更牛的技术和终身财富,包括华为、BAT在内的知名合作企业,进名企拿高薪不是梦,实现你当初定的小小目标!