史上最详细 最基础的 android 面试 知识点总结(一)
1. 什么是Activity ?
这样的问题 回答的时候 ,首先 Activity 是 四大组件之一,是一个view 对象的容器,可以用来展现一个界面,通过 setcontentView() ,//方法来 设置要显示的布局
activity 是 上下文对象 Context的子类 同时 实现了 window.callback 和 keyevent.callback 这两个接口, 所以 activity 可以响应 与处理 窗体与用户的交互事件,以及与键盘相关的事件。(Context 上下文对象, 其实就是一个变量 ,维护了android 应用 一些公共环境的引用,比如 通过 上下文 ,我们就可以拿到 资源管理的服务,系统的资产目录,或者通过getcachdir()获取当前应用运行所在的目录,一旦拿到了上下文,就相当于拿到了已知相关环境的引用)。拿到activity 就可以重写 onkeydown ontouchevent 去处理窗体事件。
2. 请描述下 activity 的生命周期?
生命周期,描述的是一个类,从创建(new 出来)到死亡(垃圾回收)过程中 执行的方法, 在这个过程中,对于不同的生命阶段会调用不同的方法。
activity 从创建打销毁有多种状态,从一种状态到另一种状态 会激发相应的方法。这些回调方法包括,oncreate ondestroy onstart onstop onresume onpause, 这些方法都是两两对应的 oncreate 创建 与 ondestroy 销毁。 onstart 可见 与 onstop 不可见 onresume可编辑(获取到焦点)与 onpause 失去焦点。 还有一种情况 当 activity 被 stop掉 ,但是没有被 destroy ,再次启动此 activity 时候就会调用 onrestart 方法(而不调用 oncreate)。如果被destroy 了 那么就会调用 oncreate。
结合项目讲 ,为了保证每次进入activity 看到的界面是最新的 我们就把这操作 写到onstart 方法里。或者检查网络(每次进入界面检查是否联网)。 视频播放 ,比如 看着视频,有电话打进来,那么我们就需要把视频播放器 暂停掉,这个操作放在onpause 或者onstop 方法里面 比较好,然后在onresume 里面 在恢复 播放。
常用的c 就是以上这些方法 还有一些方法可以了解下 当做扩展 比如 onpostresume onpostcreate 这是系统自己调用的, 在执行 onresume oncreate 的时候会去执行。
3. activity 在跳转的时候会执行哪些方法。
一般 从A activity 跳转到 B activity 首先 A activity 会失去焦点(onpause) 变为不可见 (onstop)B activity 在 创建 (oncreate)可见(onstart) 获得焦点(onreusme),但是一些特殊情况,比如 把 B activity 背景设为透明,或者 是 dialog 样式,那么 A activity 在失去焦点后,还是可见的,所以不会执行 onstop 方法。
4. 横竖屏 切换时 activity 的生命周期。
这个生命周期 跟清单文件 里面的配置有关。
1.不设置Activity的 android: configchanges 时 ,切换屏幕会重新调用 个生命周期方法 首先onpause onstop ondestroy 然后 oncreate onstart onresume .
如果我们 设置 configChanges 设置为 android:configChanges="orientation|keyboardHidden"时,默认 就不会销毁 在创建,但是 我发现 在我的手机上,打开 自动旋转屏,一样还是会销毁在创建, 关闭旋转屏 就没问题。 一般开发中我们都会把 activity 设置成 orentation的。
5. 如何退出 activity ,如何安全退出 调用多个activity 的application?
退出 activity 直接调用finish 方法(比如用户点击back键 就是退出一个activity ),退出activity 会执行 ondestroy 方法。
1,异常 退出, 要退出的时候抛出一个异常 比如空指针 使程序 force close ,比如
import java.lang.Thread.UncaughtExceptionHandler;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
public class MainActivity extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread.setDefaultUncaughtExceptionHandler(new ExtAppExceptionHandler());//Sets the default uncaught exception handler. This handler is invoked in case any Thread dies due to an unhandled exception
findViewById(R.id.btn).setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
String s;
public void extApp(){
// try {
s.equals("aaa");// 这里 s 未进行初始化,肯定会抛出异常, 如果我们要退出 程序 就要拦截掉弹出的 crash 窗口(注意不要自己捕获,否则就会拦截掉)
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
class ExtAppExceptionHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread thread, Throwable ex) {
android.os.Process.killProcess(android.os.Process.myPid());// 这里杀死当前进程。退出app
}
}
@Override
public void onClick(View v) {
extApp();
}
}
2, 可以定义一个集合,每次进入activity的时候 将当前activity 加入到 集合中, 在每个activity 的ondestroy 方法中 remove掉 添加进的当前activity。(以上 可在baseactivity 中), 然后在我们退出app的时候 便利 这个集合,把每一个都finish()。
3. 我们也可以通过广播的方式, 在 每个activity 中注册一个广播, 当我们 退出 的时候 发送一个广播 然后finish 掉 每个activity。
以上三种是比较常用的关闭app的操作。
当问到 对于 activity的理解 问题 可以回答以上几点。
6. service 是否在main thread 中, service 中能否进行耗时操作。
默认 情况,没有显示的指定 service 所在的线程,那么service 和 activity 是运行在当前app 所在进程的 main thread(ui 线程)中的,所以 不可以做耗时操作。
如果service 中要做耗时操作,那么可以在service 中开启一个子线程,或者 使用intentservice (intentservice onCreate方法中 初始化了一个ServiceHandler,在onHandleIntent这个接口中 我们可以执行耗时操作 )让 service 不在主线程中执行,需要在清单文件中注册 service android :process="other process"
7. 两个activity 之间 传递数据 方式。
一般通过 intent。 intent 可以传递 基本类型 以及 对象 (实现 序列化 或者邮包)或者bundle bundle 实现了Bundle implements Parcelable内部维护了一个 hashmap。可以把bundle理解成map put key value 方式存储数据。
8. 怎么在启动一个activity 的时候 启动一个service.
在activity 的oncreate 方法中 调用 startservice 方法 即可。
9 同一个程序中的 不通过activity 是否可以放到不同的任务栈中。
可以 在开启一个新的activity 的时候通过 intent 给activity 设置intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);即可。注意 当我们在 service 或者broadcastreceiver 中开启一个 activity 时一定要注意设置flag 因为在这两个组件中默认是没有任务栈的。(结合 launchmode )
10 service 的启动方式 。
服务 有两种开启方式 一种是 startservice 一种是 bindservice。
startservice 一旦被开启 与调用者 就没有关系了。这个服务 会长期的在后台运行。
bindservice 是 将调用者 与 服务绑定,如果开启这个服务的 activity 被销毁,那么这个服务也相应的要挂掉
bindservice 有一个特点 就是 可以让我们间接地 调用服务里的方法 bindService(Intent service, ServiceConnection conn, int flags) serviceConnection 中两个方法onServiceConnected(ComponentName name, IBinder service) onServiceDisconnected(ComponentName name)
11 描述下 service 的生命周期,service有哪些启动方法 有什么区别,怎么停止service。
service的生命周期 比activity 少,常用的 就只有 oncreate onstartCommand onbind onunbind ondestroy 这些。
通常两种启动方式一种是 startservice 一种是 bindservice。
startservice 一旦被开启 与调用者 就没有关系了。这个服务 会长期的在后台运行。’
bindservice 是 将调用者 与 服务绑定,如果开启这个服务的 activity 被销毁,那么这个服务也相应的要挂掉
bindservice 有一个特点 就是 可以让我们间接地 调用服务里的方法 bindService(Intent service, ServiceConnection conn, int flags) serviceConnection 中两个方法onServiceConnected(ComponentName name, IBinder service) onServiceDisconnected(ComponentName name)
两种启动方式 对于 service 生命周期有不同的影响
通过 startservice 方式
service会经历 oncreate onstartCommand 然后处于运行状态,停止时 ondestroy 注意如果你将服务写成内部类的话(广播 用内部类 同理) 这里 一定要将 服务类前面加上static 修饰 否则会报 no empty constructor 这样一个错,不能初始化这个服务,还有在清单文件中声明 内部类的时候 格式要类似 <service android:name=".MainActivity$MyService"/> 外部类 mainactivity+内部类
如果 你通过 bindService 方式 启动 服务 。
那么相应的 会执行 oncreate onBInd 当activity 退出时会执行 onunbInd ondestroy、
PS : 记得 我们在activity 的 Ondestroy 方法中要 执行下stopService 或者unbindService, 否则 会报错
service的 一个原则 无论是 先start 还是 bind oncreate 方法只会执行一次,换句话说, 无论你 执行了多少次 startService 或者 bindservice service 只被创建一次、
多次调用startService onstart 方法会调用多次 , 多次调用 bindService onbind 方法 只会执行一次 多次 destroy 也只执行一次。 多次调用unbindService 会报异常。
12 什么是 IntentService ,有什么优点?
普通的Service 默认运行在 UI 线程中, 而 intentService内部维护了 一个handler 我们使用 intentservice 的时候 只要去实现 onhandleIntent 接口 可以在这接口做耗时操作, 注意 我们 使用 intentservice时候 要自己添加一个空参数的构造方法,否则会在初始化 intentService的时候报错 InstantiationException。
intentService 就是 android 提供的一个带有异步处理的service 类。
13 什么时候使用service?
对于谷歌开发者文档中Processes 根据优先级的高低分为, 前台进程(Foreground process) 可见进程( Visible process) 服务进程(Service process) 后台进程( Background process)空进程( Empty process)
当系统内存不足的 时候 低优先级的进程 容易被回收掉 优先级越高,越靠后被回收掉
关于
service process 的介绍 :A process that is running a service that has been started with the startService()
method
and does not fall into either of the two higher categories. Although service processes are not directly tied to anything the user sees, they are generally doing things that the user cares about (such as playing music in the background or downloading data on
the network), so the system keeps them running unless there‘s not enough memory to retain them along with all foreground and visible processes.
空进程: 就是 按 back键 退出以后的进程,当系统内存不足时 首先回收 空进程。
后台进程; 就是按 home键 后 应用在后台运行,activity 执行了 onstop 方法, 当系统内存不足 时,可能会试图去回收 后台进程。 当后台进程的activity 被销毁时,会执行 onsavedInstance 方法 。
服务进程: 当一个进程r 中 有服务运行时 比如 应用中开启服务 播放音乐,下载数据,等,系统会尽量维持 有服务的进程 ,知道内存不足时,才会试图去回收 服务进程。这就是为什么有些耗时操作要放在服务中进行,而不是 在activity 中 开启一个子线程,因为activity 优先级比较低,容易被回收, 当前activity 被回收后,当前进程就变成了后台进程 或者空进程,容易被回收。 如果进程被回收了,那么线程也挂掉了,所以 为了保持我们应用在后台一直存在运行,我们一般用service 组件里面 去开启线程执行耗时操作。这样就能保证我们的进程 不会被轻易地回收掉。
前台进程: 就是屏幕直接能看到的,比如launcher 就是一个前台进程,可以响应我们的交互事件
可见进程: 就是 能看到的,比如 我们 将一个mainactivity 设置主题透明,那么这个 应用 就是 前台进程,后面的launcher 就是可见进程。
给 service 设置 setForground(true) 可以使服务类似于 前台进程,能尽量保证 服务不会被回收。 service 的 特点 可以使其在后台一直运行,所以一般耗时操作 放在这里运行,比如 广播接受者 接收到一个广播 要做耗时操作(比如上传资源到服务器),广播接受者的生命周期很短赞,要做耗时操作,就可以在receive 方法里面 开启一个服务
14 描述下 activity intent service 之间的关系
比如 拿网络更新数据来说。 activity 可以显示 最新的数据, 在activity 中 有一个服务 ,去请求 最新的数据,而 intent 可以开启这个service。
15. 请描述一下 broadcastreceiver 。
广播接受者,就是 接受系统 以及 应用 自身 发出的 广播的 对象。比如系统的 开关机,来电 短信。屏幕 亮暗。。。。等等都有定义广播
广播分两种 有序广播 和无需广播 ,有序广播 是一个同步的操作, 无须广播是一个异步的操作
终止一条广播 要在 接受到广播后调用abortbroadcast 方法, 指定的广播接受者 是不能被拦截的 一定会受到广播,(比如 电话拦截,电话 是通过注册 绑定了接受者 一定会受到广播,如果我们要拦截掉,只能 在自己定义的 接受者里面 setResultData(null ); 将数据 置为null. 而无法拦截让电话 不收到广播。
private class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
setResultData(null );
}
}
sendStickyBroadcast(intent): 这是粘性广播,也就表示 阴魂不散的广播,比如 一个普通的广播接受者,如果我们没有注册,那么 就不会接收到广播。一个广播(一般生命周期只有20秒,接收不到,那么就接收不到了)而 sticiky 则不同 我们发送一个 stickky的 广播,那么这个广播会停留一段时间,比如 手机中 网络的广播 开启wifi 需要初始化 网卡,接收网络热点等等,20秒的时间可能不够用,所以这里更改手机网络状况 就用了 sendstickyBroadCast 保证 网卡状态一定会被更新。(这个方法了解即可)wifi 设置。
广播接受者 的注册方式 ,一般有两种
一种是 清单文件中注册 : 注册 receiver 过滤 intentfiler 一旦应用部署到手机上面 就生效了(现在可能需要手动启动一次应用,安装后 未启动过 好像 还不能用,android 安全优化。)
一种是 代码中注册 registReceiver(receiver,filter) (代码注册的广播 必须要执行后 广播才会生效)
发送自定义广播
intent itent=new Intent("com.self.broadcast")
sendBroadCast(intent);
两种注册类型的区别:
静态注册是当程序关闭后,如果有广播发过来,还能启动程序
动态注册的生命周期跟程序的生命周期是一样的,程序关闭后动态注册的广播是不能在接收到广播的
动态注册的优点:在Android的广播机制中,动态注册的优先级高于静态注册的优先级,因此在必要情况下,我们需要动态注册广播接收器。
静态注册的有点:动态注册广播接收器还有一个优点就是当用来注册广播的Activity关闭后,广播也就失效了,同时反映了静态注册广播的一个优势,就是无需担心广播接收器是否关闭,只要设备处于开启状态,广播接收器就能接收。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。