安卓面试基础知识总结

1 Activity

1.1 Activity 的概念

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

1.2 Activity 与View 的区别

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

2) 如果再细化,Activity 相当于视图层中的控制层,是用来控制和管理View 的,真正用来显示和处理事件的实际上是View 。

3) 每个Activity 内部都有一个Window 对象, Window对象包含了一个DecorView(实际上就是FrameLayout) ,我们通过setContentView 给Activity 设置显示的View 实际上都是加到了DecorView 中。

1.3 Activity 生命周期

1.3.1 生命周期主干

1.3.2 其他中转方法

1.4 Activity 启动模式

1.4.1 四种启动模式

1.4.2 配置样例

1.5 Activity 启动方法

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

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

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

带请求码启动Activity 。

1.6 请求码与响应码

2 BroadcastReceiver

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. 耗时的较长的工作最好放在服务中完成

3 Service

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()不起作用。

4 ContentProvider

4.1 ContentProvider

数据库在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.2 ContentResolver

外界的程序通过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.3 ContentObserver

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

4.4 ContentProvider 和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); 5 Service 如何向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.

2.

3.

4.

Application Preferences Files contentProviders SQLite DB

6 AsyncTask

6.1 底层处理

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

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

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

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

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

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

Runnable 任务,固定容量为10

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

6.2 AsyncTask 介绍

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.3 AsyncTask 实现的原理和适用的优缺点

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

使用的优点:

简单, 快捷

过程可控

使用的缺点:

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

7 Handler

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

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.2 Handler 介绍

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

7.3 Handler 的特点

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 来说能更好的利用系统资源且高效

8 ListView

8.1 ListView 优化

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.2 getview 的加载方法一般有以下三种种方式:

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

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

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

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

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

8.1.3 补充

当处理一些耗时的资源加载的时候需要做到以下几点,以使你的加载更快更平滑:

1. 适配器在界面主线程中进行修改

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

3. 在主界面的线程中提交适配器的变化并调用notifyDataSetChanged()方法

8.2 ListView 的图文混合显示

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 集,在显示前判断处理一下即可。

9 JNI

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): java.lang.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.

3.

4.

5. 实现PakkageInstallActivityHide.java ,UninstallerActivityHide.java 。 只需把PakkageInstallActivity.java 修改去掉dialog 和对话框。 安装程序调用者发一个上面定义的intent 即可。如下例子,静默安装/sdcard/hello.apk 卸载的方法类似。 注意,这个方法需要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)

11 Android 中数据的存储方式

11.1 方式

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

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

2. xml

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

关信息。

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

5. NetWork :将数据保存于网络。

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 语句,它是一个轻量级的嵌入式数据库

4. NetWork :

将数据上传到网络

补充:

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

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

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

12 什么是异步,什么是同步?分别在什么情况下使用?

比如:在子线程中执行数据加载, 主线程中实现界面显示就是异步, 这样

界面可以先显示出来, 在后台加载完数据再填充界面, 而同步则是在一个线程中, 如果数据没有加载完, 那么界面就不会展示, 两个任务必须按顺序执行.

异步适合加载网络数据, 或者大量数据

同步适合多线程访问或修改同一个数据, 要保证数据修改前后的一致性

的时候使用.

13 开发中遇到过哪些异常?是如何处理的?

1. java.lang.NullPointerException 异常的解释是" 程序遇上了空指针" ,简

单地说就是调用了未经初始化的对象或者是不存在的对象,即把数组的初始化和数组元素的初始化混淆起来了。数组的初始化是对数组分配需要的空间,而初始化后的数组,其中的元素并没有实例化,依然是空的,所以还需要对每个元素都进行初始化(如果要调用的话)

2. java.lang.OutOfMemoryError: bitmap size exceeds VM budget 自动把眼

睛跳动到OOM 异常看去

3. java.lang.ClassNotFoundException 异常的解释是" 指定的类不存在" 。

4. java.lang.ArrayIndexOutOfBoundsException

算法异常, 一般是被0除,logcat 中一般有提示;

5. SQLException :操作数据库异常类, 日志中一般会写出来执行什么语句有问

题, 直接从代码中查找即可;

6. java.lang.IllegalArgumentException 这个异常的解释是" 方法的参数错

误" ,比如g.setColor(int red,int green,int blue) 这个方法中的三个值,如果有超过255的也会出现这个异常,因此一旦发现这个异常,我们要做的,就是赶紧去检查一下方法调用中的参数传递是不是出现了错误。

7. java.lang.IllegalAccessException 这个异常的解释是" 没有访问权限" ,

当应用程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常。对程序中用了Package 的情况下要注意这个异常

8. java.io.FileNotFoundException 文件找不到异常, 找到与自己写得类有关

的行号, 双击进入找到相关代码, 文件读写异常, 一般是使用完流没有关流会产生的异常, 检查流是否关闭„. .

14 开发时是如何做屏幕适配的?

14.1 美工切图:两套图

一般切480*800和1280*720的图做屏幕适配。

14.2 屏幕适配

14.2.1 图片适配

不同的手机分辨率会找不同的drawable 对应的目录, 在做屏幕适配时, 会把一些对应分辨率的图片放在drawable-某个手机的分支下.

14.2.2 布局适配

不同手机屏幕的大小不一样, 我们想让程序运行时, 布局也展示的不一样. 在res 目录下创建layout-1280x720文件夹, 里边创建的布局文件就会加载在1280x720的手机屏幕上.

14.2.3 尺寸适配

在res 下创建values 目录, 跟着对应手机的分辨率.

android 下单位: px像素, dip/dp与像素无关的单位密度.

密度比值: 密度比值 = 开跟(宽的平方 + 高的平方) / 屏幕的尺寸.

= 开跟(57600 + 102400) / 屏幕的尺寸.

= 开跟(160000) / 屏幕的尺寸.

= 400 / 2.7

= 148.[***********][1**********]

= 0.75

= 开跟(1638400 + 518400) / 屏幕的尺寸.

= 开跟(2156800) / 屏幕的尺寸.

= 1468.[***********]3375614966 / 4.7

= 312.[***********][1**********]

= 2.

换算: px = dip * 密度比值;

在240*320手机上,

160dip * 0.75 = 120px;

在1280*720手机上,

160dip * 2 = 320px; 320dip * 2 = 640px

代码获取密度比值: density

Resources resources = getResources();

DisplayMetrics metrics = resources.getDisplayMetrics();

System.out.println("密度比值: " + metrics.density);

14.2.4 权重适配

14.2.5 代码适配

代码中的默认没有dp 这个尺寸, 而像素不会根据尺寸匹配屏幕, 可以通过工具类转换dp 到px.

14.2.6 其他

在自定义控件中可以根据图片原有比例算出适合屏幕的尺寸来显示. 提供高清图片, 放在一个屏幕比较适中偏小的文件夹中, 如mdpi.(这样

可以解决图片过多, 应用臃肿的现象)

15 开发时,是如何访问网络的?

15.1 一般在子线程中访问网络.

使用AsyncTask 在doInBackground 中访问网络.

15.2 U RLConnection,HttpClient,AsyncHttpClient,Xutils 使用get

或post 方法发送请求, 接收响应. 获得流对象取得数据.

15.3 使用HttpURLConnection (URLConnection 子类)

1)调用URL 对象的openConnection()方法来创建URLConnection 对象

2)设置URLConnection 的参数和普通请求属性

3)发送GET 或POST 请求

4)通过输入流读取远程资源

5)关闭释放资源

15.4 H ttpClient: Apache提供了一个HttpClient ,用于发送HTTP

请求,接收HTTP 响应。

使用HttpClient 发送请求、接收响应,只需要以下几步:

1)创建HttpClient 对象

2)如果需要发送get 请求,创建HttpGet 对象;如果发送post 请求,创建HttpPost 对象

3)发送参数,setParams(HttpParams params), 对于HttpPost ,也可以调用setEntity(HttpEntity entity)来进行设置

4)httpClient.execute()发送请求,执行此方法返回HttpResponse 对象

5)处理响应对象,调用HttpResponse 的getEntity()获取HttpEntity 对象,该对象封装了服务器响应内容

15.5 使用Socket 通过Tcp 或Udp 访问网络.

1. 基于TCP 协议的Socket

服务器端首先声明一个ServerSocket 对象并且指定端口号,然后调

用Serversocket 的accept ()方法接收客户端的数据。accept ()方法在没有数据进行接收的处于堵塞状态。(Socketsocket=serversocket.accept()), 一旦接收到数据,通过inputstream 读取接收的数据。

客户端创建一个Socket 对象,指定服务器端的ip 地址和端口号(Socketsocket=newSocket("172.168.10.108",8080);), 通过inputstream 读取数据,获取服务器发出的数据(OutputStreamoutputstream=socket.getOutputStream()),最后将要发送的数据写入到outputstream 即可进行TCP 协议的socket 数据传输。

2. 基于UDP 协议的数据传输

服务器端首先创建一个DatagramSocket 对象,并且指点监听的端口。

接下来创建一个空的DatagramSocket 对象用于接收数据

(bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data ,data.length )), 使用DatagramSocket 的receive 方法接收客户端发送的数据,receive ()与serversocket 的accepet ()类似,在没有数据进行接收的处于堵塞状态。

客户端也创建个DatagramSocket 对象,并且指点监听的端口。接下来创建一个InetAddress 对象,这个对象类似与一个网络的发送地址

(InetAddress serveraddress=InetAddress.getByName

("172.168.1.120" )). 定义要发送的一个字符串,创建一个

DatagramPacket 对象,并制定要讲这个数据报包发送到网络的那个地址以及端口号,最后使用DatagramSocket 的对象的send ()发送数据。*

(Stringstr="hello";bytedata[]=str.getByte();DatagramPacketpacket=new

DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet); )

16 开发中大图片是如何处理的?图片是怎么进行缓存的? 16.1 介绍OOM :

加载大图片时会报下列异常:java.lang.OutOfMemoryError :堆内存空间:给类实例、数组分配内存空间的。 RGB ARGB 32 应用程序在启动时系统为它创建一个进程,系统为每个进程创建dalvik 虚拟机(模拟器设置的VM Heap ),当图片的大小大于虚拟机的堆内存空间时,就内存溢出(内存泄露OOM ); 16.2 解决办法

缩放图片加载到内存

步骤:

1. 获得设备屏幕的分辨率;

2. 得到原图的分辨率;

3. 通过比较得到一个合适的比例值;

4. 按照比例值缩放图片

5. 把图片显示在imageview

16.3 图片三级缓存:

1. 当加载图片时, 因为内存加载速度最快, 所以先从内存中加载图片

(Lrucache).

2. 如果内存中没有图片, 再从本地cache 文件夹中加载图片, 这样会比较慢,

但比网络加载快. 如果本地加载成功, 将图片放到LruCache 中, 通过内存缓存起来.

3. 如果本地加载不到图片, 再通过网络加载图片, 这样是最慢的方式, 如果

加载成功同样将图片缓存到LruCache 中.

16.4 内存存储

Java 中常用引用

强引用: 垃圾回收机制就程序崩溃都不会回收.

软引用: 保证软件能够运行的情况, 可以回收软引用的对

象.Map map;

弱引用: 内存达到一定程序, 就会回收掉.

虚引用: 只要垃圾回收一跑, 就会回收.

(1)因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。

(2)另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃,

所以我们这里用得是LruCache 来缓存图片,当存储Image 的大小大于LruCache 设定的值,系统自动释放内存.

16.5 本地存储:

通过getCacheDir()得到缓存目录, 将图片读取到内存中.

实现:把文件描述符传递给本地代码,由本地代码去创建图片

优点:由于是本地代码创建的,那么byte 数组的内存占用不会算到应用内存中,并且一旦内存不足,将会把bitmap 的数组回收掉,而bitmap 不会被回收,当显示的时候,发现bitmap 的数组为空时,将会再次根据文件描述符去加载图片,此时可能由于加载耗时造成界面卡顿,但总比OOM 要好得多。 注意:由于本地代码在创建图片时,没有对图片进行校验,所以如果文件不完整,或者根本就不是一个图片时,系统也不会报错,仍然会返回一个bitmap, 但是这个bitmap 是一个纯黑色的bitmap 。

所以我们在下载图片的时候,一定要先以一个临时文件下载,等下载完毕了,再对图片进行重命名。

16.6 网络加载:

直接访问url 加载图片.

17 开发中如何避免OOM 异常?如果出现来OOM 异常应该如

何处理?

1. 缓存图像到内存,采用软引用缓存到内存,而不是在每次使用的时候都从新

加载到内存,eg : Bitmap bitmap =

BitmapFactory.decodeFile(path);mImageCache.put(path, new

SoftReference(bitmap));

2. 调整图像大小,onLoadingComplete()手机屏幕尺寸有限,分配给图像的显

示区域本身就更小,有时图像大小可以做适当调整;

3. 采用低内存占用量的编码方式,比如Bitmap.Config.ARGB_4444比

Bitmap.Config.ARGB_8888更省内存;

4. 及时回收图像,如果引用了大量Bitmap 对象,而应用又不需要同时显示所

有图片,可以将暂时用不到的Bitmap 对象及时回收掉;

bitmap.recycle();mImageCache.remove(path);

5. 自定义堆内存分配大小,优化Dalvik 虚拟机的堆内存分配;

18 开发中做过自定义控件么?或者问做过哪些自定义控件?

如何实现的?

18.1 自定义控件的实现步骤

1. 写一个类继承View 或你想扩展功能的控件(比如TextView )

2. 在/res/value下创建一个attr.xml 文件

3. 重写父类的构造方法(我一般把三个都写上)在构造方法中获取到自定

义是属性的值。

4. 重写onDraw()方法

5. 新建一个Activity (此处不再给出),在其使用的布局文件中添加自定

义控件,并且可以引入自定义的命名空间,使用attr 中定义的属性

(具体资料实现参加附件资料)

18.2 具体实现

1. 用过.

2. 自定义SlidingMenu, 仿ViewPager, 自定义栏目定制功能, 自定义扇形进

度条, 自定义开关. 仿优酷旋转菜单.

18.2.1 仿VIewPager 技术要点

1.

2.

3.

4. 新建MyViewpager 继承ViewGroup 注册OnTouch 事件根据用户手指移动距离判断是否需要跳到下一页 注册手势事件,实现用户手指滑动页面跟着用户手指滑动的效果 处理事件分发机制,判断ViewPager 的内部子控件是否需要处理滑动事

件,按照预想的效果,将事件合理分发(如上下滑动事件教给子View 处理,左右滑动事件交给ViewPager 处理)

5. 在需要的Activity 中new 出来,按照需要添加子View ,进行操作和显示 18.2.2 自定义优化菜单技术要点

1. 用相对布局先绘制好界面

2. 按照需要的效果为每层界面添加动画效果(补间动画使用时需要注意在

控件消失后设置相应控件不可用或者不可点击,属性动画不需要设置)

3. 重写OnKeyDown 事件,对用户按下返回键也实现相应的动画

4. 为菜单上每个按钮添加事件(setOnclick 时最好让本类实现点击事件接

口,因为菜单的点击事件可能有点多,这样代码更有条理性)

自定义TOgbutton

18.2.3 自定义ToggleButton 技术要点

1.

2.

3.

4.

5.

6. 新建MyToggleButton 类集成View 初始化各种图片资源 为自身设置OnclickEvent 为自身设置OntouchEvent 设置Touch 边界,防止用户将控件滑出边界 在OntouchEvent 里根据用户手指移动绝对值距离判断是点击事件or 移动事件,定义变量区别,让两个Event 分别响应,然后刷新界面

19 都用过哪些设计模式?都是在什么情况下使用?写个单

利设计模式、观察者模式。

常用的:适配器模式, 装饰模式, 观察者模式, 工厂模式, 单例模式,

19.1 适配器模式

ListView ,ViewPager ,等的Adapter 就是典型的适配器

19.2 单例模式:

1. 初始化一个该类的私有成员变量.

2. 私有构造方法.

3. 提供一个方法返回该类的成员变量.

19.3 观察者模式:

1. 写一个回调接口.

2. 设置一个该接口的成员变量

3. 提供一个set..Listener(该接口) 方法, 给另一个类来实现此接口. 将实现的对象赋值给成员变量

4. 在数据改变时调用接口的回调方法.

19.4 工厂模式

1. Fragment 工厂

2. 线程工厂

20 静态代码块、构造代码块、构造函数执行顺序?(子类父

类都有,使用多态创建对象) 静态方法的覆盖问题?

1. 静态代码块->构造代码块->构造函数.

2. 静态方法不会被覆盖, 如果父类的引用指向了子类的对象, 如:Parent sub =

new Sub(); 这时调用sub 的静态方法会执行父类的, 如果子类引用只想子类对象, 如:Sub sub = new Sub(); 这是调用sub 的静态方法会执行子类的. 21 开启线程有哪些方法?是么情况下使用Thread ?什么情

况下使用Runnable ?

1. 写一个类继承Thread, 复写run 方法, 使用start 开启线程.

2. 实现runnable 接口, 将实现的对象传递给Thread 的构造方法, 再使用start

开启线程.

在程序开发中只要是多线程肯定永远以实现Runnable 接口为主,因为实现Runnable 接口相比继承Thread 类有如下好处:

(1)避免点继承的局限,一个类可以实现多个接口。

(2)适合于资源的共享

22 TCP 与UDP ?Socket ?

22.1 T CP

TCP (Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。

一个TCP 连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,我们这里只做简单、形象的介绍,你只要做到能够理解这个过程即可。

我们来看看这三次对话的简单过程:

1. 主机A 向主机B 发出连接请求数据包:“我想给你发数据,可以吗?”,

这是第一次对话;

2. 主机B 向主机A 发送同意连接和要求同步(同步就是两台主机一个在发

送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;

3. 主机A 再发出一个数据包确认主机B 的要求同步:“我现在就发,你接

着吧!”,这是第三次对话。

三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A 才向主机B 正式发送数据。

22.2 U DP

UDP (User Data Protocol,用户数据报协议)是与TCP 相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!

UDP 适用于一次只传送少量数据、对可靠性要求不高的应用环境。

比如,我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP 数据包,然后对方主机确

认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。例如,在默认状态下,一次“ping”操作发送4个数据包(如图2所示)。大家可以看到,发送的数据包数量是4包,收到的也是4包(因为对方主机收到后会发回一个确认收到的数据包)。这充分说明了UDP 协议是面向非连接的协议,没有建立连接的过程。正因为UDP 协议没有连接的过程,所以它的通信效果高;但也正因为如此,它的可靠性不如TCP 协议高。QQ 就使用UDP 发消息,因此有时会出现收不到消息的情况。

22.3 T CP 协议和UDP 协议的差别

23 关于 Fragment

Android 3.0出现,基于pad 的

有两种方式:activity 可以包含多个fragment

另一种是动态加载fragment

24 关于app 竖屏幕显示

app 竖着的话必须设置属性:android :screenOrientation="portrait" 25 Scrollview 里面能不能嵌套listview ,有什么问题出现?

能,listview 显示不全,只显示一行,listview 无法滑动,焦点呗scrollcview 抢占了。

1. 计算每个item 的高度,调用measure 计算,然后用,view ,setparams.height 。每个item 的布局必须是linearlyout ,因为其他的布局里面没有

重写onmesure 的方法。

3. 重写listview 的ontounchevent 方法。当按下的时候拦截scrollview 的滚动。

26 handler 不加static 为什么会有内存泄露.

同一个线程下的handler 共享一个looper 对象,消息中保留了对handler 的引用,只要有消息在队列中,那么handler 便无法被回收,如果handler 不是static ,那么使用Handler 的Service 和Activity 就也无法被回收,即便它们的ondestroy 方法被调用。这就可能导致内存泄露。当然这通常不会发生,除非你发送了一个延时很长的消息。

但把hanlder 添加为static 后,会发现在handler 中调用外部类的方法和成员变量需要它们都定义为final ,这显然是不大可能的。这里建议在你的Service 或Activity 中的增加一个内部static Handler类,

这个内部类持有Service 或Activity 的弱引用, 这样就可以解决final 的问题。

27 handler 中遇到不加static 会出现警告, 而我们还要引用成员变量, 该怎样解决

外部类的方法和成员变量需要它们都定义为final ,

28 application 的framework,library 分别有什么 framework 是程序的结构. 类库是构建程序的部件.

29 为什么不能在broadcastreceiver 中开启子线程

BroadcastReceiver 的生命周期很短,子线程可能还没有结束BroadcastReceiver 就先结束了。

BroadcastReceiver 一旦结束,此时BroadcastReceiver 的所在进程很容易在系统需要内存时被优先杀死,

因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。

所以采用子线程来解决是不可靠的。

30 jvm 与dalvik 的区别

1. 架构不同:JVM 使用栈架构;Dalvik 使用的是寄存器,数据是加载到CUP 的

寄存器上的。

2. JVM 加载的.class 文件,Dalvik 加载的是.dex 文件,对内存的分配情况做

了优化。

31 jvm 是怎样工作的

32 当前的activity 是singletop 的, 而且在栈的最顶端, 如

果我们从service 中执行startAcitvity 来开启这个activity, 会执行哪些方法

onResume()-onRestart()

如果我要让手机每三天做一件事, 你会怎么设计, 有哪些需要注意的

画一下你的app 的模型图

如果调用Service 的onStart 方法, 再调用onBind 方法, 最后调用onStop 方法, 会怎样

11. Serializable和Parceable 有什么区别, 分别在什么情况下使用

12. 为什么HttpConnection 会涉及到基站问题而HttpClient 不会

13. ImageLoader内部是怎样实现的

14. 怎样在子线程中实现handler, 并用handler 接收消息

15. intent传递数据时为什么要继承parceable 或serializeble 接口,而且没有实现任何方法

16. 有一个很难复现的bug ,而且很急,你会用什么方法找到这个bug

17. 有一个图片墙,我会向下滑动--停,向下滑动--停„„,要怎样避免OOM

33 跨进程通信

33.1 原理

Android 中的跨进程通信采用的是Binder 机制,其底层原理是共享内存。 33.2 为什么不能直接跨进程通信?

为了安全考虑,应用之间的内存是无法互相访问的,各自的数据都存在于自身的内存区域内。

33.3 如何跨进程通信?

要想跨进程通信,就要找到一个大家都能访问的地方,例如硬盘上的文件,多个进程都可以读写该文件,通过对该文件进行读写约定好的数据,来达到通信的目的。

● Binder 在linux 层面属于一个驱动,但是这个驱动不是去驱动一个硬件,而且驱动一小段内存。

● 不同的应用通过对一块内存区域进行数据的读、写操作来达到通信的目的。 ● 不同的应用在同一内存区域读写数据,为了告知其他应用如何理解写入的数据,就需要一个说明文件,这就是AIDL 。当两个应用持有相同的AIDL 文件,就能互相理解对方的的意图,就能做出相应的回应,达到通信的目的。


相关文章

  • 我的iOS培训经历
  • 我的iOS培训经历 以下是我学习iOS培训的经历,从最初的知之甚少到了解到整个iOS培训经历,现在分享给大家,其中包括我的感受,也有我的一些关于iOS培训iOS开发的建议,见笑了. 经常有人问,我24岁了,现在到目前为止任何语言不会,专业也 ...

  • 从事什么职业就业前景比较好?
  • www.lnbdqn.com 从事什么职业就业前景比较好? 很多人对自己的未来都是迷茫的,当然我也是.不知道该做什么,只希望有一个人能告诉自己怎么做.那么现在从事什么职业比较好呢? 安卓开发工程师.安卓相关技术人员.安卓程序员等职位目前比较 ...

  • 2017年广州公务员考试时间
  • 2017年广州公务员考试时间 2017年广州市公务员考试报名将于2月24日启动,请报考人员在2017年2月24日9:00至2017年3月2日16:00期间登录广州市人力资源和社会保障局网站,下载"广州考录"APP(仅限安 ...

  • 安卓实训的总结与体会
  • 不知不觉中为期三周的实训已经接近尾声.虽然时间很短,不过我确实学到了一些我觉得有用的东西,并且是平时上课学不到的东西.三周的实训,时间很短,确实很短.原本刚开始,乃至之前听说有为期三周的实训的时候,都觉得,这样的实训不过就是走过场罢了,只有 ...

  • 安卓工业平板的用途和注意事项
  • 安卓工业平板.安卓点检仪的用途及注意事项 随着安卓工业平板在设备点检定修领域的广泛应用,标志着点检定修手持终端迎来了智能点巡检工业平板化,因此在点检员的操作使用上必须注意一些使用事项,以及了解安卓工业平板在点检.巡检方面的用途及应用.通过1 ...

  • 李开复在互联网大会的演讲_js
  • 李开复:2012年中国移动互联网的关键词是渗透与价值 作者李开复 2012-10-21 10:55 评论(154) 创业移动互联网李开复创新大中小 创新工场董事长李开复在移动开发者大会上的演讲中,以"渗透与价值"为主题剖 ...

  • 连连看游戏需求分析报告
  • 楚 雄 师 范 学 院 计科系本科生毕业设计文档(1) 题 目:<基于安卓系统的趣味连连看游戏设计与实现>需求分析报告 专 业: 网络工程(非师范) 学 号: 2010108210 3 学生姓名: 朱 晓 明 指导教师: 秦海菲 ...

  • 2016最新安卓版UI设计规范篇(2)
  • 上表就是我们在界面上最基本的一些控件尺寸的大小规范,比如状态栏.导航栏.和菜单栏,这些都是比较死的数据,多去看几次就记了,当然数据还是挺多的,你也可以用MDPI的尺寸标准看成DP然后再去适配其它的尺寸,这样做的话需要记住的数据就少了很多了, ...

  • 小米手机的营销策略分析
  • 小米手机的营销策略分析 霍好平 摘要:随着网络操作系统和手机通讯业的日益成熟,为智能机的发展带来了更广阔的市场.安卓系统是当前手机操作系统中兼容性最强的一个,受到了众多消费者的欢迎,小米手机正是搭栽着安卓系统所开发出来的一款智能机,一经推出 ...

  • 电脑通过USB线与安卓2.2手机共享上网--华为T8100
  • 电脑通过USB线与安卓2.2手机共享上网 本人经过两天多次试验,终于将自己的电脑,以USB连线的方式,通过安卓手机实现了无线上网,现分享如下: 假如你的手机3G包月流量巨大,那么你的电脑就可以通过安卓2.2手机实现共享上网,那时你的安卓手机 ...

© 2024 范文参考网 | 联系我们 webmaster# 12000.net.cn