1、启动模式?
一. Android启动模式具体解释
1. Standard 标准模式
Android创建Activity时的默认模式,假设没有为Activity设置启动模式的话,默觉得标准模式。每次启动一个Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在。
生命周期:如上所看到的,每次被创建的实例Activity 的生命周期符合典型情况,它的onCreate、onStart、onResume都会被调用。
2. SingleTop 栈顶复用模式
分两种处理情况:须要创建的Activity已经处于栈顶时,此时会直接复用栈顶的Activity。不会再创建新的Activity;若须要创建的Activity不处于栈顶,此时会又一次创建一个新的Activity入栈,同Standard模式一样。
生命周期:若情况一中栈顶的Activity被直接复用时,它的onCreate、onStart不会被系统调用,由于它并没有发生改变。可是一个新的方法 onNewIntent会被回调(Activity被正常创建时不会回调此方法)。
3. SingleTask 栈内复用模式
若须要创建的Activity已经处于栈中时,此时不会创建新的Activity,而是将存在栈中的Activity上面的其他Activity所有销毁,使它成为栈顶。
生命周期:同SingleTop 模式中的情况一同样。仅仅会又一次回调Activity中的 onNewIntent方法
4. SingleInstance 单实例模式
SingleInstance比較特殊,是全局单例模式,是一种加强的SingleTask模式。它除了具有它所有特性外,还加强了一点:具有此模式的Activity仅仅能单独位于一个任务栈中。
二.启动模式的使用方式
1. 在 Manifest.xml中指定Activity启动模式
一种静态的指定方法,在Manifest.xml文件里声明Activity的同一时候指定它的启动模式,这样在代码中跳转时会依照指定的模式来创建Activity。样例例如以下:
<activity android:name="..activity.MultiportActivity" android:launchMode="singleTask"/>
2. 启动Activity时。在Intent中指定启动模式去创建Activity
一种动态的启动模式,在new 一个Intent后,通过Intent的addFlags方法去动态指定一个启动模式。样例例如以下:
Intent intent = new Intent();
intent.setClass(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
注意:以上两种方式都能够为Activity指定启动模式,可是二者还是有差别的。
(1)优先级:动态指定方式即另外一种比第一种优先级要高,若两者同一时候存在,以另外一种方式为准。
(2)限定范围:第一种方式无法为Activity直接指定 FLAG_ACTIVITY_CLEAR_TOP 标识,另外一种方式无法为Activity指定 singleInstance 模式。
2、ANR
一.定义
ANR:Application Not Responding,即应用无响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close。
二.出现场景
1.Service Timeout:前台服务在20s内未执行完成,后台服务200s;
2.BroadcastQueue Timeout:前台广播在10s内未执行完成,后台广播60s
3.ContentProvider Timeout:内容提供者执行超时
4.InputDispatching Timeout: 输入事件分发超时5s,包括按键分发事件的超时。
三.实现原理
Android系统ANR的实现,基本都是基于Handler消息机制来完成的。前面说过响应超时的定义,那么在一个事件执行开始时,通过Handler去post一个对应时间的延迟消息,如果事件在规定事件内执行完成,就remove掉这个message,否则,Handler就会收到这个ANR的Message,做进一步处理,dump日志,弹出ANR对话框。
四.可能导致ANR的原因
1.IO操作,如数据库、文件、网络
2.CPU不足,一般是别的App占用了大量的CPU,导致App无法及时处理
3.硬件操作,如camera
4.线程问题,如主线程被join/sleep,或wait锁等导致超时
五.如何避免
1.UI主线程尽量只做跟UI相关的工作.
2.耗时的操作,如I/O,网络连接,把它放入单独的线程处理
3.尽量用Handler来处理UI线程和非UI线程之间的交互
3、service 两种启动方式的区别
Service的生命周期Service的生命周期方法比Activity少一些,只有onCreate,onStart,onDestroy
一.通过startService启动
此种开启方式Service会经历onCreate()--onStart()。若Service还没运行,则先调用onCreate(),然后调用onStart();如果Service已经启动,则只会调用onStart()。一个Service的onStart()方法可以被调用多次。stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。
二.通过bindService启动
此种启动方式Service会经历onCreate()--onBind(),onBind将会返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的运行状态等。这个时候调用者会和Service绑定在一起,调用者退出的时候,Service就会调用onUnbind--onDestroy退出。
4、四大组件
Android 开发的四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),勇于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。
一.活动
Activity是Android的四大组件之一。是用户操作的可视化界面;它为用户提供了一个完成操作指令的窗口。当我们创建完毕Activity之后,需要调用setContentView()方法来完成界面的显示;以此来为用户提供交互的入口。在Android App 中只要能看见的几乎都要依托于Activity,所以Activity是在开发中使用最频繁的一种组件。
一个Activity实质上有四种状态:
a.运行中(Running/Active):这时Activity位于栈顶,是可见的,并且可以用户交互。
b.暂停(Paused):当Activity失去焦点,不能跟用户交互了,但依然可见,就处于暂停状态。当一个新的非全屏的Activity或者一个透明的Activity放置在栈顶,Activity就处于暂停状态;这个时候Activity的各种数据还被保持着;只有在系统内存在极低的状态下,系统才会自动的去销毁Activity。
c.停止(Stoped):当一个Activity被另一个Activity完全覆盖,或者点击HOME键退入了后台,这时候Activity处于停止状态。这里有些是跟暂停状态相似的:这个时候Activity的各种数据还被保持着;当系统的别的地方需要用到内容时,系统会自动的去销毁Activity。
d.销毁(Detroyed):当我们点击返回键或者系统在内存不够用的情况下就会把Activity从栈里移除销毁,被系统回收,这时候,Activity处于销毁状态。
二.服务
service(服务)是安卓中的四大组件之一,它通常用作在后台处理耗时的逻辑,与Activity一样,它存在自己的生命周期,也需要在AndroidManifest.xml配置相关信息。
三.广播接受者
在Android中,广播是一种广泛运用的在应用程序之间传输信息的机制。而广播接收器是对发送出来的广播进行过滤接受并响应的一类组件。可以使用广播接收器来让应用对一个外部事件做出响应。
广播接收者的注册有两种方法,分别是程序动态注册(在运行时的代码中使用Context.registerReceive()进行注册)和AndroidManifest文件中进行静态注册。
动态注册广播接收器特点是当用来注册的Activity关掉后,广播也就失效了。静态注册无需担忧广播接收器是否被关闭,只要设备是开启状态,广播接收器也是打开着的。也就是说哪怕app本身未启动,该app订阅的广播在触发时也会对它起作用。
四.内容提供者
ContentProvider应用程序间非常通用的共享数据的一种方式,也是Android官方推荐的方式。Android中许多系统应用都使用该方式实现数据共享,比如通讯录、短信等。
5、OOM和内存泄漏?
GC回收则会定时扫描内存,发现不被引用的对象即可回收。正常来说你的app堆内存会有升有降。此时如果有某个Activity持有某个引用,在onDestroy时还不把这个引用设为null,那么返回进入退出这个界面,Activity就会创建很多次从而存在多个实例,导致堆内存直升不降!这就叫做内存泄漏。当用户重复这个操作或者有多个不同Activity内存泄漏时,app运行一段时间堆内存超过系统规定的最大值 heapSize,杯子满了就会发现内存溢出(OOM),app崩溃。
怎么避免内存
一句话归纳:(生命周期比Activity长的类不要去强引用Activity)
内部类请使用static,因为非静态内部类默认持有外部类的引用,比如在Activity里面直接放一个自定义的Adapter
静态类(比如Application,单例类,其他static类)请不要持有Activity引用,因为静态类生命周期比Activity长。解决办法:在需要的地方用BaseApplication.getTopActivity。或者Activity作为弱引用传入
注意Handler会默认持有当前Activity,用的时候最好不要直接new Handler().post(new Runnable...),除非你确定这个runnable会在Activity销毁前执行完
OK,假设你的项目比较紧急,想暂时规避内存泄漏问题怎么办?可以在manifest.xml加入本文开头给的那个设置:
android:largeHeap="true"
此时heapsize会增大2-3倍,缓解OOM的发生。
6、Serializable和Parcelable区别?
Android中Intent如果要传递类对象,可以通过两种方式实现。
方式一:Serializable,要传递的类实现Serializable接口传递对象,
方式二:Parcelable,要传递的类实现Parcelable接口传递对象。
Serializable(Java自带):
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
Parcelable(android 专用):
除了Serializable之外,使用Parcelable也可以实现相同的效果,
不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,
而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
选择序列化方法的原则:
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
两者最大的区别在于存储媒介的不同,Serializable使用IO读写存储在硬盘上,而Parcelable是直接在内存中读写,很明显内存的读写速度通常大于IO读写,所以在Android中通常优先选择Parcelable。
7、Serializable和Parcelable区别?
一、使用Bundle
在Android开发中,我们通常会使用Bundle在不同的组件中传递一些数据,由于Bundle 本身已经实现了Parcelable 接口,所以它可以很方便地在进程间传输。当我们在一个进程中启动了另一个进程的Activity、Service和Receiver,我们可以将需要传输的数据放入Bundle中并通过Intent传递出去。我们必须要知道,我们传输的数据必须是可序列化的,比如基本类型、实现了Serializable 或Parcelable接口的对象以及一些Android支持的特殊对象
二、使用文件共享
两个进程可以通过读/写同一个文件来交换数据,也就是说A进程把数据写入到共享文件中,B进程通过读取共享文件获取A进程共享的数据,这在Android 中也是一个常见的数据共享方式。通过文件共享实现进程间通信的局限性也是比较明显的:当多个线程并发读写文件,那么我们得到的数据就可能不是正确的。所以在使用这项技术的时候,我们应该尽量避免并发读写这种情况的发生,或者只在对数据同步要求不高的情况下使用文件共享来实现进程间通信,并且妥善处理并发读写问题。
三、ContentProvider
ContentProvider 是Android中提供的专门用于不同进程间数据共享的方式,ContentProvider作为Android中的四大组件之一,可见它在Android中是比较重要的。它的底层实现同样是Binder
四、Socket
Socket也称为套接字. 是网络通信中的概念, 它分为流式套接字和用户数据包套接字两种. 分别对应于网络的传输控制层中TCP和UDP协议.
8、sp、dp和px的区别
px : 其实就是像素单位,比如我们通常说的手机分辨列表800*400都是px的单位
sp : 同dp相似,还会根据用户的字体大小偏好来缩放
dp : 虚拟像素,在不同的像素密度的设备上会自动适配