第二天----Android笔记

笔记参考文章

1、一个Activity从启动到结束会以如下顺序经历整个生命周期:

1.onCreate()
->onStart():Activity已出现在后台,无法与用户交互。这个时候可以理解为Activity已经显示出来,但是我们还看不到。
->onResume():Activity已经可见,并且出现在前台并开始活动。
->onPause():Activity仍可见,正常情况下紧接着onStop就会被调用。必须执行完,新的Activity的onResume才会执行。
->onStop()
->onDestory()
当前Activity从不可见重新变为可见状态时调用onRestart

2、栈顶复用模式(singleTop)

如果需要新建的Activity位于任务栈栈顶,那么此Activity的实例就不会重建,而是重用栈顶的实例。并回调onNewIntent( )方法

3、栈内复用模式(singleTask)

一种单例模式,即一个栈内只有一个该Activity实例。
可以通过在AndroidManifest文件的Activity中指定该Activity需要加载到那个栈中,即singleTask的Activity可以指定想要加载的目标栈。singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中。

4、单例模式(singleInstance)

栈内复用模式(singleTask)的加强版,打开该Activity时,直接创建一个新的任务栈,并创建该Activity实例放入新栈中。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例。

5、mainFest文件中exported属性代表是否能被其他应用隐式调用

1.Activity中标示当前Activity是否可以被另一个Application的组件启动
2.Service中标示其它应用的组件是否可以唤醒service或者和这个service进行交互
3.provider中标示当前内容提供者是否会被其它应用使用
4.receiver中,标识当前broadcastReceiver是否可以从当前应用外部获取Receiver message 。如果为false ,当前broadcast Receiver 只能收到同一个应用或者拥有同一user ID 应用发出广播。

除了Provider,其默认值是由有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,那么这个Activity将只会被当前Application或者拥有同样user ID的Application的组件调用,对于其他应用,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
对于Provider,当Android sdk 的最小版本为16或者更低时他的默认值是true。如果是17和以上的版本默认值是false。

6、广播接收器

动态广播最好在Activity的onResume()注册、onPause()注销
有注册就必然得有注销,否则会导致内存泄露
重复注册、重复注销也不允许

7、消息机制主要包含:MessageQueue,Handler和Looper这三大部分,以及Message

1.Message:需要传递的消息,可以传递数据;
2.MessageQueue:消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
3.Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
4.Looper:不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。

每个线程中只能存在一个Looper,Looper是保存在ThreadLocal中的。
主线程(UI线程)已经创建了一个Looper,所以在主线程中不需要再创建Looper,但是在其他线程中需要创建Looper。
每个线程中可以有多个Handler,即一个Looper可以处理来自多个Handler的消息。
Looper中维护一个MessageQueue,来维护消息队列,消息队列中的Message可以来自不同的Handler。

8、AsyncTask使用不当的后果

1.生命周期
AsyncTask不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean);
2.内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
3.结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
1、获取Context对象,主要有以下四种方法
1.View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
2.Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
3.ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
4.Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。

当Application的Context能搞定的情况下,并且生命周期长的对象,优先使用Application的Context。

不要让生命周期长于Activity的对象持有到Activity的引用。

尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用,如果使用静态内部类,将外部实例引用作为弱引用持有。

2、如何进行布局优化?

1.删除布局中无用的控件和层次,其次有选择地使用性能比较低的ViewGroup。
例如:
如果布局中既可以使用LinearLayout也可以使用RelativeLayout,那么就采用LinearLayout,这是因为RelativeLayout的功能比较复杂,它的布局过程需要花费更多的CPU时间。

FrameLayout和LinearLayout一样都是一种简单高效的ViewGroup,因此可以考虑使用它们,但是很多时候单纯通过一个LinearLayout或者FrameLayout无法实现产品效果,需要通过嵌套的方式来完成。
这种情况下还是建议采用RelativeLayout,因为ViewGroup的嵌套就相当于增加了布局的层级,同样会降低程序的性能。

2.采用标签,标签,ViewStub。
标签主要用于布局重用。
标签一般和配合使用,可以降低减少布局的层级。
ViewStub提供了按需加载的功能,当需要时才会将ViewStub中的布局加载到内存,提高了程序初始化效率。

3.避免多度绘制
过度绘制(Overdraw)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的 UI 结构里面,如果不可见的 UI 也在做绘制的操作,会导致某些像素区域被绘制了多次,同时也会浪费大量的 CPU 以及 GPU 资源。

3、线程优化

线程优化的思想就是采用线程池,避免程序中存在大量的Thread。
线程池可以重用内部的线程,从而避免了线程的创建和销毁锁带来的性能开销,同时线程池还能有效地控制线程池的最大并法术,避免大量的线程因互相抢占系统资源从而导致阻塞现象的发生。
因此在实际开发中,尽量采用线程池,而不是每次都要创建一个Thread对象。

4、其他性能优化建议

1.避免过度的创建对象
2.不要过度使用枚举,枚举占用的内存空间要比整型大
3.常量请使用static final来修饰
4.用一些Android特有的数据结构,比如SparseArray和Pair等
5.适当采用软引用和弱引用
6.采用内存缓存和磁盘缓存
7.尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄漏。

5、Java 内存分配策略

Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式分配,和堆式分配,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区。
1.静态存储区(方法区):主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。
2.栈区 :当方法被执行时,方法体内的局部变量都在栈上创建,并在方法执行结束时这些局部变量所持有的内存将会自动被释放。因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
3.堆区 : 又称动态内存分配,通常就是指在程序运行时直接 new 出来的内存。这部分内存在不使用时将会由 Java 垃圾回收器来负责回收。

局部变量的基本数据类型和引用存储于栈中,引用的对象实体存储于堆中。—— 因为它们属于方法中的变量,生命周期随方法而结束。
成员变量全部存储于堆中(包括基本数据类型,引用和引用的对象实体)—— 因为它们属于类,类对象终究是要被new出来使用的。

6、内存泄漏

1.对 Activity 等组件的引用应该控制在 Activity 的生命周期之内; 如果不能就考虑使用 getApplicationContext 或者 getApplication,以避免 Activity 被外部长生命周期的对象引用而泄露。
2.尽量不要在静态变量或者静态内部类中使用非静态外部成员变量(包括context ),即使要使用,也要考虑适时把外部成员变量置空;也可以在内部类中使用弱引用来引用外部类的变量。
3.对于生命周期比Activity长的内部类对象,并且内部类中使用了外部类的成员变量,可以这样做避免内存泄漏:
4.将内部类改为静态内部类
5.静态内部类中使用弱引用来引用外部类的成员变量
6.Handler 的持有的引用对象最好使用弱引用,资源释放时也可以清空 Handler 里面的消息。比如在 Activity onStop 或者 onDestroy 的时候,取消掉该 Handler 对象的 Message和 Runnable.
7.在 Java 的实现过程中,也要考虑其对象释放,最好的方法是在不使用某对象时,显式地将此对象赋值为 null,比如使用完Bitmap 后先调用 recycle(),再赋为null,清空对图片等资源有直接引用或者间接引用的数组(使用 array.clear() ; array = null)等,最好遵循谁创建谁释放的原则。
8.正确关闭资源,对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销。
9.保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命周期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值