Android高级开发面试题目,妈妈不再用担忧我不能升职加薪了!

**Java基础
一、内部类的做用**html

内部类能够用多个实例,每一个实例都有本身的状态信息,而且与其余外围对象的信息相互独立。java

在单个外部类中,可让多个内部类以不一样的方式实现同一个接口,或者继承同一个类。android

建立内部类对象的时刻并不依赖于外围类对象的建立。面试

内部类并无使人迷惑的“is-a”关系,他就是一个独立的实体。算法

内部类提供了更好的封装,除了该外围类,其余类都不能访问数据库

二、父类的静态方法可否被子类重写,为何?编程

不能小程序

子类继承父类后,用相同的静态方法和非静态方法,这时非静态方法覆盖父类中的方法(即方法重写),父类的该静态方法被隐藏(若是对象是父类则调用该隐藏的方法),另外子类可继承父类的静态与非静态方法,至于方法重载我以为它其中一要素就是在同一类中,不能说父类中的什么方法与子类里的什么方法是方法重载的体现设计模式

想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:862625886。本群可免费获取Gradle、RxJava、小程序、Hybrid、移动架构、NDK、React Native、性能优化等技术教程!数组

三、哪些状况下的对象会被垃圾回收机制处理掉

Java垃圾回收机制最基本的作法是分代回收。内存中的区域被划分红不一样的世代,对象根据其存活的时间被保存在对应世代的区域中。通常的实现是划分红3个世代:年轻、年老和永久。内存的分配是发生在年轻世代中的。当一个对象存活时间足够长的时候,它就会被复制到年老世代中。对于不一样的世代可使用不一样的垃圾回收算法。进行世代划分的出发点是对应用中对象存活时间进行研究以后得出的统计规律。通常来讲,一个应用中的大部分对象的存活时间都很短。好比局部变量的存活时间就只在方法的执行过程当中。基于这一点,对于年轻世代的垃圾回收算法就能够颇有针对性。
四、进程和线程的区别

简而言之,一个程序至少有一个进程,一个进程至少有一个线程。

线程的划分尺度小于进程,使得多线程程序的并发性高。

另外,进程在执行过程当中拥有独立的内存单元,而多个线程共享内存,从而极大地提升了程序的运行效率。

线程在执行过程当中与进程仍是有区别的。每一个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。可是线程不可以独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分能够同时执行。但操做系统并无将多个线程看作多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

进程是具备必定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程本身基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),可是它可与同属一个进程的其余的线程共享进程所拥有的所有资源.

一个线程能够建立和撤销另外一个线程;同一个进程中的多个线程之间能够并发执行.

进程和线程的主要差异在于它们是不一样的操做系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不一样执行路径。线程有本身的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,因此多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行而且又要共享某些变量的并发操做,只能用线程,不能用进程。若是有兴趣深刻的话,我建议大家看看《现代操做系统》或者《操做系统的设计与实现》。对就个问题说得比较清楚。

五、HashMap的实现原理

HashMap概述:HashMap是基于哈希表的Map接口的非同步实现。此实现提供全部可选的映射操做,并容许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

HashMap的数据结构:在java编程语言中,最基本的结构就是两种,一个是数组,另一个是模拟指针(引用),全部的数据结构均可以用这两个基本结构来构造的,HashMap也不例外。HashMap其实是一个“链表散列”的数据结构,即数组和链表的结合体。

HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。

六、String、StringBuffer、StringBuilder区别

String 字符串常量

StringBuffer 字符串变量(线程安全)

StringBuilder 字符串变量(非线程安全)

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 所以在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,而后将指针指向新的 String 对象,因此常常改变内容的字符串最好不要用String ,由于每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了之后,JVM 的 GC 就会开始工做,那速度是必定会至关慢的。

而若是是使用 StringBuffer 类则结果就不同了,每次结果都会对 StringBuffer 对象自己进行操做,而不是生成新的对象,再改变对象引用。因此在通常状况下咱们推荐使用 StringBuffer ,特别是字符串对象常常改变的状况下。而在某些特别状况下, String 对象的字符串拼接实际上是被 JVM 解释成了 StringBuffer 对象的拼接,因此这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是如下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

在大部分状况下 StringBuffer > String

Java.lang.StringBuffer线程安全的可变字符序列。一个相似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但经过某些方法调用能够改变该序列的长度和内容。

可将字符串缓冲区安全地用于多个线程。能够在必要时对这些方法进行同步,所以任意特定实例上的全部操做就好像是以串行顺序发生的,该顺序与所涉及的每一个线程进行的方法调用顺序一致。

StringBuffer 上的主要操做是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每一个方法都能有效地将给定的数据转换成字符串,而后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

在大部分状况下 StringBuilder > StringBuffer

java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用做 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种状况很广泛)。若是可能,建议优先采用该类,由于在大多数实现中,它比 StringBuffer 要快。二者的方法基本相同
七、什么致使线程阻塞

线程的阻塞

为了解决对共享存储区的访问冲突,Java 引入了同步机制,如今让咱们来考察多个线程对共享资源的访问,显然同步机制已经不够了,由于在任意时刻所要求的资源不必定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个。为了解决这种状况下的访问控制问题,Java 引入了对阻塞机制的支持.

阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪),学过操做系统的同窗对它必定已经很熟悉了。Java 提供了大量方法来支持阻塞,下面让咱们逐一分析。

sleep() 方法:sleep() 容许 指定以毫秒为单位的一段时间做为参数,它使得线程在指定的时间内进入阻塞状态,不能获得CPU 时间,指定的时间一过,线程从新进入可执行状态。 典型地,sleep() 被用在等待某个资源就绪的情形:测试发现条件不知足后,让线程阻塞一段时间后从新测试,直到条件知足为止。

suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,而且不会自动恢复,必须其对应的resume() 被调用,才能使得线程从新进入可执行状态。典型地,suspend() 和 resume() 被用在等待另外一个线程产生的结果的情形:测试发现结果尚未产生后,让线程阻塞,另外一个线程产生告终果后,调用 resume() 使其恢复。

yield() 方法:yield() 使得线程放弃当前分得的 CPU 时间,可是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另外一个线程.

wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种容许 指定以毫秒为单位的一段时间做为参数,另外一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程从新进入可执行状态,后者则必须对应的 notify() 被调用.

初看起来它们与 suspend() 和 resume() 方法对没有什么分别,可是事实上它们是大相径庭的。区别的核心在于,前面叙述的全部方法,阻塞时都不会释放占用的锁(若是占用了的话),而这一对方法则相反。

首先,前面叙述的全部方法都隶属于 Thread 类,可是这一对却直接隶属于 Object 类,也就是说,全部对象都拥有这一对方法。初看起来这十分难以想象,可是实际上倒是很天然的,由于这一对方法阻塞时要释放占用的锁,而锁是任何对象都具备的,调用任意对象的 wait() 方法致使线程阻塞,而且该对象上的锁被释放。而调用 任意对象的notify()方法则致使因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到得到锁后才真正可执行)。

其次,前面叙述的全部方法均可在任何位置调用,可是这一对方法却必须在 synchronized 方法或块中调用,理由也很简单,只有在synchronized 方法或块中当前线程才占有锁,才有锁能够释放。一样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁能够释放。所以,这一对方法调用必须放置在这样的 synchronized 方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不知足这一条件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。

wait() 和 notify() 方法的上述特性决定了它们常常和synchronized方法或块一块儿使用,将它们和操做系统的进程间通讯机制做一个比较就会发现它们的类似性:synchronized方法或块提供了相似于操做系统原语的功能,它们的执行不会受到多线程机制的干扰,而这一对方法则至关于 block 和wakeup 原语(这一对方法均声明为 synchronized)。它们的结合使得咱们能够实现操做系统上一系列精妙的进程间通讯的算法(如信号量算法),并用于解决各类复杂的线程间通讯问题。

关于 wait() 和 notify() 方法最后再说明两点:

a、调用 notify() 方法致使解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,咱们没法预料哪个线程将会被选择,因此编程时要特别当心,避免因这种不肯定性而产生问题。

b、除了 notify(),还有一个方法 notifyAll() 也可起到相似做用,惟一的区别在于,调用 notifyAll() 方法将把因调用该对象的 wait() 方法而阻塞的全部线程一次性所有解除阻塞。固然,只有得到锁的那一个线程才能进入可执行状态。

**Android基础
一、是否使用过IntentService,做用是什么,AIDL解决了什么问题?**

生成一个默认的且与主线程互相独立的工做者线程来执行全部传送至onStartCommand() 方法的Intetnt。

生成一个工做队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就没必要担忧多线程的问题。在全部的请求(Intent)都被执行完之后会自动中止服务,因此,你不须要本身去调用stopSelf()方法来中止。

该服务提供了一个onBind()方法的默认实现,它返回null

提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工做队列,而后从工做队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理。

AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成能够在Android设备上两个进程之间进行进程间通讯(interprocess communication, IPC)的代码。若是在一个进程中(例如Activity)要调用另外一个进程中(例如Service)对象的操做,就可使用AIDL生成可序列化的参数。 AIDL IPC机制是面向接口的,像COM或Corba同样,可是更加轻量级。它是使用代理类在客户端和实现端传递数据。

二、Activity、Window、View三者的差异?

Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀,Xml配置像窗花图纸。

在Activity中调用attach,建立了一个Window

建立的window是其子类PhoneWindow,在attach中建立PhoneWindow

在Activity中调用setContentView(R.layout.xxx)

其中其实是调用的getWindow().setContentView()

调用PhoneWindow中的setContentView方法

建立ParentView: 做为ViewGroup的子类,实际是建立的DecorView(做为FramLayout的子类)

将指定的R.layout.xxx进行填充 经过布局填充器进行填充【其中的parent指的就是DecorView】

调用到ViewGroup

调用ViewGroup的removeAllView(),先将全部的view移除掉

添加新的view:addView()

三、Fragment 特色

Fragment能够做为Activity界面的一部分组成出现;

能够在一个Activity中同时出现多个Fragment,而且一个Fragment也能够在多个Activity中使用;

在Activity运行过程当中,能够添加、移除或者替换Fragment;

Fragment能够响应本身的输入事件,而且有本身的生命周期,它们的生命周期会受宿主Activity的生命周期影响。

四、Handler、Thread和HandlerThread的差异?

http://blog.csdn.net/guolin_b...

http://droidyue.com/blog/2015...

从Android中Thread(java.lang.Thread -> java.lang.Object)描述能够看出,Android的Thread没有对Java的Thread作任何封装,可是Android提供了一个继承自Thread的类HandlerThread(android.os.HandlerThread -> java.lang.Thread),这个类对Java的Thread作了不少便利Android系统的封装。

android.os.Handler能够经过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也就是HandlerThread。HandlerThread对象start后能够得到其Looper对象,而且使用这个Looper对象实例Handler。

五、Launch mode应用场景

Standard,建立一个新的Activity。

SingleTop,栈顶不是该类型的Activity,建立一个新的Activity。不然,onNewIntent。

SingleTask,回退栈中没有该类型的Activity,建立Activity,不然,onNewIntent+ClearTop。

注意:

设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 若是存在这样的Task,它就会在这个Task中启动,不然就会在新的任务栈中启动。所以, 若是咱们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。

若是设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 若是存在,就会把位于这个Activity实例上面的Activity所有结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。

在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面能够有其余的Activity。这点与singleInstance是有区别的。

singleInstance,回退栈中,只有这一个Activity,没有其余Activity。

SingleTop适合接收通知启动的内容显示页面。

例如,某个新闻客户端的新闻内容页面,若是收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。

singleTask适合做为程序入口点。

例如浏览器的主界面。无论从多少个应用启动浏览器,只会启动主界面一次,其他状况都会走onNewIntent,而且会清空主界面上面的其余页面。

singleInstance应用场景:

闹铃的响铃界面。 你之前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,而且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是由于 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 所以退出以后这个 Task 的栈空了。若是是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。

六、Android事件分发机制

https://www.jianshu.com/p/380...
七、view绘制流程

https://www.jianshu.com/p/bb7...
八、post和postDelay

九、线程同步

http://www.itzhai.com/java-ba...

推荐:Android开发面试题汇总

[收集的Android面试题,有时间看看~一、 Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念DVM指Dalvik的虚拟机。每个Android应用程序都在它本身的进程中

http://www.juwends.com/tech/a...

十、单例模式

public class Singleton {
private volatile static Singleton mSingleton;
private Singleton () {
}
public static Singleton getInstance () {
if (mSingleton == null ){
synchronized (Singleton.class){
if (mSingleton == null )
mSingleton = new Singleton();
}
}
return mSingleton;
}
}

十一、什么状况致使内存泄漏

a、资源对象没关闭形成的内存泄漏

描述: 资源性对象好比(Cursor,File文件等)每每都用了一些缓冲,咱们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不只存在于 java虚拟机内,还存在于java虚拟机外。若是咱们仅仅是把它的引用设置为null,而不关闭它们,每每会形成内存泄漏。由于有些资源性对象,好比 SQLiteCursor(在析构函数finalize(),若是咱们没有关闭它,它本身会调close()关闭),若是咱们没有关闭它,系统在回收它时也会关闭它,可是这样的效率过低了。所以对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,而后才置为null.在咱们的程序退出时必定要确保咱们的资源性对象已经关闭。 程序中常常会进行查询数据库的操做,可是常常会有使用完毕Cursor后没有关闭的状况。若是咱们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操做的状况下才会复现内存问题,这样就会给之后的测试和问题排查带来困难和风险。

b、构造Adapter时,没有使用缓存的convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 来向ListView提供每个item所须要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化必定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,而后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此能够看出,若是咱们不去使用 convertView,而是每次都在getView()中从新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用愈来愈大。 ListView回收list item的view对象的过程能够查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代码:

public View getView ( int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
... ...
return view;
}
修正示例代码:
public View getView ( int position, ViewconvertView, ViewGroup parent ) {
View view = null ;
if (convertView != null ) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}

c、Bitmap对象不在使用时调用recycle()释放内存

有时咱们会手工的操做Bitmap对象,若是一个Bitmap对象比较占内存,当它不在被使用的时候,能够调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视状况而定。

d、试着使用关于application的context来替代和activity相关的context

这是一个很隐晦的内存泄漏的状况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他本身的范围以外。使用Application context。这个context的生存周期和你的应用的生存周期同样长,而不是取决于activity的生存周期。若是你想保持一个长期生存的对象,而且这个对象须要一个context,记得使用application对象。你能够经过调用 Context.getApplicationContext() or Activity.getApplication()来得到。更多的请看这篇文章如何避免 Android内存泄漏。

e、注册没反注册形成的内存泄漏

一些Android程序可能引用咱们的Anroid程序的对象(好比注册机制)。即便咱们的Android程序已经结束了,可是别的引用程序仍然还有对咱们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。 好比:假设咱们但愿在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则能够在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当须要显示锁屏界面的时候就会建立一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。 可是若是在释放 LockScreen对象的时候忘记取消咱们以前注册的PhoneStateListener对象,则会致使LockScreen没法被垃圾回收。若是不断的使锁屏界面显示和消失,则最终会因为大量的LockScreen对象没有办法被回收而引发OutOfMemory,使得system_process 进程挂掉。 虽然有些系统程序,它自己好像是能够自动取消注册的(固然不及时),可是咱们仍是应该在咱们的程序中明确的取消注册,程序结束时应该把全部的注册都取消掉。

f、集合中对象没清理形成的内存泄漏

咱们一般把一些对象的引用加入到了集合中,当咱们不须要该对象时,并无把它的引用从集合中清理掉,这样这个集合就会愈来愈大。若是这个集合是static的话,那状况就更严重了

十二、ANR定位和如何避免?

1.若是开发机器上出现问题,咱们能够经过查看/data/anr/traces.txt便可,最新的ANR信息在最开始部分。

2.主线程被IO操做(从4.0以后网络IO不容许在主线程中)阻塞。

3.主线程中存在耗时的计算

4.主线程中错误的操做,好比Thread.wait或者Thread.sleep等 Android系统会监控程序的响应情况,一旦出现下面两种状况,则弹出ANR对话框

5.应用在5秒内未响应用户的输入事件(如按键或者触摸)

6.BroadcastReceiver未在10秒内完成相关的处理

7.Service在特定的时间内没法处理完成 20秒

避免

1.使用AsyncTask处理耗时IO操做。

2.使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,不然仍然会下降程序响应,由于默认Thread的优先级和主线程相同。

3.使用Handler处理工做线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程。

4.Activity的onCreate和onResume回调中尽可能避免耗时的代码

5.BroadcastReceiver中onReceive代码也要尽可能减小耗时,建议使用IntentService处理。

1三、什么状况致使OOM以及如何避免?

http://blog.csdn.net/yangxueh...

http://blog.csdn.net/ljx19900...

1四、Android Service与Activity之间通讯的几种方式?

经过Binder对象

经过Broadcast(广播)的形式

1五、如何保证service在后台尽可能不被kill

onStartCommand方法,返回START_STICKY

1.START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,可是不保留那些传入的intent。不久后service就会再次尝试从新建立,由于保留在开始状态,在建立 service后将保证调用onstartCommand。若是没有传递任何开始命令给service,那将获取到null的intent。

2.START_NOT_STICKY 在运行onStartCommand后service进程被kill后,而且没有新的intent传递给它。Service将移出开始状态,而且直到新的明显的方法(startService)调用才从新建立。由于若是没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。

3.START_REDELIVER_INTENT 在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才中止传递intent。若是在被kill后还有未处理好的intent,那被kill后服务仍是会自动启动。所以onstartCommand不会接收到任何null的intent。

提高service优先级
在AndroidManifest.xml文件中对于intent-filter能够经过android:priority="1000"这个属性设置最高优先级,1000是最高值,若是数字越小则优先级越低,同时适用于广播。

提高service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:

前台进程( FOREGROUND_APP)
可视进程(VISIBLE_APP )
次要服务进程(SECONDARY_SERVER )
后台进程 (HIDDEN_APP)
内容供应节点(CONTENT_PROVIDER)
空进程(EMPTY_APP)
当service运行在低内存的环境时,将会kill掉一些存在的进程。所以进程的优先级将会很重要,可使用startForeground 将service放到前台状态。这样在低内存时被kill的概率会低一些。

onDestroy方法里重启service
service+broadcast方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,从新启动service;
Application加上Persistent属性
监听系统广播判断Service状态

1六、RequestLayout,onLayout,onDraw,DrawChild区别与联系

1.requestLayout()方法 :会致使调用measure()过程 和 layout()过程 。说明:只是对View树从新布局layout过程包括measure()和layout()过程,不会调用draw()过程,但不会从新绘制 任何视图包括该调用者自己。

2.onLayout()方法(若是该View是ViewGroup对象,须要实现该方法,对每一个子视图进行布局)

3.调用onDraw()方法绘制视图自己(每一个View都须要重载该方法,ViewGroup不须要实现该方法)

4.drawChild()去从新回调每一个子视图的draw()方法

1七、invalidate()和postInvalidate() 的区别及使用

http://blog.csdn.net/mars2639...

1八、LinearLayout对比RelativeLayout

RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure

RelativeLayout的子View若是高度和RelativeLayout不一样,则会引起效率问题,当子View很复杂时,这个问题会更加严重。若是能够,尽可能使用padding代替margin。

在不影响层级深度的状况下,使用LinearLayout和FrameLayout而不是RelativeLayout。

1九、优化自定义view

为了加速你的view,对于频繁调用的方法,须要尽可能减小没必要要的代码。先从onDraw开始,须要特别注意不该该在这里作内存分配的事情,由于它会致使GC,从而致使卡顿。在初始化或者动画间隙期间作分配内存的动做。不要在动画正在执行的时候作内存分配的事情。

你还须要尽量的减小onDraw被调用的次数,大多数时候致使onDraw都是由于调用了invalidate().所以请尽可能减小调用invaildate()的次数。若是可能的话,尽可能调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。

另一个很是耗时的操做是请求layout。任什么时候候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每个view的大小。若是找到有冲突的值,它会须要从新计算好几回。另外须要尽可能保持View的层级是扁平化的,这样对提升效率颇有帮助。

若是你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操做。与内置的view不一样,自定义的view可使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展现了如何继承ViewGroup做为自定义view的一部分。PieChart 有子views,可是它历来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。

20、ContentProvider

https://www.jianshu.com/p/ea8...

2一、Android 设计模式

http://blog.csdn.net/bboyfeiy...

2二、MVC、MVP、MVM区别?

https://www.cnblogs.com/guwei...

想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:862625886。本群可免费获取Gradle、RxJava、小程序、Hybrid、移动架构、NDK、React Native、性能优化等技术教程!

相关文章
相关标签/搜索