苏州大学Android韩冬期末复习.docx
《苏州大学Android韩冬期末复习.docx》由会员分享,可在线阅读,更多相关《苏州大学Android韩冬期末复习.docx(18页珍藏版)》请在冰豆网上搜索。
![苏州大学Android韩冬期末复习.docx](https://file1.bdocx.com/fileroot1/2023-2/26/e297efcd-5da3-48ec-8119-69977465a0eb/e297efcd-5da3-48ec-8119-69977465a0eb1.gif)
苏州大学Android韩冬期末复习
《Android应用开发》复习题:
1.Android的体系结构是怎样的?
请简要加以说明。
Android的系统架构采用了分层架构的思想。
从上层到底层共包括四层:
应用层、应用框架层、系统运行库层、Linux内核层。
2.Android程序结构是怎样的?
请简要加以分析。
●src目录:
java源代码
●gen目录:
BuildConfig.java、R.java
●res目录:
res目录是资源目录,可以存放应用使用到的各种资源,如XML界面文件、图片、数据等。
●assets目录:
assets资源目录一般可用于存放html文件、数据库文件、javascript文件等,还有原始格式的文件.
●AndroidManifest.xml:
列出了应用程序提供的功能,开发好的各种组件需要在此文件中进行配置,当应用使用到系统内置的应用还需在此文件中声明使用权限
3.Handler消息传递机制是怎样的?
试以“计时器”的编程举例加以说明。
首先需要在主线程当中创建一个Handler对象,并重写handleMessage()方法。
然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler将这条消息发送出去。
之后这条消息会被添加到MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后分发回Handler的handleMessage()方法中。
由于Handler是在主线程中创建的,所以此时handleMessage()方法中的代码也会在主线程中运行,于是我们在这里就可以安心地进行UI操作了。
一条Message经过这样一个流程的辗转调用后,也就从子线程进入到了主线程,从不能更新UI变成了可以更新UI,整个异步消息处理的核心思想也就是如此。
4.什么是进程内服务?
请编程加以说明。
在同一个进程下调用的服务,(通常情况下)即在一个应用程序下的服务。
Service的启动有两种方式:
context.startService()和context.bindService()。
新建一个MyService继承自Service,并重写父类的onCreate()、onStartCommand()和onDestroy()方法。
Service与activity通讯:
context.bindService()
我们首先创建了一个ServiceConnection的匿名类,在里面重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在Activity与Service建立关联和解除关联的时候调用。
bindService()方法接收三个参数,第一个参数就是刚刚构建出的Intent对象,第二个参数是前面创建出的ServiceConnection的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。
然后如何我们想解除Activity和Service之间的关联怎么办呢?
调用一下unbindService()方法就可以了,这也是UnbindService按钮的点击事件里实现的逻辑。
5.什么是跨进程服务?
请编程加以说明。
通过一个应用程序(客户端)的Activity调用另一个应用程序(服务端)的Service为跨进程服务。
由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI运行另一个服务进程,而且经常会在不同的进程间传递对象。
在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。
Android提供了AIDL工具来处理这项工作。
在Android中,如果需要在不同进程间实现通信,就需要用到AIDL技术去完成。
AIDL是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。
在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢?
显然,Java中是不支持跨进程内存共享的。
因此要传递对象,需要把对象解析成操作系统能够理解的数据格式,以达到跨界对象访问的目的。
我们只是修改了ServiceConnection中的代码。
可以看到,这里首先使用了MyAIDLService.Stub.asInterface()方法将传入的IBinder对象传换成了MyAIDLService对象,接下来就可以调用在MyAIDLService.aidl文件中定义的所有接口了。
ClientTest中的Activity如果想要和MyService建立关联其实也不难,首先需要将MyAIDLService.aidl文件从ServiceTest项目中拷贝过来,注意要将原有的包路径一起拷贝过来,完成后项目的结构如下图所示:
这里先是对MyAIDLService.Stub进行了实现,重写里了toUpperCase()和plus()这两个方法。
这两个方法的作用分别是将一个字符串全部转换成大写格式,以及将两个传入的整数进行相加。
然后在onBind()方法中将MyAIDLService.Stub的实现返回。
这里为什么可以这样写呢?
因为Stub其实就是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现。
我们实现了IPerson.Stub这个抽象类的hello方法,然后再onBind(Intent)方法中返回我们的stub实例,这样一来调用方获取的IPerson.Stub就是我们的这个实例,hello方法也会按照我们的期望那样执行。
我们要重写ServiceConnection中的onServiceConnected方法将IBinder类型的对象转换成我们的IPerson类型。
我们再通过服务端Service定义的“android.intent.action.AIDLService”这个标识符来绑定我们所需要的服务,这样客户端和服务端就实现了通信的连接,我们就可以调用IPerson中的hello方法了。
使用了MyAIDLService.Stub.asInterface()方法将传入的IBinder对象传换成了MyAIDLService对象,接下来就可以调用在MyAIDLService.aidl文件中定义的所有接口了。
IPerson接口中的抽象内部类Stub继承android.os.Binder类并实现IPerson接口,其中比较重要的方法是asInterface(IBinder)方法,该方法会将IBinder类型的对象转换成IPerson类型,必要的时候生成一个代理对象返回结果。
6.如何发送广播?
请编程加以说明。
●因此新建一个MyBroadcastReceiver继承自BroadcastReceiver,代码如下所示:
publicclassMyBroadcastReceiverextendsBroadcastReceiver{
@Override
publicvoidonReceive(Contextcontext,Intentintent){
Toast.makeText(context,"receivedinMyBroadcastReceiver",
Toast.LENGTH_SHORT).show();
}
}
●然后在AndroidManifest.xml中对这个广播接收器进行注册
●然后修改MainActivity中的代码,如下所示:
publicclassMainActivityextendsActivity{
……
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Buttonbutton=(Button)findViewById(R.id.button);
button.setOnClickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent("com.example.broadcasttest.
MY_BROADCAST");
sendBroadcast(intent);
}
});
……
}
……
}
可以看到,我们在按钮的点击事件里面加入了发送自定义广播的逻辑。
首先构建出了一个Intent对象,并把要发送的广播的值传入,然后调用了Context的sendBroadcast()方法将广播发送出去,这样所有监听com.example.broadcasttest.MY_BROADCAST这条广播的广播接收器就会收到消息。
此时发出去的广播就是一条标准广播。
7.如何接收系统广播消息?
请编程加以说明。
其实只需要新建一个类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法就行了。
这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑就可以在这个方法中处理。
registerReceiver(BroadcastReceiver,intentFilter);--oncreate()
unregisterReceiver(BroadcastReceiver);--ondestroy()
8.什么是观察者模式?
观察者模式的使用场景是怎样的?
观察者模式的优缺点是什么?
试编程加以说明。
●定义:
定义对象间一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新
●使用场景:
Ø关联行为场景。
注意的是,关联行为是可拆分的,而不是组合关系。
Ø事件多级触发场景
Ø跨系统的消息交换场景,如消息队列的处理机制
●优点:
Ø观察者和被观察这之间是抽象耦合的
Ø建立一套触发机制
●缺点:
Ø需要考虑下开发效率和运行效率
9.什么是装饰模式?
装饰模式的使用场景是怎样的?
装饰模式的优缺点是什么?
试编程加以说明。
●装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
●装饰器模式的应用场景:
(1)需要扩展一个类的功能。
(2)动态的为一个对象增加功能,而且还能动态撤销。
(继承不能做到这一点,继承的功能是静态的,不能动态增删。
)
●缺点:
产生过多相似的对象,不易排错。
●优点:
Ø装饰类和被装饰类可以独立发展,而不会互相耦合
Ø装饰模式是继承关系的一个替代方案
Ø装饰模式可以动态地扩展为一个实现类的功能
10.Executor、ExecutorService和Executors的区别是什么?
●Executor是一个简单的标准化接口,用于定义类似于线程的自定义子系统,包括线程池、异步IO和轻量级任务框架。
根据所使用的具体Executor类的不同,可能在新创建的线程中,现有的任务执行线程中,或者调用execute()的线程中执行任务,并且可能顺序或并发执行。
●ExecutorService提供了多个完整的异步任务执行框架。
ExecutorService管理任务的排队和安排,并允许受控制的关闭。
●Executors类提供大多数Executor的常见类型和配置的工厂方法,以及使用它们的几种实用工具方法
●Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。
真正的线程池接口是ExecutorService。
ExecutorService继承Executor。
Executors类为创建ExecutorService提供了便捷的工厂方法。
11.为什么说Executors类为创建ExecutorService提供了便捷的工厂方法?
要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。
(1)newCachedThreadPool:
创建一个可缓存的线程池。
如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能地添加新线程来处理任务。
此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
(2)newFixedThreadPool:
创建固定大小的线程池。
每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
(3)newSingleThreadExecutor:
创建一个单线程的线程池。
这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。
如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。
此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
(4)newScheduledThreadPool:
创建一个定长线程池,此线程池支持定时以及周期性执行任务的需求。
12.MyBatis与JDDC相比的优势是什么?
(1)数据库连接不再过于频繁。
(2)SQL语句比较集中
(3)SQL语句参数比较灵活
(4)支持结果映射和结果缓存。
(5)SQL重用度提高。
(6)相对安全
13.将MyBatis引入到项目中都有哪些步骤?
(1)引入MyBatis的JAR包;
(2)配置MyBatis的XML配置文件;
(3)编写映射接口和SQL映射XML文件;
(4)在应用中使用接口,获得结果。
14.Fragment的生命周期是什么?
试编程加以说明。
(1)当一个Fragment被创建的时候,它会经历以下状态:
onAttach()→onCreate()→onCreateView()→onActivityCreated()。
(2)当这个Fragment对用户可见的时候,它会经历以下状态:
onStart()→onResume()。
(3)当这个Fragment进入后台的时候,它会经历以下状态:
onPause()→onStop()。
(4)当这个Fragment被销毁了(或者持有它的Activity被销毁了),它会经历以下状态:
onPause()→onStop()→onDestroyView()→onDestroy()→onDetach()。
(5)一旦Activity进入Resumed状态(也就是Running状态),你就可以自由地添加和删除Fragment了。
因此,只有当Activity在Resumed状态时,Fragment的生命周期才能独立地运转,其它时候是依赖于Activity的生命周期变化的。
15.如何把Fragment加入到Activity中?
试编程加以说明。
当Fragment被加入Activity中时,它会处在对应的ViewGroup中。
加载方式①:
通过Activity的布局文件将Fragment加入Activity
加载方式②:
通过编程的方式将Fragment加入到一个ViewGroup中。
16.如何安装配置Maven?
请简要加以说明。
1.安装JDK
2.下载Maven
3.配置环境变量
4.给Maven添加本地仓库
5.配置用户范围settings.xml
6.错误处理
7.设置MAVEN_OPTS环境变量
17.何为Maven坐标?
何为Maven仓库?
如何编写POM?
●坐标:
maven的坐标通过5个元素进行定义,其中groupId、artifactId、version是必须的,packaging是可选的(默认为jar),classifier是不能直接定义的。
✧groupId:
定义当前Maven项目所属的实际项目,跟Java包名类似,通常与域名反向一一对应。
✧artifactId:
定义当前Maven项目的一个模块,默认情况下,Maven生成的构件,其文件名会以artifactId开头,如hibernate-core-3.6.5.Final.jar。
✧version:
定义项目版本。
✧packaging:
定义项目打包方式,如jar,war,pom,zip,……,默认为jar。
✧classifier:
定义项目的附属构件,如hibernate-core-3.6.6.Final-sources.jar,hibernate-core-3.6.6.Final-javadoc.jar,其中sources和javadoc就是这两个附属构件的classifier。
classifier不能直接定义,通常由附加的插件帮助生成。
●仓库:
在Maven的术语中,仓库是一个位置(place),例如目录,可以存储所有的工程jar文件、libraryjar文件、插件或任何其他的工程指定的文件。
Maven仓库有三种类型:
∙本地(local)
∙中央(central)
∙远程(remote)
Maven仓库就是放置所有JAR文件(WAR,ZIP,POM等等)的地方,所有Maven项目可以从同一个Maven仓库中获取自己所需要的依赖JAR,这节省了磁盘资源。
●编写POM
就像Make的Makefile、Ant的build.xml一样,Maven项目的核心是pom.xml。
POM(ProjectObjectModel,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。
现在先为HelloWorld项目编写一个最简单的pom.xml。
首先创建一个名为helloworld的文件夹,打开该文件夹,新建一个名为pom.xml的文件,输入其内容,如代码清单3-1所示。
代码清单3-1HelloWorld的POM
1.
xml version="1.0" encoding="UTF-8"?
>
2.//maven.apache.org/POM/4.0.0"
3.xmlns:
xsi="http:
//www.w3.org/2001/XMLSchemainstance"
4.xsi:
schemaLocation="http:
//maven.apache.org/POM/4.0.0
5.http:
//maven.apache.org/mavenv4_0_0.xsd">
6.4.0.0
7.com.juvenxu.mvnbook
8.helloworld
9.1.0SNAPSHOT
10.Maven Hello World Project
11.
代码的第一行是XML头,指定了该xml文档的版本和编码方式。
紧接着是project元素,project是所有pom.xml的根元素,它还声明了一些POM相关的命名空间及xsd元素,虽然这些属性不是必须的,但使用这些属性能够让第三方工具(如IDE中的XML编辑器)帮助我们快速编辑POM。
根元素下的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven2及Maven3来说,它只能是4.0.0。
这段代码中最重要的是包含groupId、artifactId和version的三行。
这三个元素定义了一个项目基本的坐标,在Maven的世界,任何的jar、pom或者war都是以基于这些基本的坐标进行区分的。
groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联。
譬如在googlecode上建立了一个名为myapp的项目,那么groupId就应该是com.googlecode.myapp,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp。
本书中所有的代码都基于groupIdcom.juvenxu.mvnbook。
artifactId定义了当前Maven项目在组中唯一的ID,我们为这个HelloWorld项目定义artifactId为helloworld,本书其他章节代码会分配其他的artifactId。
而在前面的groupId为com.googlecode.myapp的例子中,你可能会为不同的子项目(模块)分配artifactId,如myapputil、myappdomain、myappweb等。
顾名思义,version指定了HelloWorld项目当前的版本——1.0SNAPSHOT。
SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。
随着项目的发展,version会不断更新,如升级为1.0、1.1SNAPSHOT、1.1、2.0等。
6.5节会详细介绍SNAPSHOT,第13章会介绍如何使用Maven管理项目版本的升级发布。
最后一个name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但还是推荐为每个POM声明name,以方便信息交流。
没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦,或者正交性。
这在很大程度上避免了Java代码和POM代码的相互影响。
比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码;而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。
参考书:
《Android编程权威指南》
18.FragmentManager是如何管理fragment并将它们的视图添加到activity的视图层级结构中的?
P122-7.6
19.android:
l