天天看点

《Android移动应用开发》 复习题(一)

《Android移动应用开发》

  大家好,我是亓官劼(qí guān jié )

由于学习工作的需要,算法刷题将会逐渐由C++向Python3过度,正在过度中,如实现的不太优美,请见谅。

本文原创为【亓官劼】(qí guān jié ),请大家支持原创,部分平台一直在恶意盗取博主的文章!!! 全部文章请关注微信公众号【亓官劼】。

复习题(一)

(一)Android的体系结构是怎样的?请简要加以说明。

Android的系统架构采用了分层架构的思想,从上层到底层共包括四层,分别是应用层、应用框架层、系统运行库层以及Linux内核层。

应用层:Android平台不仅仅是操作系统,也包含了许多应用程序,譬如SMS短信客户端程序、电话拨号程序、图片浏览器、Web浏览器等应用。这些应用程序都是用Java语言编写的,并且可以被开发人员开发的其他应用程序所替换。

应用框架层:该层是Android应用开发的基础。应用框架层包括活动管理器、窗口管理器、内容提供者、视图系统、包管理器、电话管理器、资源管理器、位置管理器、通知管理器和XMPP服务十个部分。

系统运行库层:系统运行库层可以分成两部分,分别是系统库和Android运行时。

Linux内核层:Android的核心系统服务依赖于Linux内核,如安全性、内存管理、进程管理、网络协议栈和驱动模型。Linux内核也同时作为硬件和软件栈之间的抽象层。

(二)Android程序结构是怎样的?请简要加以分析。

解答:如以工程名称Firstdemo作为根目录,将所有自动生成的和非自动生成的文件都保存在这个根目录下。

(1)src目录:src目录下是java源代码存放目录,里面一般都是.java结尾的java文件。

(2)gen目录:gen目录是Android开发工具自动生成的文件。目录中有个可自定义的包,包里有两个文件,BuildConfig.java和R.java。BuildConfig.java是Android调试用的。R.java是在建立项目时自动生成的,这个文件是只读模式,不能更改。

(3)res目录:res目录是资源目录,可以存放应用使用到的各种资源,如XML界面文件、图片、数据等。

(4)assets目录:assets资源目录一般可用于存放html文件、数据库文件、javascript文件等,还有原始格式的文件,例如二进制格式的音频文件、视频文件等。

(5)AndroidMamifest.xml

AndroidMamifest.xml项目清单文件列出了应用程序提供的功能,开发好的各种组件需要在此文件中进行配置,当应用使用到系统内置的应用(如电话服务、互联网服务、短信服务、GPS服务等)还需在此文件中声明使用权限。每个Android程序必须在根目录下包含一个AndroidMamifest.xml文件。

(三)Activity的四种启动模式是什么?并请加以说明。

Standard、single Top、single Task、single Instance

Standard:默认模式,会在启动时创建一个新实例,创建的模式也可以随Intent.FLAG_ACTIVITY_NEW_TASK而改变

single Top:当启动activity时,有相同的activity在前台与用户交互,那就复用这个activity,这个实例会被调用Activity.onNewIntent()。

single Task:在启动activity时,若有一个运行着这个activity的task,那这个activity实例会被调到前台,并调用Activity.onNewIntent() ,启动实例的Intent的flag会被设置Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT . singleTask是singleTop的一个扩展集。

single Instance:开辟一个只允许一个activity实例在里头运行的task. 如果用同样的intent再次启动这个activity,task会被调到前台,其Activity.onNewIntent() 会被调用. 如果这个activity实例要启动一个新activity,那么这个新activity会在一个新task中运行.

(四)Handler消息传递机制是怎样的?举例加以说明。

利用Handler消息传递的过程是:使用Handler发送消息,该消息被传送到指定的Message Queue。为了保证正常工作,当前线程必须有Message Queue,而Message Queue 是由Looper 对象来管理的。因此要求当前线程必须有一个Looper对象,根据不同类型的线程,处理情况不同,主要分为以下两类:

主线程:系统以及为其初始化了Looper对象,因此可以直接创建Handler对象,并由该Handler对象发送,处理消息。

非主线程:先调用Looper的prepare()方法创建一个Looper对象,然后调用Looper的loop()方法启动它。

当线程有了Looper对象之后,再创建Handler子类的实例,重写handleMessage()方法处理消息,最后由loop()启动Looper对象。

(五)如何发送广播?如何接收系统广播消息?

Android广播分为两个方面:广播发送者和广播接收者。通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器),用于异步接收广播Intent。广播Intent是通过调用Context.sendBroadcast()发送、BroadcastReceiver()接收。广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()、Context.sendStickyBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。

广播接收器只能接收广播,对广播的通知做出反应,很多广播都产生于系统代码,如:时区改变的通知、电池电量不足、用户改变了语言偏好,或者开机启动等。

广播接收器没有用户界面,但是它可以为它们接收到信息启动一个Activity或者使用NotificationManager来通知用户。

解答:Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。如:开机启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,由系统自动发出。(编程实现略。)

(六)Service 和 Thread 的区别是什么?为什么使用Service?注意事项是什么?

Thread是程序执行的最小单元,可以用Thread来执行一些异步操作。而Service是Android的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主进程的main线程中的。如果是Remote Service,那么对应的Service则是运行在独立进程的main线程中。

Service可以用来处理一些比较复杂的操作,并且不会因为系统内存紧张而被“杀掉”。

Service不是一个单独的进程,除非单独声明,否则它不会运行在单独的进程中,而是和启动它的程序运行在同一进程中。Service也不是线程,这意味着它将在主线程里运行。

(七)比较进程内服务与跨进程服务的不同。

进程内服务:同一个进程下调用的服务, (通常情况下)即在一个应用程序下的服务。

跨进程服务:通过一个应用程序(客户端)的 Activity 调用另一个应用程序(服务端)的 Service 为跨进程服务。在 Android 中,如果需要在不同进程间实现通信,就需要用到 AIDL 技术去完成。

(八)Executor、ExecutorService和Executors的区别是什么?

Executor 是一个简单的标准化接口,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。根据所使用的具体 Executor 类的不同,可能在新创建的线程中,现有的任务执行线程中,或者调用 execute() 的线程中执行任务,并且可能顺序或并发执行。

ExecutorService 提供了多个完整的异步任务执行框架。 ExecutorService 管理任务的排队和安排, 并允许受控制的关闭。

Executors 类提供大多数 Executor 的常见类型和配置的工厂方法, 以及使用它们的几种实用工具方法

Java 里面线程池的顶级接口是 Executor ,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService 。ExecutorService 继承Executor 。Executors 类为创建 ExecutorService 提供了便捷的工厂方法。

(九)ThreadPoolExecutor和ExecutorService有怎样的关系?ThreadPoolExecutor的构造方法是怎样的?试对ThreadPoolExecutor构造方法的参数加以说明。

关系:ThreadPoolExecutor是ExecutorSevice的一个实现类, 它使用可能的儿个池线程之一执行每个提交的任务,通常使用Executors工厂方法配置。

方法:1. 用给定的初始参数和默认的线程工厂及被拒绝的执行处理程序创建新的ThreadPoolExecutor.

2. 用给定的初始参数和默认的线程工厂创建新的ThreadpoolExecutor.

3. 用给定的初始参数和默认被拒绝的执行处理程序创建新的ThreadPoolExecutor.

4. 用给定的初始参数创建新的ThreadPoolExecutor.

说明:✧corePoolSize: 池中所保存的线程数,包括空闲线程。

✧maximumPoolSize: 池中允许的最大线程数。

✧keepAliveTime: 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

✧unit: keepAliveTime 参数的时间单位。

✧workQueue;:执行前用于保持任务的队列。此队列仅保持由execute 方法提交的

Runnable任务。

✧threadFactory;:执行程序创建新线程时使用的工厂,

✧Handler: 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。

(十)为什么说Executors类为创建ExecutorService提供了便捷的工厂方法?

要配置一个线程池是比较复杂的, 尤其是对于线程池的原理不是很清楚的情况下, 很有可能配置的线程池不是较优的, 因此在 Executors 类里面提供了一些静态工厂, 生成一些常用的线程池。

( 1) newCachedThreadPool : 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲( 60 秒不执行任务)的线程,当任务数增加时,此线程池又可以智能地添加新线程来处理任务。 此线程池不会对线程池大小做限制, 线程池大小完全依赖于操作系统(或者说 JVM )能够创建的最大线程大小。

( 2) newFixedThreadPool : 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。 线程池的大小一旦达到最大值就会保持不变, 如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

( 3) newSingleThreadExecutor : 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。 如果这个唯一的线程因为异常结束, 那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

( 4) newScheduledThreadPool :创建一个定长线程池, 此线程池支持定时以及周期性执行任务的需求。

(十一)Java中的强引用、软引用、弱引用的区别是什么?

强引用:是指创建一个对象并把这个对象赋值给一一个引用变量。 强引用不为null时,它指向的对象水远不会被垃圾回收,即使当内存不足时。当强引用被置为nul时,该对象则被标记为可回收的,但是GC可能依旧没有回收它,这和GC的回收算法有关,同时该对象仍然占着内存。总之,我们不能保证可回收的对象被GC回收。

软引用:通过SoftReference类来实现。软引用指向的对象,不用置null,也可以被GC回收,对象是否被释放取决于GC算法以及GC运行时可用的内存数量。通俗地讲,内存空间足够,GC就不会回收它;如果内存空间不足了,就会回收这些对象的内存。

弱引用:通过WeakReference类来创建。GC运行时如果碰到了弱引用对象,不管当前内存空间足够与否,都会回收它的内存,但是也有可能需要GC多次才能发现和释放弱引用的对象。

软引用和弱引用都可以与引用队列( ReferenceQueue)关联,这样就可以知道软引用或者弱引用是否被回收。

(十二)什么是观察者模式?观察者模式的使用场景是怎样的?观察者模式的优缺点是什么?试编程加以说明。

观察者模式就是定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

使用场景:

(1)关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。

(2)事件多级触发场景。

(3)跨系统的消息交换场景,如消息队列的处理机制。

优点:观察者和被观察者之间是抽象耦合;建立了一套触发机制。

缺点:开发和调试比较复杂,而且一个观察者卡壳,会影响整体的执行效率。同时多级触发时的效率让人担忧。

(十三)什么是装饰模式?装饰模式的使用场景是怎样的?装饰模式的优缺点是什么?试编程加以说明。

装饰模式就是动态地给一个对象添加一些额外的职责。

使用场景:

(1)需要扩展一个类的功能,或给一个类增加附加功能。

(2)需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

(3)需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。

优点:

(1)装饰类和被装饰类可以独立发展,而不会相互耦合。

(2)装饰模式是继承关系的一个替代方案。

(3)装饰模式可以动态地扩展一个实现类的功能,这不需要多说,装饰模式的定义就是如此。

缺点:多层类的装饰太过复杂。

(十四)循环对象 Looper 的作用是什么?请加以说明。

用于为一个线程开启一个消息队列(MessageQueue),循环等待其他线程发送消息,当有消息时会唤起线程来处理消息,直到线程结束为止。通常情况下Android中并不会为新线程开启消息循环,不会用到Looper,而主线程除外,系统自动为主线程创建一个Looper对象,并创建消息队列,所以主线程会一直运行, 以处理用户事件,直至退出。

当需要一个线程时,这个线程要能够循环处理其他线程发来的消息事件,或者需要长期与其他线程进行复杂的交互,这时就需要用到Looper来为线程建立消息队列。

Looper对象提供了以下几个方法:

●prepare(): 用于初始化Looper, prepare( )方法保证每个线程至多只有一个Looper对象。

●loop(): 用于开启消息循环,当调用了loop( )方法后,Looper线程就真正地开始工作

了,它会从消息队列中获取消息并交给对应的Handle对象处理消息。

●quit(): 用于结束Looper消息循环。