Android 知识
-
四大组件相关问题
-
Activity四种启动模式
Standard、SingleTop、SingleTask、SingleInstance
1. Standard:每次启动都重新创建一个新的实例,且谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity的任务栈中
2. SingleTop:栈顶复用模式。如果新的Activity已经位于任务栈的栈顶,那么不会被重新创建,而是回调onNewIntent()方法,通过此方法的参数可以去除当前请求的信息 -- 栈顶唯一
3. SingleTask:这是一种单例模式,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,而是回调onNewIntent方法。同时该Activity上方的Activity全部被销毁出栈 -- 栈内唯一
4. SingleInstance:一个Activity单独运行在一个工作栈中,具备SingleTask所有的特点。
* 坑1:此时有三个Activity,A、B、C,B的启动模式为SingleInstance,其他都默认。startActivity了一个A,A里面启动了B,B里面启动了C。此时在当前任务栈中的顺序是A -> B -< C。C页面按返回键返回到A,A页面按返回键时会返回到B。
* 坑2:此时有两个Activity,A、B,A启动模式是默认的,B为SingleInstance。当A里startActivity页面B之后。按下Home键,应用退回到后台,此时在点击图标进入App,此时显示的界面是A。 -
Activity的生命周期?在横竖屏转换时候的生命周期流程
onCreate() :完成初始化工作
onStart():界面可见但不在前台,无法与用户交互
onResume():获得焦点,可见可交互
onPause():可做数据存储、停止动画等操作
onStop():可做回收工作
onDestroy():常做回收工作、资源释放
onRestart():界面由不可见到可见,界面重新启动屏幕旋转时的生命流程
onPause()
onSaveInstanceState()
onStop()
onDestroy()
onCreate()
onStart()
onRestoreInstanceState()
onResume()为了避免由于配置改变导致Activity重建,可在AndroidManifest.xml中对应的Activity中设置android:configChanges="orientation|screenSize"。可是再次旋转屏幕时,该Activity不会被系统杀死和重建,只会调用onConfigurationChanged。 -
在SingleTop模式中,打开一个已经存在栈顶的Activity
打开第一个A:onCreate -> onStart -> onResume
此时A跳转至B:A.onPause -> B.onCreate -> B.onStart -> B.onResume -> A.onStop
此时B的启动模式是栈顶模式,再有B打开B:B.onPause -> B.onNewIntent -> B.onResume -
Service两种启动方式
- startService:回调服务中的onStartCommand。如果服务还未被创建,则回调的顺序为onCreate -> onStartCommand。如果服务被启动后会一直保存在运行的状态,直到stopService或者stopSelf方法被调用,服务停止并回调onDestroy。无论调用多少次startService,只需调用一次stopService就能终止服务
- bindService:回调服务中的onBind方法。如果服务还未被创建,则回调的顺序为onCreate -> onBind,之后调用方法可以获取到onBind方法里返回的IBinder对象的实例,从而实现和服务的通信。知道调用了unBindService方法使服务终止,回调顺序onUnBind -> onDestroy
-
Service如何和Activity进行通信
- 通过绑定服务的方式。在绑定的服务中声明一个Binder类,并创建一个Binder对象,在onBind函数中返回这个对象,并让Activity实现ServiceConnection接口,在onServiceConnected方法中获取到Service提供的这个Binder对象,通过这个对象的各种自定义方法就能完成Service与Activity的通信
- 通过Intent的方式,startService中需要传入一个Intent对象作为参数,通过这个Intent实例对象进行实现通信
- 通过CallBack和Handler的方式,在绑定的服务中声明一个Binder类,并创建一个Binder对象,在OnBind函数中返回这个对象,让Activity实现ServiceConnection接口,并且在onServeiceConnected方法中实例化Service中的CallBack接口,并且实现onDataChange方法,其中的实质是一段Handler代码,可以再其中完成还是操作,以这种方式完成通信
-
Android数据持久化
- File文件存储方式:写入读取文件和Java中实现IO类似
- SharePreferences存储:适用于基本类型数据,本质是意见支队存在XML文件
- SQLite数据库存储
- ContentProvide:四大组件,用于数据的存储和共享,不止局限于数据被该应用程序使用,且能让不同的应用之间共享数据,还能通过对指定的一部分数据进行共享,从而保证隐私数据不会有泄漏的风险。
-
Android广播机制
广播是一种运用在程序之间传输信息的机制,Android中我们发送广播内容实质是一个Intent,这个Intent中可以携带我们要发送的数据
- 普通广播:一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此他们接收到的先后是随机的
- 有序广播:一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播是有先后顺序的,且优先级高的广播器会先收到广播消息。有序广播可以被接收器阶段后使得后面的接收器无法收到它
- 本地广播:发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收本应用程序发出的广播
静态注册:
1. 创建一个广播接收器类,在OnReceive方法中Toast一段信息
2. 在AndroidMainfest.xml中注册才可以使用
> 动态注册:
新建一个类,继承自BroadCaseReceiver,并重写OnReceive函数。由于动态注册时是现在OnCreate方法中的,因此存在一个缺点,必须启动后才能接收到广播。未启动之下就能接收到广播的话,使用静态注册广播接收器。
-
-
Android消息机制
-
Handler消息传递机制
Handler是可以通过发送和处理Message和Runnable对象来进行消息传递,是一种异步消息机制。可以让对应的Message和Runnable在蔚来的某个时间点进行相应的处理。让耗时操作在子线程里执行,让更新UI的操作在主线程完成,而子线程和主线程之间就靠Handler实现通信
Message:是线程之间传递的信息,可以携带少量的信息,用于在不同线程之间交换数据
Handler:负责Message的发送和处理。通过Handler.sendMessage向消息池发送各种消息时间,通过Handler.handleMessage处理相应的消息事件
MessageQueue:用来存放Handler发送过来的消息,内部通过单链表的数据结构来维护消息列表,等待Looper的轮询
Looper:通过Looper.loop不断从MessageQueue中抽取Message,按分发机制将消息分发给目标处理者Handler.sendMessage发送消息时,会通过MessageQueue.enqueueMessage向MessageQueue中添加一条消息,通过Looper.loop开启循环后,不断轮询调用MessageQueue.next。调用目标Handler.dispatchMessage去传递消息,目标Handler收到消息后调用Handler.handlerMessage处理消息。
Handler消息机制.jpg子线程需要手动调用Looper.loop与Looper.prepare方法创建Looper
postDelay:postdelay的Message并不是先等待一定时间在放入到MessageQueue中,而是直接进入并阻塞当前线程,然后将其delay的时间和队头的进行比较,按照触发时间进行排序,如果出发时间更近则放入队头,保证队头的时间最小、队尾的时间最大。此时如果队头的Message正是被delay的,则将当前线程堵塞一段时间,知道等待足够时间在唤醒执行该Message,否则唤醒后直接执行
-
ANR(Application Not Responding)
当操作在一段时间内系统无法处理时,例如:应用在5秒内未响应用户的额输入时间,广播接收器10秒内为完成相关的处理,服务20秒内无法完成处理,那么会在系统层面弹出应用程序无响应的对话框。
为了避免发生ANR,应尽量使用多线程,不要在主线程做好事操作,而是通过开子线程,把耗时的工作放在工作线程中处理,所使用的方法比如继承自Thread类、实现Runnable接口、使用AsyncTask、IntentService、HandlerThread等机制。发生ANR可以通过data/anr找到traces.txt文件确定ANR发生的原因。
-
注:静态内部类生命开始于手动创建,结束于系统回收,因此不会发生内存泄漏。前提是静态内部类引用的对象没有被静态修饰
静态修饰导致内存泄漏
private static Drawable background
ImageView mImage = new ImageView(MainActivity.this)
mImage.setBackground(background)旋转屏幕时,会造成MainActivity内存泄漏。由于background.setCallback(this),而background为静态修饰,导致被background持有的MainActivity无法销毁重建
-
RecyclerView与ListView
-
各文件夹下图片占用内存计算
A(Alpha) R(Red) G(Green) B(Blue)
ARGB_8888:8 + 8 + 8 + 8 = 32位 = 4字节
ARGB_4444: 4 + 4 + 4 + 4 = 16位 = 2字节
RGB_565: 0 + 5 + 6 + 5 = 16位 = 2字节
ALPHA_8: 8 + 0 + 0 + 0 = 8位 = 1字节一张522*686的PNG图片,我把它放到drawable-xxhdpi目录下,在三星s6上加载,占用内存计算
解:xxhdpi对应density为480,targetDensity对应三星s6密度为640,ARGB_8888 一个像素占用4byte522/480 * 640 * 686/480 * 640 * 4 = 2546432B
结合精度计算如下
(522/480f * 640 + 0.5) * (686/480f * 640 + 0.5) * 4 = 2547360B结论:Bitmap在内存中占用大小取决于,色彩格式、存放的资源目录、屏幕密度