banner
NEWS LETTER

Android基础

Scroll down

Android 基础

一、Android 基本常识

  1. 写10个简单的linux命令
mkdir 创建文件夹
rmdir 删除文件夹
rm 删除文件
mv 移动文件
cp 拷贝文件
cat 查看文件
tail 查看文件尾部
more 分页查看文件
cd 切换当前目录
ls 列出文件清单
reboot 重启
date 显示日期
cal 显示日历
ps 查看系统进程相当于 windows 的任务管理器
ifconfig 配置网络
  1. 什么是 ANR 如何避免它?

    在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应
    (ANR:ApplicationNotResponding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,
    并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
    不同的组件发生ANR的时间不一样,主线程(Activity、Service)是5秒,BroadCastReceiver是10秒。
    解决方案:将所有耗时操作,比如访问网络,Socket通信,查询大量SQL语句,复杂逻辑计算等都放在子线程中去,
    然后通过handler.sendMessage、runonUITread、AsyncTask等方式更新UI。无论如何都要确保用户界面操作的流畅度。
    如果耗时操作需要让用户等待,那么可以在界面上显示进度条。

  2. Android 的四大组件都需要在清单文件中注册吗?

    Activity、Service、ContentProvider如果要使用则必须在AndroidManifest.xml中进行注册,
    而BroadcastReceiver则有两种注册方式,静态注册和动态注册。其中静态注册就是指在AndroidManifest.xml中进行注册,而动态注册时通过代码注册。

  3. sp 频繁操作有什么后果?sp 能存多少数据?

    Sp的底层是由xml来实现的,操作sp的过程就是xml的序列化和解析的过程。Xml是存储在磁盘上的,因此考虑到需要I/O速度问题,
    sp不适宜频繁操作。同时序列化xml是就是将内存中的数据写到xml文件中,由于dvm的内存是很有限的,因此单个sp文件不建议太大,
    具体多大是没有一个具体的要求的,但是我们知道DVM堆内存也就是16M,因此数据大小肯定不能超过这个数字的。
    其实sp设置的目的就是为了保存用户的偏好和配置信息的,因此不要保存太多的数据。

二、Activity

  1. 什么是 Activity?

    四大组件之一,通常一个用户交互界面对应一个activity。activity是Context的子类,同时实现了window.callback和keyevent.callback,
    可以处理与窗体用户交互的事件。常见的Activity类型有FragmentActivitiy,ListActivity,TabAcitivty等。
    如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity。

  2. 请描述一下 Activity 生命周期

    Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,
    这些回调方法包括:onCreateonStartonResumeonPauseonStoponDestroy其实这些方法都是两两对应的,
    onCreate创建与onDestroy销毁;onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause;这6个方法是相对应的,
    那么就只剩下一个onRestart方法了,这个方法在什么时候调用呢?
    答案就是:在Activity被onStop后,但是没有被onDestroy,在再次启动此Activity时就调用onRestart(而不再调用onCreate)方法;
    如果被onDestroy了,则是调用onCreate方法。

  3. Activity 的状态都有哪些?

    a) foreground activity
    b) visible activity
    c) background activity
    d) empty process

  4. 如何保存 Activity 的状态?

    Activity的状态通常情况下系统会自动保存的,只有当我们需要保存额外的数据时才需要使用到这样的功能。
    一般来说,调用onPause()和onStop()方法后的activity实例仍然存在于内存中,activity的所有信息和状态数据不会消失,
    当activity重新回到前台之后,所有的改变都会得到保留。但是当系统内存不足时,调用onPause()和onStop()方法后的activity可能会被系统摧毁,
    此时内存中就不会存有该activity的实例对象了。如果之后这个activity重新回到前台,之前所作的改变就会消失。为了避免此种情况的发生,
    我们可以覆写onSaveInstanceState()方法。onSaveInstanceState()方法接受一个Bundle类型的参数,开发者可以将状态数据存储到这个Bundle对象中,
    这样即使activity被系统摧毁,当用户重新启动这个activity而调用它的onCreate()方法时,上述的Bundle对象会作为实参传递给onCreate()方法,
    开发者可以从Bundle对象中取出保存的数据,然后利用这些数据将activity恢复到被摧毁之前的状态。
    需要注意的是,onSaveInstanceState()方法并不是一定会被调用的,因为有些场景是不需要保存状态数据的.
    比如用户按下BACK键退出activity时,用户显然想要关闭这个activity,此时是没有必要保存数据以供下次恢复的,
    也就是onSaveInstanceState()方法不会被调用.如果调用onSaveInstanceState()方法,调用将发生在onPause()或onStop()方法之前。

1
2
3
4
5
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
}
  1. 两个Activity之间跳转时必然会执行的是哪几个方法?(重要)

    一般情况下比如说有两个activity,分别叫A,B,当在A里面激活B组件的时候,
    A会调用onPause()方法,然后B调用onCreate(),onStart(),onResume()。
    这个时候B覆盖了窗体,A会调用onStop()方法.如果B是个透明的,或者是对话框的样式,就不会调用A的onStop()方法。
    如下图,打开一个MainActivity,然后点击MainActivity中的按钮跳转到SecondActivity的日志。

  1. 横竖屏切换时 Activity 的生命周期

    此时的生命周期跟清单文件里的配置有关系。
    1、不设置 Activity 的 android:configChanges 时,切屏会重新调用各个生命周期
    默认首先销毁当前 activity,然后重新加载。
    如下图,当横竖屏切换时先执行 onPause/onStop 方法

2、设置 Activity 的 android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调
用各个生命周期,只会执行 onConfigurationChanged 方法。
通常在游戏开发, 屏幕的朝向都是写死的。
  1. 如何将一个 Activity 设置成窗口的样式?

    只需要给我们的 Activity 配置如下属性即可。

1
android:theme="@android:style/Theme.Dialog"
  1. 请描述一下 Activity 的启动模式都有哪些以及各自的特点

    启动模式(launchMode)在多个 Activity 跳转的过程中扮演着重要的角色,它可以决定是否生成新的 Activity 实例,
    是否重用已存在的 Activity 实例,是否和其他 Activity 实例公用一个 task 里。这里简单介绍一下 task 的概念,task 是
    一个具有栈结构的对象,一个 task 可以管理多个 Activity,启动一个应用,也就创建一个与之对应的 task。
    Activity 一共有以下四种 launchMode:

    1. standard
    2. singleTop
    3. singleTask
    4. singleInstance
      我们可以在 AndroidManifest.xml 配置的 android:launchMode 属性为以上四种之一即可。
      下面我们结合实例一一介绍这四种 lanchMode:

standard:

standard模式是默认的启动模式,不用为<activity>配置android:launchMode属性即可,当然也可以指定值为standard。
standard 模式的原理如下图所示:


如图所示,每次跳转系统都会在task中生成一个新的 FirstActivity 实例,并且放于栈结构的顶部,当我们按下后退键
时,才能看到原来的 FirstActivity 实例。
这就是 standard 启动模式,不管有没有已存在的实例,都生成新的实例。

singleTop

我们在上面的基础上为<activity>指定属性 android:launchMode="singleTop",系统就会按照 singleTop 启
动模式处理跳转行为。我们重复上面几个动作,将会出现下面的现象:

我们看到这个结果跟standard有所不同,三个序列号是相同的,也就是说使用的都是同一个FirstActivity实例;
如果按一下后退键,程序立即退出,说明当前栈结构中只有一个Activity实例。singleTop模式的原理如下图所示:


正如上图所示,跳转时系统会先在栈结构中寻找是否有一个FirstActivity实例正位于栈顶,如果有则不再生成新的,
而是直接使用。也许朋友们会有疑问,我只看到栈内只有一个Activity,如果是多个Activity怎么办,
如果不是在栈顶会如何?我们接下来再通过一个示例来证实一下大家的疑问。
我们再新建一个Activity命名为SecondActivity,
我们看到,两个 FirstActivity 的序列号是不同的,证明从 SecondActivity 跳转到 FirstActivity 时生成了新的
FirstActivity 实例。原理图如下:

我们看到,当从 SecondActivity 跳转到 FirstActivity 时,系统发现存在有 FirstActivity 实例,但不是位于栈顶,
于是重新生成一个实例。
这就是 singleTop 启动模式,如果发现有对应的 Activity 实例正位于栈顶,则重复利用,不再生成新的实例。

singleTask

在上面的基础上我们修改 FirstActivity 的属性 android:launchMode="singleTask"。演示的结果如下:
我们注意到,在上面的过程中,FirstActivity 的序列号是不变的,SecondActivity 的序列号却不是唯一的,说明
从 SecondActivity 跳转到 FirstActivity 时,没有生成新的实例,但是从 FirstActivity 跳转到 SecondActivity 时生成
了新的实例。singleTask 模式的原理图如下图所示:


在图中的下半部分是SecondActivity跳转到FirstActivity后的栈结构变化的结果,我们注意到,SecondActivity消失了,
没错,在这个跳转过程中系统发现有存在的FirstActivity实例,于是不再生成新的实例,而是将FirstActivity之上的Activity实例统统出栈,
将FirstActivity变为栈顶对象,显示到幕前。也许朋友们有疑问,如果将SecondActivity也设置为singleTask模式,
那么SecondActivity实例是不是可以唯一呢?在我们这个示例中是不可能的,因为每次从SecondActivity跳转到FirstActivity时,
SecondActivity实例都被迫出栈,下次等FirstActivity跳转到SecondActivity时,找不到存在的SecondActivity实例,
于是必须生成新的实例。但是如果我们有ThirdActivity,让SecondActivity和ThirdActivity互相跳转,那么SecondActivity实例就可以保证唯一。
这就是singleTask模式,如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈吗,使此Activity实例成为栈顶对象,显示到幕前。

singleInstance

这种启动模式比较特殊,因为它会启用一个新的栈结构,将Activity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。
我们修改FirstActivity的launchMode="standard",SecondActivity的launchMode="singleInstance",由于涉及到了多个栈结构,
我们需要在每个Activity中显示当前栈结构的id,所以我们为每个Activity添加如下代码:
1
2
TextView taskIdView = (TextView) findViewById(R.id.taskIdView);
taskIdView.setText("current task id: " + this.getTaskId());
我们发现这两个 Activity 实例分别被放置在不同的栈结构中,关于 singleInstance 的原理图如下


我们看到从FirstActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,
再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到FirstActivity,这个时候系统会在原始栈结构中生成一个FirstActivity实例,
然后回退两次,注意,并没有退出,而是回到了SecondActivity,为什么呢?是因为从SecondActivity跳转到FirstActivity的时候,
我们的起点变成了SecondActivity实例所在的栈结构,这样一来,我们需要“回归”到这个栈结构。
如果我们修改FirstActivity的launchMode值为singleTop、singleTask、singleInstance中的任意一个,
流程将会如图所示:

singleInstance启动模式可能是最复杂的一种模式,为了帮助大家理解,我举一个例子,假如我们有一个share应用,
其中的ShareActivity是入口Activity,也是可供其他应用调用的Activity,我们把这个Activity的启动模式设置为singleInstance,
然后在其他应用中调用。我们编辑ShareActivity的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
<activity
android:name=".ShareActivity"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.SINGLE_INSTANCE_SHARE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
然后我们在其他应用中这样启动该 Activity:
1
2
Intent intent = new Intent("android.intent.action.SINGLE_INSTANCE_SHARE");
startActivity(intent);
当我们打开ShareActivity后再按后退键回到原来界面时,ShareActivity做为一个独立的个体存在,如果这时我们打开share应用,
无需创建新的ShareActivity实例即可看到结果,因为系统会自动查找,存在则直接利用。大家可以在ShareActivity中打印一下taskId,
看看效果。关于这个过程,原理图如下:

  1. 一个启动模式为 singleTop 的 activity,如果再试图启动会怎样? 面试官想问的是onNewIntent()
    Activity 有一个 onNewIntent(Intent intent)回调方法,该方法我们几乎很少使用,导致已经将其忽略掉
    该方法被启动模式设置为“singleTop”的Activity回调,或者当通过设置Intent.FLAG_ACTIVITY_SINGLE_TOP的Intent启动Activity时被回调。
    在任何情况下,只要当栈顶的Activity被重新启动时没有重新创建一个新的Activity实例而是依然使用该Activity对象,那么onNewIntent(Intent)方法就会被回调。
    当一个Activity接收到新Intent的时候会处于暂停状态,因此你可以统计到onResume()方法会被再次执行,当然这个执行是在onNewIntent之后的。
    注意:如果我们在Activity中调用了getIntent()方法,那么返回的Intent对象还是老的Intent(也就是第一次启动该Activity时的传入的Intent对象),
    但是如果想让getIntent()返回最新的Intent,那么我们可以通过setIntent(Intent)方法设置。

三、Service

  1. Service是否在mainthread中执行,service里面是否能执行耗时的操作?
    默认情况,如果没有显示的指service所运行的进程,Service和activity是运行在当前app所在进程的mainthread(UI主线程)里面。
    service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件)
    特殊情况,可以在清单文件配置service执行所在的进程,让service在另外的进程中执行
1
2
3
4
5
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
  1. Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?
    Activity通过bindService(Intentservice,ServiceConnectionconn,intflags)跟Service进行绑定,
    当绑定成功的时候Service会将代理对象通过回调的形式传给conn,这样我们就拿到了Service提供的服务代理对象。
    在Activity中可以通过startService和bindService方法启动Service。一般情况下如果想获取Service的服务对象那么肯定需要通过bindService()方法,
    比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么可以使用startService()方法。

  2. 请描述一下 Service 的生命周期
    Service有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同的使用方法生命周期方法也不同。
    非绑定模式:当第一次调用startService的时候执行的方法依次为onCreate()、onStartCommand(),(onStart())当Service关闭的时候调用onDestory方法。
    绑定模式:第一次bindService()的时候,执行的方法为onCreate()、onBind()解除绑定的时候会执行onUnbind()、onDestory()。
    上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还必须注意Service实例只会有一个,
    也就是说如果当前要启动的Service已经存在了那么就不会再次创建该Service当然也不会调用onCreate()方法。
    一个Service可以被多个客户进行绑定,只有所有的绑定对象都执行了onBind()方法后该Service才会销毁,
    不过如果有一个客户执行了onStart()方法,那么这个时候如果所有的bind客户都执行了unBind()该Service也不会销毁。

    Service的生命周期图如下所示,帮助大家记忆。

其他文章
目录导航 置顶
  1. 1. Android 基础
请输入关键词进行搜索