Android面试基础知识总结

Android面试基础知识总结
Android面试基础知识总结

1Activity

1.1Activity的概念

是Android应用层开发的四大组件之一,主要负责和用户交互部分,有自己的生命周期,在其上可以布置按钮,文本框等各种控件,简单来说就是Android 的UI部分。

1.2Activity与View的区别

1)Activity是四大组件中唯一一个用来和用户进行交互的组件。可以说

Activity就是android的视图层。

2)如果再细化,Activity相当于视图层中的控制层,是用来控制和管理View

的,真正用来显示和处理事件的实际上是View。

3)每个Activity内部都有一个Window对象, Window对象包含了一个

DecorView(实际上就是FrameLayout),我们通过setContentView给Activity设置显示的View实际上都是加到了DecorView中。

1.3Activity生命周期

1.3.1生命周期主干

1.3.2其他中转方法

1.4Activity启动模式1.4.1四种启动模式

1.4.2配置样例

1.5Activity启动方法

1)在一个Activity中调用startActivity()方法。

直接启动Activity,不带请求码。

2)在一个Activity中调用startActivityForResult()方法。

带请求码启动Activity。

1.6请求码与响应码

2BroadcastReceiver

2.1概念

BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。

2.2应用场景

在Android系统中,广播体现在方方面面:

eg:

1.当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动

服务的功能;

2.当锁屏或者点亮屏幕时就会产生一条广播,接收这条广播就可以实现一

些暂停或者开启一些耗电进程的功能。

3.当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做

出提示和保存数据等操作;

4.当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量

低时告知用户及时保存进度;

2.3注册

2.3.1静态注册

2.3.1.1概念

静态注册是在AndroidManifest.xml文件中配置的。

2.3.2动态注册

2.3.2.1概念

动态注册需要在代码中动态的指定广播地址并注册。

2.3.2.2需要注意的事项

RegisterReceiver是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,所以可以直接调用。在实际应

用中,我们在Activity或Service中注册了一个BroadcastReceiver,当这个Activity或Service被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,需要在特定的地方执行解除注册操作:生命周期的onDestroy()。

有部分广播接受者,涉及到用户的敏感内容,需要在权限文件中声明。如开机完成的广播,用户电量变化的广播,用户网络状态发生改变的广播

2.3.3生命周期

1.广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,

onReceive()方法结束之后销毁

2.广播接收者中不要做一些耗时的工作,否则会弹出Application No Response

错误对话框

3.最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销

毁后进程就成为了空进程,很容易被系统杀掉

4.耗时的较长的工作最好放在服务中完成

3Service

3.1概念

服务是看不到界面的,,就是一个没有界面的Activity, 并且长期在后台运行的一个组件.。

3.2为什么用服务?

进程优先级, 回收时是从5~1, 从低到高

Foreground process 前台进程

Visible process 可视进程

Service process 服务进程

Background process 后台进程

Empty process 空进程

回收的优先级: 先回收空进程, 一个一个回收的, 当内存够用时, 不再回收空进程. 如果空进程回收完毕后, 内存还是不够用时, 继续向上一个一个的回收后台进程. 依次类推.

当系统内存不够用时, 需要回收服务进程时, 当系统内存又够用时, 会重新启动服务. 当用户去手动的把服务关闭时, 服务不会再重启了

3.3作用

由于ANR对Activity和BroadcastReceiver响应时间的限制(Activity对事件响应不超过5秒,BroadcastReceiver执行不超过10秒),使得在其中都不适合执行较耗时操作,这样像网络、数据库、复杂计算这类耗时操作的执行就需要一个组件来承担。Service作为Android四大组件之一,其功能之一就是耗时操作的执行,主要功能如下:

a. 执行需要长时间运行的操作,这个操作不与用户进行交互,如网络下载、大文件I/O、复杂计算、监听手机状态。

b. 应用内或应用间数据通信,Android每个应用程序都在自己的dalvik虚拟机中运行,一个应用是不允许访问其他应用的内存信息的,为此Android引入了Content Provider在不同应用间共享数据,BroadcastReceiver广播信息给不同应用程序,但Content Provider更多用于数据的共享,BroadcastReceiver 广播的信息会被所有应用接收较耗费系统资源,对于两个应用间动态的进行交互还需要通过Service来完成。

3.4启动方式

3.4.1直接启动

Activity开启完服务后就不管服务了. Activity和服务没有关系. startService 开启的服务, 只有stopService可以关闭

3.4.2绑定启动

绑定服务, 生命周期方法会执行: onUnbind -> onDestory 服务销毁了.

在activity中调用service中的方法.

步骤:

调用bindService方法绑定服务

1.在Activity中定义一个连接桥的内部类, 会在bindService方法传递给

service.

2.在service服务中onBind方法中返回一个IBinder接口对象.

3.在service类中定义一个IBinder的内部实现类, 在onBind方法返回.

4.当onBinder方法返回完对象后, activity中连接桥里的

onServiceConnected会备调用, 其中形参IBinder service就是

service类中onBind返回的对象.

5.activity得到了service中的内部类对象, 点击按钮是调用内部类中的

forwardBuyTicket方法, 此方法会转调服务中buyTicket方法.

3.5生命周期

Service的生命周期(适用于2.1及以上)

1. 被startService的

无论是否有任何活动绑定到该Service,都在后台运行。

onCreate(若需要) -> onStart(int id, Bundle args). 多次startService,则onStart调用多次,但不会创建多个Service实例,只需要一次stop。该Service一直后台运行,直到stopService或者自己的stopSelf()或者资源不足由平台结束。

2. 被bindService的

调用bindService绑定,连接建立服务一直运行。未被startService只是BindService,则onCreate()执行,onStart(int,Bund,le)不被调用;这种情况下绑定被解除,平台就可以清除该Service(连接销毁后,会导致解除,解除后就会销毁)。

3. 被启动又被绑定

类似startService的生命周期,onCreate onStart都会调用。

4. 停止服务时

stopService时显式onDestroy()。或不再有绑定(没有启动时)时隐式调用。有bind情况下stopService()不起作用。

4ContentProvider

4.1ContentProvider

数据库在Android当中是私有的,当然这些数据包括文件数据和数据库数据以及一些其他类型的数据。

不能将数据库设为WORLD_READABLE,每个数据库都只能创建它的包访问,这意味着只有由创建数据库的进程可访问它。如果需要在进程间传递数据,则可以使用AIDL/Binder或创建一个ContentProvider,但是不能跨越进程/包边界直接来使用数据库。

一个Content Provider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。

也就是说,一个程序可以通过实现一个Content Provider的抽象接口将自己的数据暴露出去。

外界根本看不到,也不用看到这个应用暴露的数据在应用当中是如何存储的,或者是用数据库存储还是用文件存储,还是通过网上获得,这些一切都不重要,

重要的是外界可以通过这一套标准及统一的接口和程序里的数据打交道,可以读取程序的数据,也可以删除程序的数据,

当然,中间也会涉及一些权限的问题。下边列举一些较常见的接口,这些接口如下所示。

· query(Uri uri, String[] projection, String selection, String[]

selectionArgs,String sortOrder):通过Uri进行查询,返回一个Cursor。

· insert(Uri url, ContentValues values):将一组数据插入到Uri 指定的地方。

· update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri指定位置的数据。

· delete(Uri url, String where, String[] selectionArgs):删除指定Uri并且符合一定条件的数据。

4.2ContentResolver

外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activity当中通过getContentResolver()可以得到当前应用的ContentResolver实例。

ContentResolver提供的接口和ContentProvider中需要实现的接口对应,主要有以下几个。

?query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder):通过Uri进行查询,返回一个

Cursor。

?insert(Uri url, ContentValues values):将一组数据插入到Uri 指定的地方。

?update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri指定位置的数据。

?delete(Uri url, String where, String[] selectionArgs):删除指定Uri并且符合一定条件的数据。

4.3ContentObserver

在注册,翻译成中文就是内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理。ContentObserver一般和系统或第三方程序提供的Provider一起使用,这些Provider一般情况下会有一个Uri,然后ContentObserver就去监听这些Uri数据的变化,然后做出相应的处理。

4.4ContentProvider和ContentResolver中用到的Uri

在ContentProvider和 ContentResolver当中用到了Uri的形式通常有两种,一种是指定全部数据,另一种是指定某个ID的数据。

我们看下面的例子。

· content://contacts/people/ 这个Uri指定的就是全部的联系人数据。

· content://contacts/people/1 这个Uri指定的是ID为1的联系人的数据。

在上边两个类中用到的Uri一般由3部分组成。

·第一部分是方案:"content://" 这部分永远不变

·第二部分是授权:"contacts"

·第二部分是路径:"people/","people/1"(如果没有指定ID,那么表示返回全部)。

由于URI通常比较长,而且有时候容易出错,且难以理解。所以,在Android 当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串的使用,例如下边的代码:

Contacts.People.CONTENT_URI (联系人的URI)。

在我们的实例MyProvider中是如下定义的:

public static final String AUTHORITY="com.teleca.PeopleProvider";

public static final String PATH_SINGLE="people/#";

public static final String PATH_MULTIPLE="people";

public static final Uri

content_URI=Uri.parse("content://"+AUTHORITY+"/"+PATH_MULTIPLE);

5Service如何向Activity传递数据

一个Android程序可以由多个Activity和Servier组成,在这些程序组件之间传递数据的方法有以下几种,每种方法都有其特定的使用途径。

5.1原始数据类型

在Activity/Servier之间传递临时性的原始数据,可以使用Intent的putExtras方法来传递数据。

若传递的数据需要长久保存,则使用SharedPreference类来完成。

5.2传递对象

当在Activity/Servier之间传递不需要长久保存的对象时,可以使用以下几种途径:

(1)通过Application类,每个Android应用程序都有一个Application 类。当你在程序的AndroidManifest.xml中给Application设定一个名字时,你的程序中就必须有一个Application的子类。这个Application子类会被Android自动实例化,并且是一个全局性的类,它的生命周期和程序的生命周期相同,你可以把一些全局性的对象保存在Application类中。Application类可以通过getApplication()获得。

(2)通过HashMap of WeakReferences传递对象。当一个Activity需要向另外一个Activity传递对象时,可以使用一个关键字把对象存在一个HashMap 中,并把这个关键字通过Internt的Extras发给目标Activity,目标Activity 接到该关键字后使用该关键字把对象从HashMap中取出。

5.3在Activity/Service之间传递需要长久保存的对象时,可以使

用以下的方式

1.Application Preferences

2.Files

3.contentProviders

4.SQLite DB

6AsyncTask

6.1底层处理

底层使用本地线程池机制:

1.核心线程数:线程池中保存的线程数,包括空闲线程,默认为5个

2.线程池中允许的最大线程数,固定为128个+10个阻塞线程

3.当线程数大于核心线程数时,如果线程池中中线程数大于核心线程数5

超过一秒事,终止多余的线程,保留五个核心线程数。

4.执行前用于保持任务的队列,此队列仅保持execute方法提交的

Runnable任务,固定容量为10

5.执行程序创建新线程时使用的工厂

6.2AsyncTask介绍

Android的AsyncTask比Handler更轻量级一些(只是代码上轻量一些,而实际上要比handler更耗资源),适用于简单的异步处理。

首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。

AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。

AsyncTask定义了三种泛型类型 Params,Progress和Result。

Params 启动任务执行的输入参数,比如HTTP请求的URL。

Progress 后台任务执行的百分比。

Result 后台执行任务最终返回的结果,比如String。

使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:

doInBackground(Params…)后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通

常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

onPostExecute(Result)相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。此方法在主线程执行,任务执行的结果作为此方法的参数返回

有必要的话你还得重写以下这三个方法,但不是必须的:

onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。此方法在主线程执行,用于显示任务执行的进度。

onPreExecute()这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

onCancelled() 用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

Task的实例必须在UI thread中创建;

execute方法必须在UI thread中调用;

不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;

该task只能被执行一次,否则多次调用时将会出现异常;

6.3AsyncTask实现的原理和适用的优缺点

AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI 进度更新),最后反馈执行的结果给UI主线程.

使用的优点:

简单,快捷

过程可控

使用的缺点:

在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

7Handler

7.1Handler异步实现的原理和适用的优缺点

1.Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的

MessageQueue(消息队列)。

2.Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息

到MessageQueue里;或者接收Looper从Message Queue取出)所送来的

消息。

3.Message Queue(消息队列):用来存放线程放入的消息。

4.线程:UIthread 通常就是main thread,而Android启动程序时会替它

建立一个MessageQueue。

在Handler 异步实现时,涉及到Handler, Looper, Message,MessageQueue 四个对象,实现异步的流程是主线程启动Thread(子线程)运行并生成Message 放到MessageQueue,Looper从MessageQueue中获取Message并传递给Handler,Handler逐个获取Looper中的Message,并进行UI变更。

使用的优点:

结构清晰,功能定义明确

对于多个后台任务时,简单,清晰

使用的缺点:

在单个后台异步

处理时,显得代码过多,结构过于复杂(相对性)

7.2Handler介绍

Handler主要接受子线程发送的数据, 并用此数据配合主线程更新UI.

当应用程序启动时,Android首先会开启一个主线程, 主线程为管理界面中的UI控件,进行事件分发,更新UI只能在主线程中更新,子线程中操作是危险的。这个时候,Handler就需要出来解决这个复杂的问题。由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传递)Message对象(里面包含数据), 把这些消息放入主线程队列中,配合主线程进行更新UI。

7.3Handler的特点

Handler可以分发Message对象和Runnable对象到主线程中, 每个Handler 实例,都会绑定到创建他的线程中,

它有两个作用:

(1)安排消息或Runnable 在某个主线程中某个地方执行

(2)安排一个动作在不同的线程中执行

Handler中分发消息的一些方法

post(Runnable)

postAtTime(Runnable,long)

postDelayed(Runnable long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

以上post类方法允许你排列一个Runnable对象到主线程队列中,

sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等

待更新.

7.4综上所述

数据简单使用

AsyncTask:实现代码简单,数据量多且复杂使用

handler+thread :相比较AsyncTask来说能更好的利用系统资源且高效

8ListView

8.1ListView优化

8.1.1简介

在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。

ListView加载数据都是在public View getView(int position, View convertView, ViewGroup parent) {}方法中进行的(要自定义listview都需要重写listadapter:如BaseAdapter,SimpleAdapter,CursorAdapter的等的getvView方法),优化listview的加载速度就要让convertView匹配列表类型,并最大程度上的重新使用convertView。

8.1.2getview的加载方法一般有以下三种种方式:

1.最慢的加载方式是每一次都重新定义一个View载入布局,再加载数据

2.正确的加载方式是当convertView不为空的时候直接重新使用

convertView从而减少了很多不必要的View的创建,然后加载数据

3.最快的方式是定义一个ViewHolder,将convetView的tag设置为

ViewHolder,不为空时重新使用即可

8.1.3补充

当处理一些耗时的资源加载的时候需要做到以下几点,以使你的加载更快更平滑:1.适配器在界面主线程中进行修改

2.可以在任何地方获取数据但应该在另外一个地方请求数据

3.在主界面的线程中提交适配器的变化并调用notifyDataSetChanged()方法8.2ListView的图文混合显示

8.2.1异步加载图片基本思想:

1.先从内存缓存中获取图片显示(内存缓冲)

2.获取不到的话从SD卡里获取(SD卡缓冲)

3.都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)

8.2.2具体优化

优化一:先从内存中加载,没有则开启线程从SD卡或网络中获取,这里注意从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅。

优化二:在adapter里新建一个busy变量,表示listview是否处于滑动状态,如果是滑动状态则仅从内存中获取图片,没有的话无需再开启线程去外存或网络获取图片。

优化三:利用线程池在从网络获取图片时,先是将其保存到sd卡,然后再加载到内存,这么做的好处是在加载到内存时可以做个压缩处理,以减少图片所占内存

资料与源码实现(见附件)

8.2.3关于图片错位的处理

图片错位问题的本质源于我们的listview使用了缓存convertView,假设一种场景,一个listview一屏显示九个item,那么在拉出第十个item的时候,事实上该item是重复使用了第一个item,也就是说在第一个item从网络中下载图片并最终要显示的时候其实该item已经不在当前显示区域内了,此时显示的后果将是在可能在第十个item上输出图像,这就导致了图片错位的问题。所以解决之道在于可见则显示,不可见则不显示。在ImageLoader里有个imageViews的map对象,就是用于保存当前显示区域图像对应的url集,在显示前判断处理一下即可。

9JNI

9.1快速智能开发步骤

1.配置NDK目录结构(只需一次)

2.添加本地支持:右键选中工程,Android Tools—>Add native support

3.将cpp代码改成c代码,注意Android.mk文件也要修改,刷新工程,删

除obj目录

4.声明本地方法,实现对应c代码实现:Javah+全类名生成本地方法标头

文件,把头文件剪切到jni目录下,c代码引用头文件,实现头文件里

的方法。

5.实现对应的c代码

6.交叉编译,一锤子敲下去

7.使用静态代码块,引用库函数,调用方法

9.2开发中常见的JNI问题

9.2.1错误一

10-31 06:42:33.645: E/AndroidRuntime(805): https://www.360docs.net/doc/7b3251282.html,ng.UnsatisfiedLinkError: Native method not found:

com.example.ndk2.MainActivity.hello_From_C:()Ljava/lang/String;

1.引入的函数库名字不对,或者没有引入

2.java方法和c方法不对应

3.部署的平台有问题

9.2.2错误二

当前工程报错,但是没有任何文件有错误,有可能Android.mk有问题

在Android.mk文件中不要用到全角空格或者回车

9.2.3错误3

在C代码中有编译时异常 , 在控制台上会提示

9.2.4错误4

10-31 06:53:23.165: A/libc(2075): Fatal signal 11 (SIGSEGV) at 0x476a415c (code=2), thread 2075 (om.example.ndk2)

下面打印一大堆debug信息

C代码中有运行时异常

9.3应用场景

1.输出日志

2.收集用户反馈信息

3.用户登录

4.加密算法

5.电商数据加密

10静默安装

10.1方式一:定制ROM

Google的安全策略要求任何应用应该提示APK安装包的权限,对于一些内置特定厂商应用,可以跳过安装过程的信息加快安装,或者运营商强制安装。10.2方式二:查看系统源码

10.2.1基本原理

在窗口中点击一个APK时,触发单击事件,PackageInstaller接收系统服务PackageManagerService传来的intent信息,传来的Intent信息中有APK的一些参数。实现的关键是区分一般APK和特定APK。

通过传给PackageManagerService的intent中添加特别的参数,PackageInstaller接收后进行判断,进行特别的隐藏安装流程。这个实现只能通过程序调用的方式安装。

安装过程的信息窗口在PackageInstallActivity.java中实现的。安装过程的信息窗口有4个:需要实现一个PakkageInstallActivityHide.JAVA的文件,去掉下面的dialog和窗口

安装权限确认窗口:installPermissionConfirm

安装进度条:installProgress

安装结果窗口:installResult

安装错误提示对话框

10.2.2具体实现(方法一)

1.在Androidmainfest.xml声明一个特定的intent:

android.intent.action.VIEW.HIDE,由PackageInstallActivityHide.java

来接受

注意:

2.实现PakkageInstallActivityHide.java,UninstallerActivityHide.java。

只需把PakkageInstallActivity.java修改去掉dialog和对话框。

3.安装程序调用者发一个上面定义的intent即可。如下例子,静默安装

/sdcard/hello.apk

4.卸载的方法类似。

5.注意,这个方法需要PackageInstall这个apk必须与系统一起编译。这个

apk在/system/app/目录下面;android.intent.action.VIEW.HIDE 这个静默安装的接口需要开放给第三方。

10.2.3具体实现(方法二)

1.从模拟器System\framework目录下提取framework.jar

2.将framework.jar后缀名改为zip,解压后提取其中的classes.dex文件

3.用dex2jar工具将classes.dex转成classes.dex.dex2jar.jar(注意新版本

的dex2jar工具无法转换Android2.2的framework,建议使用dex2jar-0.0.7.8-SNAPSHOT,该工具可以从google官方站上下载到)

4.将classes.dex.dex2jar.jar改名为classes.dex.dex2jar.zip解压取出

android/content/pm/目录下的PackageManager.class,IPackageInstallObserver.class,IPackageDeleteObserver.class及相关的几个class文件备用

5.找到android-sdk目录下的android.jar,改名为android.zip(注意改名前

先备份一下),解压后将步骤4中取得的class文件覆盖到android对应的目录下,

6.这个时候你的android.jar已经是一个更新过的SDK了,重新打开eclipse

工程,你已经可以调用方法:

void android.content.pm.PackageManager.installPackage(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName)

11Android中数据的存储方式

11.1方式

1.Shared Preferences:主要用于保存程序的系统配置信息。用来存储

“key-values paires”。一般用于保存程序启动时设定的信息,以便在

程序下一次启动时继续保留前一次设定的信息。

2.xml

3.Files:用文件的形式保存信息。可以通过对文件的读写来获取或保存相

关信息。

4.SQLite:用数据库的形式保存信息。SQLite是一个开源的数据库系统。

https://www.360docs.net/doc/7b3251282.html,Work:将数据保存于网络。

11.2区别

1.Shared Preferences:

Android提供用来存储一些简单的配置信息的一种机制,例如,一些默认欢迎语、登录的用户名和密码等。其以键值对的方式存储,

SharedPreferences是以XML的格式以文件的方式自动保存的,在DDMS 中的File Explorer中展开到/data/data//shared_prefs下,以上面这个为例,可以看到一个叫做SETTING_Infos.xml的文件

2.Files

在Android中,其提供了openFileInput 和 openFileOuput 方法读取

设备上的文件,下面看个例子代码,具体如下所示:

String FILE_NAME = "tempfile.tmp"; //确定要操作文件的文件名

FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_PRIVATE); //初始化

FileInputStream fis = openFileInput(FILE_NAME); //创建写入流

上述代码中两个方法只支持读取该应用目录下的文件,读取非其自身目

录下的文件将会抛出异常。需要提醒的是,如果调用

FileOutputStream 时指定的文件不存在,Android 会自动创建它。另外,

在默认情况下,写入的时候会覆盖原文件内容,如果想把

新写入的内容附加到原文件内容后,则可以指定其模式为

Context.MODE_APPEND

3.SQLite

SQLite是Android所带的一个标准的数据库,它支持SQL语句,它是一

个轻量级的嵌入式数据库

https://www.360docs.net/doc/7b3251282.html,Work:

将数据上传到网络

补充:

1.Shared Preferences底层使用xml,xml也可以保存数据,但是Shared

Preferences只能保存键值对方式,xml能保存复杂数据

2.Content provider底部还是使用了Sqlite数据库,也是算一种方式。

相关主题
相关文档
最新文档