Android面试题汇总

前言:分别从易倒难,好好拿去理解吧

1.请介绍下Android中常用的五种布局?

答: 在Android中,共有五种布局方式,分别是:FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)。

(1)FrameLayout 框架布局,放入其中的所有元素都被放置在最左上的区域,而且无法为这些元素指定一个确切的位置,下一个子元素会重叠覆盖上一个子元素,适合浏览单张图片。 
(2)LinearLayout 线性布局,是应用程序中最常用的布局方式,主要提供控件水平或者垂直排列的模型,每个子组件都是以垂直或水平的方式来定位(默认是垂直)。 
(3)AbsoluteLayout 绝对定位布局,采用坐标轴的方式定位组件,左上角是(0,0)点,往右x轴递增,往下Y轴递增,组件定位属性为android:layout_x 和 android:layout_y来确定坐标。
(4)RelativeLayout 相对布局,根据另外一个组件或是顶层父组件来确定下一个组件的位置。和CSS里面的类似。 
(5)TableLayout 表格布局,类似Html里的Table.使用TableRow来布局,其中TableRow代表一行,TableRow的每一个视图组件代表一个单元格。

2.请介绍下Android的数据存储方式

答:(1)使用SharedPreferences存储数据;它是Android提供的用来存储一些简单配置信息的一种机制,采用了XML格式将数据存储到设备中。只能在同一个包内使用,不能在不同的包之间使用。 
(2)文件存储数据;文件存储方式是一种较常用的方法,在Android中读取/写入文件的方法,与Java中实现I/O的程序是完全一样的,提供了openFileInput()和openFileOutput()方法来读取设备上的文件。 
(3)SQLite数据库存储数据;SQLite是Android所带的一个标准的数据库,它支持SQL语句,它是一个轻量级的嵌入式数据库。 
(4)使用ContentProvider存储数据;主要用于应用程序之间进行数据交换,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。 
(5)网络存储数据;通过网络上提供给我们的存储空间来上传(存储)和下载(获取)我们存储在网络空间中的数据信息。

3. android 中的动画有哪几类,它们的特点和区别是什么?

答:有两种,一种是 Tween(补间) 动画、还有一种是 Frame(帧) 动画。
 ①Tween 动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;
 ②Frame(帧) 动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。

4.请谈谈Activity的生命周期?

答: 在系统中的Activity被一个Activity栈所管理。当一个新的Activity启动时,将被放置到栈顶,成为运行中的Activity,前一个Activity保留在栈中,不再放到前台,直到新的Activity退出为止。Activity有四种本质区别的状态: 
1)在屏幕的前台(Activity栈顶),叫做活动状态或者运行状态(active or running) 
2)如果一个Activity失去焦点,但是依然可见(一个新的非全屏的Activity 或者一个透明的Activity 被放置在栈顶),叫做暂停状态(Paused)。一个暂停状态的Activity依然保持活力(保持所有的状态,成员信息,和窗口管理器保持连接),但是在系统内存极端低下的时候将被杀掉。 
3)如果一个Activity被另外的Activity完全覆盖掉,叫做停止状态(Stopped)。它依然保持所有状态和成员信息,但是它不再可见,所以它的窗口被隐藏,当系统内存需要被用在其他地方的时候,Stopped的Activity将被杀掉。 
4)如果一个Activity是Paused或者Stopped状态,系统可以将该Activity从内存中删除,Android系统采用两种方式进行删除,要么要求该Activity结束,要么直接杀掉它的进程。当该Activity再次显示给用户时,它必须重新开始和重置前面的状态。 
5)Activity提供了7个生命周期方法: onCreate(),onStart(),onResume(),onPause(),onStop(),onDestory(),onRestart()。在这七个生命周期方法中有三个关键的循环。从onCreate(Bundle)开始到onDestroy()结束。Activity在onCreate()设置所有的“全局”状态,在 onDestory()释放所有的资源。 首先我们运行程序,这是打开MainActivity依次调用onCreate->onStart->onResume,这时MainActivity在栈顶,与我们交互的Activity都在栈顶。然后我按下返回键,则会依次调用onPause->onStop->onDestory。这属于一个完整的生命周期。

5.请描述下Activity的生命周期

答:activity的生命周期方法有:onCreate()、onStart()、onReStart()、onResume()、onPause()、onStop()、onDestory()。 
activity主要生命周期的方法说明: 
 onCreate(Bundle savedInstanceState):创建activity时调用。设置在该方法中,还以Bundle的形式               提供对以前储存的任何状态的访问! 
 onStart():activity变为在屏幕上对用户可见时调用。 
 onResume():activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用的)。   
 onPause():activity被暂停时候调用。
 onStop():activity被停止并转为不可见阶段及后续的生命周期事件时调用。 
 onRestart():重新启动activity时调用。该活动仍在栈中,而不是启动新的活动。 
 onDestroy():activity被完全从系统内存中移除时调用,该方法被调用

6.谈谈你对BroadCastRceiver(广播)的理解?

答:广播接收者,android四大组件之一,也是唯一一个能动态注册的组件。 
1)广播接收者是一个专注于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统──比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。 
2)应用程序可以拥有任意数量的广播接收者以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。 
广播接收者没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

7.View如何进行刷新?

答:在一个开启的线程中调用handler对象的sendMessage方法发送信息,在UI线程中调用handler对象的回调方法handleMessage进行处理,在回调方法中执行invalidate或者postInvalidate

8.DIP、DPI分别是什么?

答:dip(device independent pixels)设备独立像素, 与设备屏幕有关。 
dpi:屏幕像素密度。

9.Android四大组件分别是哪些?各自有什么作用和特点?

答:(1)活动(Activity):Activity是Android程序与用户交互的窗口,是Android构造中最基本的一种,它需要为保持各界面的状态,做很多持久化的事情,妥善管理生命周期以及一些跳转逻辑。
(2)服务(Service):后台服务于Activity,封装有一个完整的功能逻辑实现,接受上层指令,完成相关的事务,定义好需要接受的Intent提供同步和异步接口。
(3)内容提供者(Content Provider):是Android提供的第三方应用数据的访问方案,可以派生Content Provider类,对外提供数据,可以像数据库一样进行选择排序,屏蔽内部数据的存储细节,向外提供统一的接口模型,大大简化上层应用,对数据的整合提供了更方便的途径。
(4)广播接收器(BroadCast Receiver):接受一种或者多种Intent作触发时间,接受相关消息,做一些简单处理,转换成一条Notification,统一了Android的事件广播模型。(如接受系统通知,向通知栏发送消息)

10.Activity的四种加载(启动)模式分别是?各自有什么特点??

答:①standard:特点是每一次启动该Act时,会重建一个新的该Act实例
②singleTop:特点是每一次该Act时,检查栈顶是否存在该Act的实例
存在:则直接重用该Act实例
不存在:则需要新建一个该Act的实例
③singleTask:特点是每一次启动该Act时,需要在栈中去检查栈中是否存在该Act的实例
存在:
在栈顶:直接复用该Act的实例
不在栈顶:首先要把其上的Act实例移除掉,使该Act的实例回到栈顶去,然后再复用该Act的实例
不存在:新建一个该Act的实例
④singleInstance:看进程中是否有该Act实例存在:直接从该独享栈中取出该Act的实例复用
不存在:新建一个栈,然后新建一个该Act的实例,放入该栈中
注意:如果把程序入口MainAct的Act设置为singleInstance时,通过该Act启动了别的Act(SecondAct),再由其他 (SecondAct)启动ThirdAct,在ThirdAct中启动MainAct,由MainAct再去启动SecondAct时,不会产生第四个实例只是把MainAct所在的栈切换到SecondAct所在的栈,把栈顶的Act实例展示出来

11.Activity意外退出时,如何进行数据保存和恢复?

答:开发者提前可以复写onSaveInstanceState方法,创建一个Bundle类型的参数,把数据存储在这个Bundle对象中,这样即使Activity意外退出,Activity被系统摧毁,当重新启动这个Activity而调用onCreate方法时,上述Bundle对象会作为参数传递给onCreate方法,开发者可以从Bundle对象中取出保存的数据,利用这些数据将Activity恢复到被摧毁之前的状态。

12.Intent是什么?有什么用处?

答:Intent(意图):作用是调用某个组件去做一个事情,它既能充当桥梁的角色,也能传递数据。

13.Intent如何传值?Bundle是什么,有什么用?

答:Intent的传值:通过Intent类提供的setData和putExtra方法传递。
Bundle(捆):
两个Activity之间的通讯可以通过bundle类来实现,把要传递的数据通过key-value的形式加入数据,另外一个Activity里面取出数据时,用key找出对应的value

14.onCreate(Bundle savedInstanceState)中savedInstanceState有什么用,什么情况下为null?

答:avedInstanceState:是用来保存实例状态的。
在Activity中有一个onSaveInstanceStata方法,可以用来存放数据,避免Activity意外退出时保存需要的数据,通过onCreate中savedInstanceState取出保存的数据,默认不重写时为null。

15.如何实现使用Intent来传递自定义对象??

答:avedInstanceState:是用来保存实例状态的。
在Activity中有一个onSaveInstanceStata方法,可以用来存放数据,避免Activity意外退出时保存需要的数据,通过onCreate中savedInstanceState取出保存的数据,默认不重写时为null。

16.请说明隐式、显式Intent的区别?

答:显式Intent直接用组件的名称定义目标组件,这种方式很直接。但是由于开发人员往往并不清楚别的应用程序的组件名称,因此,显式Intent更多用于在应用程序内部传递消息。比如在某应用程序内,一个Activity启动一个Service。 隐式Intent恰恰相反,它不会用组件名称定义需要激活的目标组件,它更广泛地用于在不同应用程序之间传递消息。在显式Intent消息中,决定目标组件的唯一要素就是组件名称,因此,如果你的Intent中已经明确定义了目标组件的名称,那么你就完全不用再定义其他Intent内容。 而对于 隐式Intent则不同,由于没有明确的目标组件名称,所以必须由Android系统帮助应用程序寻找与Intent请求意图最匹配的组件。

17.通过Intent传递一些二进制数据的方法有哪些?

答:1)使用Serializable接口实现序列化,这是Java常用的方法。 
2)实现Parcelable接口,这里Android的部分类比如Bitmap类就已经实现了,同时Parcelable在Android AIDL中交换数据也很常见的。

18.android 中线程与线程,进程与进程之间如何通信?

答:1 、一个 Android 程序开始运行时,会单独启动一个 Process 。默认情况下,所有这个程序中的 Activity 或者 Service 都会跑在这个 Process 。 默认情况下,一个 Android 程序也只有一个 Process ,但一个 Process 下却可以有许多个 Thread。 
2 、一个 Android 程序开始运行时,就有一个主线程 Main Thread 被创建。该线程主要负责 UI 界面的显示、更新和控件交互,所以又叫 UI Thread 。 一个 Android 程序创建之初,一个 Process 呈现的是单线程模型 — 即 Main Thread ,所有的任务都在一个线程中运行。所以, Main Thread 所调用的每一个函数,其耗时应该越短越好。而对于比较费时的工作,应该设法交给子线程去做,以避免阻塞主线程(主线程被阻塞,会导致程序假死 现象)。 
3 、Android 单线程模型: Android UI 操作并不是线程安全的并且这些操作必须在 UI 线程中执行。如果在子线程中直接修改 UI ,会导致异常。

19.Service的两种使用方式分别是什么?它们的生命周期分别怎样迁移?

答:方式1:通过startService,Service会经历onCreate->onStart,stopService的时候直接onDestroy
方式二:通过bindService,Service只会运行onCreate,这个时候TestServiceHolder和TestService绑定在一起,TestServiceHolder退出了,Srevice就会调用onUnbind->onDestroyed
.

20.请简述Handler的机制原理?

答:  andriod 提供了 Handler 和 Looper 来满足线程间的通信。Handler 先进先出原则。 Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。 
1)Looper: 一个线程可以产生一个 Looper 对象,由它来管理此线程里的 Message Queue(消息队列)。 
2)Handler: 你可以构造 Handler 对象来与 Looper 沟通,以便 push 新消息到 Message Queue 里;或者接收 Looper从 Message Queue 取出)所送来的消息。 
3)Message Queue(消息队列):用来存放线程放入的消息。 
4)线程:UI thread 通常就是 main thread,而 Android 启动程序时会替它建立一个Message Queue(消息队列)。

20.请简述Handler的机制原理?

答:  andriod 提供了 Handler 和 Looper 来满足线程间的通信。Handler 先进先出原则。 Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。 
1)Looper: 一个线程可以产生一个 Looper 对象,由它来管理此线程里的 Message Queue(消息队列)。 
2)Handler: 你可以构造 Handler 对象来与 Looper 沟通,以便 push 新消息到 Message Queue 里;或者接收 Looper从 Message Queue 取出)所送来的消息。 
3)Message Queue(消息队列):用来存放线程放入的消息。 
4)线程:UI thread 通常就是 main thread,而 Android 启动程序时会替它建立一个Message Queue(消息队列)。

21.自定义适配器的基本流程是怎么样的?

答: (1). 自定义适配器的步骤:
①.定义一个类MyAdapter继承自BaseAdapter
②.实现BasdeAdapter中的四个抽象方法
getCount(); 返回AdapterView中要添加的选项总数量,通常的做法返回数据源数量
Object getItem(int position); 返回指定位置选项的数据对象,通常做法是将数据源中对应数据返回
int getItemId(int postion); 返回AdapterView中指定位置的id,通常直接返回position值
View getView(AdapterView parent, View convertView, int position);
返回的是AdapterView中指定位置的选项视图
参数1 AdapterView parent ,parent指的就是绑定在适配器上的控件,比如ListView、Spinner、GridView、Gallery等
参数2 View convertView,convertView是系统从Recler取出视图对象,如果该对象不为null,就可以继续使用
参数3 int position,用来指定AdapterView中的具体位置
getView中通常需要完成的功能是什么?简单来说就是从数据源取出数据,然后设置到选项视图上
取数据,数据源为List为例list
Map m = list.get(position);
String s = m.get("name");
获取选项视图,通常可以使用LayoutInflater对象inflater将my_view.xml转换View的对象view
View view = inflater.inflate(R.layout.my_view, null);
TextView tv_name = view.findViewById(R.id.tv_name);
把从数据源中得到的数据设置到选项视图中具体的控件上
tv_name.setText(s);
将设置后的选项视图返回到AdapterView
return view
(2)使用的步骤:
①. 在布局文件中定义一个AdapterView控件
②. 在java中获取到控件
③. 获取到待设置的数据源
④. 通过数据源以及其他准备条件来构造适配器对象
⑤. 把适配器和AdapterView绑定起来
⑥. 需要监听选项的操作
⑦. 当数据源中数据发生改变时,需要更新AdapterView的显示

22.什么是OOM?如何避免OOM??

答: OOM概念:内存溢出(OutOfMemor),内存占有量超过了JVM分配的最大内存。
避免OOM:
①.避免对activity的超过生命周期的引用(尽量使用application代替activity)。
因为程序一般是由很多个Activity构成的,从一个Activity跳转了以后,
系统就有可能回收这个Activity的各种内存占用。可是此时如果你的一些不可回收变量(比如静态变量)保持了对此Activity对象的引用,
那么GC就不会对此Activity进行回收,无故占用了大量的内存。这种情况最好的办法就是用application代替activity。
用Context.getApplicationContext() 或者 Activity.getApplication()可以很方便的得到application对象。
②.在展示高分辨率图片时,先将图片进行压缩到与空间大小相近。
③.及时释放不使用的Bitmap,动态回收内存,方法:bitmap.recycle()。
④.对适配器视图进行优化处理,避免过多加载数据和对象的生成。

23.什么是ANR?产生ANR的原因是什么?如何避免ANR的发生??

答: ANR概念:
应用程序无响应(application not response)。
原因:
主线程中做了非常耗时的操作。
解决办法:
①.运行在主线程里的任何方法都尽可能少做事情,尽量用Handler来处理UIthread和别的thread之间的交互;
②.应用程序应该避免在BroadcastReceiver里做耗时的操作或计算;
③.避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点;
④.在主线程中更新UI。

24.自定义view与自定义Viewgroup绘制过程?

答:首先自定义View,要了解为什么要自定义View,总的来说,自定义View其实只有五步: 
第一:自定义View时所需要的属性 
第二:在定义View的构造方法,在构造方法中获得属性 
第三:测量(onMeasure)控件的宽度与高度 
第四:设置控件在父控件所在的位置 
第五:运用onDraw绘制View 。
自定义Viewgroup
首先测量viewgroup决定只身的空间大小,还需测量子view的大小给子view的一个参考值,完成自身测量之后,viewgroup主要任务是onlayout布局决定子view显示的一个规则,如何放置子view,如果没有手势与用户交互的话,自定义viewgroup其实viewgroup主要是测量与onlayout的过程

25.什么是AIDL?AIDL的作用是什么?它的基本使用流程是怎么样的?

答:AIDL是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
作用:
1、多个应用程序之间建立共同的服务机制;
2、通过AIDL在不同应用程序之间达到数据的共享和数据相互操作;
3、主要是用于多应用之间的数据交互(而 在单个应用内或者说该应用如果不需要和其它第三方应用进行交互则不需要实现aidl接口);
流程:
1、编写aidl文件
2、编写自己的Service
3、在自己的Service的onBind方法中,将aidl文件生成的类中的Stud的子类返回(需要继承Stud重写接口方法)
4、在AndroidManifest.xml中配置你的Service类,示例 注意:service android:name="com.aidl.SerachService"中,android:name属性必须填写你的Service的名字,包括包名,不能写aidl生成的类的名字,因为那不是个Servic
5、编写调用aidl服务的客户端
6、把之前编写的aidl文件(注意不是生成的java文件)和它的包目录拷贝到客户端的src目录中
7、在需要的地方用一下方法绑定,new Intent构造器中的action填写的就是之前中的android:name的字符串

26.什么是有序广播?有序广播有什么特点?什么是系统广播??

答:有序广播:是通过Context.sendOrderedBroadcast来发送。所有的receiver依次执行。
有序广播特点即从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接 收器进行处理,依次类推,直到最后。
系统广播:当系统发生事件时,就会发送出广播,通过广播中的关键字段,系统将寻找所有关注这个广播的应用,并触发他们注册的Receiver

27.什么是粘性广播?它跟普通广播有什么区别?

答:定义:没有注册的接收者,在后来注册后也能收到广播,进程间通信
当发布该广播后它还驻留在周围,它可以让其他接收者迅速的检索到数据,通过一个方法的(动态注册接收者方法)返回值 这个返回值就是意图
粘性广播的特点是Intent会一直保留到广播事件结束,而这种广播也没有所谓的10秒限制,10秒限制是指普通的广播如果onReceive方法执行时间太长,超过10秒的时候系统会将这个广播置为可以干掉的candidate,一旦系统资源不够的时候,就会干掉这个广播而让它不执行

28.ShareedPrefrence的读写数据的基本方法??

答:它保存的数据主要是简单类型的Key-value对。并且Value部分只能是一些基本数据类型:boolean、float、int、long、String等 。
1、得到SharedPreference对象的方法有:
a、Context类中的getSharedPreference(String name,int mode)方法,name :存储的文件名,如果不存在会自动创建一个 mode:访问模式,一般有两个参数MODE_PRIVTE(私有,只有当前应用程序才能进行读写)和MODE_MULTI_PROCESS(多个进程对同一个文件进行读写)
b、Activity类中的getSharedPreference(int mode)方法,自动将当前活动的类名作为文件名
c、PreferenceManager类的getDefaultSharedPreferences(Context context)方法,这是一个静态方法,接收Context参数,会自动将应用程序的包名作为前缀去命名文件
2、读常用方法:
a、boolean contains(String Key):判断SharedPreferences是否包含特定Key的数据
b、abstract Map (String,?) getAll():获取SharedPreferences数据里全部的Key-Value对。
c、 boolean getXxx(String key,Xxx defValue):获取SharedPreferences数据里指定Key对应的value。如果该Key不存在,返回默认值defValue。
3、写常用方法(通过SharedPreferences的内部接口Editor实现,edit()方法即可得到Editor对象)
a、abstract SharedPreferences.Editor clear():清空SharedPreferences里所有的数据
b、abstract SharedPreferences.Editor putXxx(String key,xxx value):向SharedPreferences中插入指定的Key-Value对。
c、abstract SharedPreferences.Editor remove(String key):从SharedPreferences中移除指定Key的数据。
d、boolean commit():当Editor编辑完成后,调用该方法提交修改,切记不可忘记调用此方法,否则不能储存数据、

29.SQLite的基本语句:建表、增删改查分别是怎么样的??

答:建表:
CREATE TABLE tableName(column1 INTEGER PRIMARY KEY AUTOINCREMENT,column2 VARCHAR(num),.....);
添加:
INSERT INTO tableName values(value1,value2);添加所有字段
INSERT INTO tableName(column1,column2) values(value1,value2);添加字段column1和字段column2
删除:
DELETE TABLE tableName 删除全部
DELETE form tableName WHERE column2 = vaule2按条件查询(字段column2的值为vaule2的这一行,如果value2为字符串则需要用单引号括起来)
更新:
UPDATE tableName SET column1 = value1, column2 = value2,...;所有数据都这样更新
UPDATE tableName SET column1 = value1, column2 = value2 WHERE column3 = value3;更新column3 = value3这一行的column1 和column2的值
查询:
SELECT * FROM tableName;查询所有的数据
SELECT column1,column3 FROM tableName; 查询所有数据,但是只显示column1,column3这两个字段的所有值
SELECT * FROM tableName WHERE column2 > someValue;查询column2字段的值大于someValue的所有字段
SELECT * FROM tableName WHERE column1 = value1 ORDER BY column2 ASC;按条件查询结果以column2 的升序排列
SELECT * FROM tableName WHERE column1 = value1 ORDER BY column2 DESC;按条件查询结果以column2 的降序排列
SELECT * FROM tableName WHERE column2 LIKE '%key%' ORDER BY column2 ASC;// 模糊查找。

30.SQLiteOpenHelper的作用是什么?

答:SQLiteOpenHelper主要是用来创建数据库和表格,以及为数据库升级的作用。在Android系统中,既然可以通过Context类的 openOrCreateDatabase()函数打开或创建SQLite数据库,并且可以通过其返回值(即SQLiteDatabase对像)调用execSQL()函数对数据 库做任何的操作(CRUD),那么还需要SQLiteOpenHelper这个类有什么意义呢?
例如:
db = openOrCreateDatabase(DB_NAME, this.MODE_PRIVATE, null);
db.execSQL("DROP TABLE IF EXISTS students");
db.execSQL("CREATE TABLE IF NOT EXISTS students (_id INTEGER PRIMARY KEY AUTOINCREMENT, name, age INTEGER)");
实际上,直接操作数据库的语句和其他的语句混在一起,不利于程序的模块化。而SQLiteOpenHelper是一个抽象类,通过它的名字可以 看出来,是一个帮我们打开数据库的小助手:
1、当new SQLiteOpenHelper子类对象时,就会通过其构造函数创建数据库文件(当然如果数据库如果存在,就不用创建了, 并且自动调用onCreate(SQLiteDatabase db)创建数据表;
2、当要对数据库读操作时,只需调用其子类的getReadableDatabase()返回SQLiteDatabase实例,通过该实例来执行SQL语句 ;
3、当要对数据库写操作时,只需调用其子类的getWritableDatabase()返回SQLiteDatabase实例,通过该实例来执行SQL语句 ;
4、当通过构造函数传进来的数据库版本高于之前的版本时,系统会调用onUpgrade()函数来更新数据库。
于是,对APP而言,就屏蔽了数据库创建的过程,将数据表的创建独立出来了。
SQLiteOpenHelper只是一个数据库管理的帮助类,让使用者不直接操作数据库而是通过操作这个类的对象来实现各种数据库操作。这个 类就是给数据库操作搭了个架子,使用者根据需求去填充那些架子。

31.什么是回调CallBack,回调的作用是什么?常见的回调使用场景??

答:把接口方法的定义和调用给封装起来,然后在回调接口中的回调方法中进行具体的操作
作用:
1、可以节省时间,充分利用了资源
2、让工具类的使用变得简单易用。用户不需要关心接口方法的定义以及调用,只需要关注方法的具体实现功能即可。
使用场景:
1、事件监听器,这其实就是回调最常见的应用场景之一
2、生命周期函数
3、当方法的具体实现不确定的时候可以设置回调函数让清楚的人自己去实现,而我们只是提供一个实现的接口出去,而其它的别人不需要知道的东西都封存起来,这也体现了封装和面向对象的思想,你问我问题,而我想到了答案告诉你,至于 你拿到答案后干什么,我怎么想到的答案都不需要对方知道

32.TCP和UDP的区别是什么?

答:TCP :传输控制协议。
a、面向连接,靠三次握手来完成
b、速度相对较慢,因为连接的过程会耗时间和资源
c、可靠的协议,数据不会丢失
d、数据大小没有限制
e、耗用系统资源相对较多
UDP :用户数据报文协议
a、面向无连接的
b、高效的、速度快
c、不可靠的协议,容易丢失数据
d、数据包大小有限制,小于64K
e、耗用系统资源相对较少

33.Http的get和post方法的区别什么??

答:get方法:
原理上:
主要用来获取或者查询资源信息,是安全的和幂等的。就是说不修改信息
表面上:
a、GET请求的数据会附在URL之后(就是把数据放在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连
b、GET方式提交的数据较小(浏览器和操作系统对URL长度的限定),一般1024字节
c、GET的安全性相对较弱,可能会造成信息泄露(信息会明文出现在URL上,其他人可能会通过浏览器的缓存查看到历史记录,从而得到信息)
d、服务器端用Request.QueryString获取变量的值
e、GET请求用起来比比较方便
post方法:
原理上:
根据Http规范,POST表示可能修改服务器上资源的请求
表面上:
a、POST请求把要提交的数据放在HTTP包的包体中。
b、POST可以提交较大量的数据(受到服务器的处理程序的处理能力限制)
c、POST安全性较高(数据不会明文出现在URL上)。
d、服务器端用Request.Form获取提交的数据。
e、用起来相对麻烦一点

34.HttpURLConnection和HttpClient有什么区别?他们的基本使用流程是怎么样的??

答:区别:
HttpURLConnection:是java的标准类,什么都没封装,用起来太原始,不方便,比如重访问的自定义,以及一些高级功能等。功能不够丰富和灵活
HttpClient:HttpClient是个很不错的开源框架,封装了访问http的请求头,参数,内容体,响应等等,用起来高效、最新、功能丰富
基本使用流程:
HttpURLConnection:
a. 开启一个子线程
b. 创建URL对象u
c. 通过u的openConnection获取链接conn,相关设置,请求方式、超时链接等
d. 通过conn的getXXXStream方法获取IO流
e. 通过IO流进行读写操作
f. 得到的结果更新UI上
h. 关闭资源
HttpClient:
a. 开启一个子线程
b. 得到一个网络资源路径(String)
c. 创建HttpClient对象client
d. 创建一个请求方式的对象HttpPost、HttpGet
e. 通过client的excute(get)方法0获取HttpyujhResponse对象response
f. 通过response的方法获取响应结果
g. 如果是状态码为200则通过response的getEntity方法获取HttpEntity对象entity
h. 得到entity对象就包含了服务器返回的所有数据
i. 如果需要操作IO流,可以通过response的getContent方法来获取IO流,如果不需要,可以通过EntityUtils的toString(entity)方法将其转化成字符串
j. 断开连接disConnected方法

35.常见的实现异步的方式有哪些?

答:AsyncTask、Thread+Handler

36.常见的耗时操作如何处理??

答:常见的耗时操作有:网络请求、数据库操作、比较复杂的运算,使用AsyncTask或Thread+Handler进行异步处理

37.子线程更新UI的基本方法有哪些?

答:a. Thread + Handler的方式
在非UI线程中执行耗时操作(网络请求、数据库操作、比较复杂的运算),在需要将操作的进度或者结果更新到UI上时,
就发送消息并携带数据,最终由Handler的handleMessage来处理(注意:Handler对象必须是创建在UI线程中)
b. Activity提供的一个简便的方式来更新UI
runOnUiThread(Runnable r);
内部做了判断当前的活动线程是否是UI线程
是:直接调用run方法
否:将Runnable给post到UI线程对应的消息队列
c. Handler里边也提供简便的更新UI的方式
handler.post(Runnable r);
内部其实调用了发送消息的方法,最终也是把Runnable对象给放到了UI线程中执行

38.AsyncTask中几个回调方法运行在哪个线程、DoInBackGround执行在哪个线程?

答:4个回调方法,其中三个运行在主线程(初始化,UI更新,进度条更新),DoInBackGround运行在子线程

39.runOnUiThread为什么可以用来更新UI??

答:该方法内部做了判断当前线程是否为UI线程的操作
不是UI线程则将该action添加到mHandler所在的UI线程的消息队列中
是UI线程,则直接执行

40.Handler的post方法为什么可以用来更新UI?

答:该方法内部实际上是发送一个延迟的消息给该线程的Handler处理,该方法内部将消息对象加入了消息队列,最终也是把Runnable对象给放到了UI线程中执行
如果是更新UI,则这个Handler对象必须创建在UI线程中

猜你喜欢

转载自blog.csdn.net/Nieyuwen/article/details/79095445