一. 请描述下Activity的生命周期?
相信图1-1很多人都看过,我再总结下:
(1)、onCreate()——执行Activity的创建工作。每个Activity生命周期都会最先执行且执行一次的方法。
(2)、onRestart()——已经被初始化的Activity重新回到可见状态时执行的回调。
(3)、onStart()——当Activity进入可见状态但不可操控时执行的回调。
(4)、onResume()——当Activity进入可操控状态时执行的回调。
(5)、onPause()——当Activity离开可操控状态时执行的回调。在包括此状态之后的所有状态下,Activity都有可能以为内存不足被系统回收,若要做数据存储,推荐在这做。
(6)、onStop()——当Activity被其它Activity遮盖掉时执行的回调。特别注意,此时遮盖的Activity已执行完onCreate()。
(7)、onDestory()——当Activity被程序finish或者被系统kill掉后执行的回调。
图1-1:
二、如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
重写onSaveInstanceState(Bundle bundle)方法,把要保存的数据放入bundle中,在发生Activity“可能”被销毁的情况下(Home、电源键、跳转)系统回调用该回调,之后在重写执行onCreate时,从其参数中取出值。注意:用户主动销毁不会执行onSaveInstanceState,入BACK。
三、如何将一个Activity设置成窗口的样式?如何将Activity设置为半透明?
在Androidfest.xml中
窗口模式:android:theme="@android:style/Theme.Dialog"
透明:android:theme="@android:style/Theme.Translucent"
可调节透明度:
1、android:theme="@style/自定义样式",
2、自定义样式继承@android:style/Theme.Translucent,
3、设置bg为#00ffffff-#ffffffff,颜色代码为八位,前两位透明度00-FF,透明-不透明,后面六位RBG颜色代码。
四、如何退出Activity?如何安全退出已调用多个Activity的Application?
单个:finish();
多个:
1、记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
2、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
3、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
五、请介绍下Android中常用的五种布局?
1、FrameLayout(框架布局):一层堆一层的遮盖,大小可控,位置固定左上角(和绝对布局的区别)
2、LinearLayout (线性布局):分为横向和纵向线性布局,布局内子元素成一行(列)依次排列。另外子元素宽度可以用layout_weight熟悉控制,值越小,元素所占宽度(高度)越大。
3、AbsoluteLayout(绝对布局):类似框架布局,一层堆一层,大小可控,位置可控。
4、RelativeLayout(相对布局):可以控制元素位置相对于另外一个元素的位置。
5、TableLayout(表格布局):事先设定布局子元素的行和列,子元素可以同时占多个相邻行(列)的格子。
六、 请介绍下Android的数据存储方式?
1、SQLite: SQLite是一个轻量级的数据库,支持基本SQL语法,是常被采用的一种数据存储方式。Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的API。
2、SharedPreference: 除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml文件,常用于存储较简单的参数设置。
3、File: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。
4、ContentProvider: Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个Content Provider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享时,就需要使用Content Provider为这些数据定义一个URI,然后其他的应用程序就通过Content Provider传入这个URI来对数据进行操作。
5、网络:很多人容易忽视这项,但是实际中,网络是很多非游戏类APP的最主要数据存储方式之一。
七、请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系?
八、AIDL的全称是什么?如何工作?能处理哪些类型的数据?
AIDL的英文全称是Android Interface Define Language
当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的
A工程:
首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。
说明一:aidl文件的位置不固定,可以任意
然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。
其次需要在AndroidManifest.xml文件中配置MyService类,代码如下:
为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。
说明:AIDL并不需要权限
B工程:
首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务
绑定AIDL服务就是将RemoteService的ID作为intent的action参数。
说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件
bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE);
ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。
九、注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意?
在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,不过我们可以搞一个信息防火墙。具体的代码:
public class SmsBroadCastReceiverextends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle = intent.getExtras();
Object[] object = (Object[])bundle.get("pdus");
SmsMessage sms[]=new SmsMessage[object.length];
for(int i=0;i
{
sms[0] =SmsMessage.createFromPdu((byte[])object);
Toast.makeText(context, "来自"+sms.getDisplayOriginatingAddress()+"的消息是:"+sms.getDisplayMessageBody(),Toast.LENGTH_SHORT).show();
}
//终止广播,在这里我们可以稍微处理,根据用户输入的号码可以实现短信防火墙。
abortBroadcast();
}
}
当实现了广播接收器,还要设置广播接收器接收广播信息的类型,这里是信息:android.provider.Telephony.SMS_RECEIVED
我们就可以把广播接收器注册到系统里面,可以让系统知道我们有个广播接收器。这里有两种,一种是代码动态注册:
//生成广播处理
smsBroadCastReceiver = newSmsBroadCastReceiver();
//实例化过滤器并设置要过滤的广播
IntentFilter intentFilter = newIntentFilter("android.provider.Telephony.SMS_RECEIVED");
//注册广播
BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver,intentFilter);
一种是在AndroidManifest.xml中配置广播
package="spl.broadCastReceiver"
android:versionCode="1"
android:versionName="1.0">
android:label="@string/app_name">
两种注册类型的区别是:
1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
十、什么是ANR?如何避免它?ANR:应用程序没有响应(Application Not Responding),五秒
在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:
1、对输入事件(如按键、触摸屏事件)的响应超过5秒
2、意向接受器(intentReceiver)超过10秒钟仍未执行完毕
3、Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。
因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。