1. 下列哪些语句关于内存回收的说明是正确的? (b )
A、 程序员必须创建一个线程来释放内存
B、 内存回收程序负责释放无用内存
C、 内存回收程序允许程序员直接释放内存
D、 内存回收程序可以在指定的时间释放内存对象
2. 下面异常是属于Runtime Exception 的是(abcd)(多选)
A、ArithmeticException
B、IllegalArgumentException
C、NullPointerException
D、BufferUnderflowException
3. Math.round(11.5)等于多少(). Math.round(-11.5)等于多少(c). c
A、11 ,-11 B、11 ,-12 C、12 ,-11 D、12 ,-12
4. 下列程序段的输出结果是:(b )
void complicatedexpression_r(){
int x=20, y=30;
boolean b;
b=x>50&&y>60||x>50&&y<-60||x<-50&&y>60||x<-50&&y<-60;
System.out.println(b);
}
A、true B、false C、1 D、011.activity
5. 对一些资源以及状态的操作保存,最好是保存在生命周期的哪个函数中进行(d)
A、onPause() B、onCreate() C、 onResume() D、onStart()
6. Intent传递数据时,下列的数据类型哪些可以被传递(abcd)(多选)
A、Serializable B、charsequence C、Parcelable D、Bundle
7. android 中下列属于Intent的作用的是(c)
A、实现应用程序间的数据共享
B、是一段长的生命周期,没有用户界面的程序,可以保持应用在后台运行,而不会因为切换页面而消失
C、可以实现界面间的切换,可以包含动作和动作数据,连接四大组件的纽带
D、处理一个应用程序整体性的工作
8. 下列属于SAX解析xml文件的优点的是(b)
A、将整个文档树在内存中,便于操作,支持删除,修改,重新排列等多种功能
B、不用事先调入整个文档,占用资源少
C、整个文档调入内存,浪费时间和空间
D、不是长久驻留在内存,数据不是持久的,事件过后,若没有保存数据,数据就会消失
要点:
XML解析主要有三种方式,SAX、DOM、PULL。常规在PC上开发我们使用Dom相对轻松些,但一些性能敏感的数据库或手机上还是主要采用SAX方式,SAX读取是单向的,优点:不占内存空间、解析属性方便,但缺点就是对于套嵌多个分支来说处理不是很方便。而DOM方式会把整个XML文件加载到内存中去,如果数据量不是很大推荐使用,PULL常常用在J2ME对于节点处理比较好,类似SAX方式,同样很节省内存。
9. 下面的对自定style的方式正确的是(a)
A、 <resources>
<style name="myStyle">
<item name="android:layout_width">fill_parent</item>
</style>
</resources>
B、 <style name="myStyle">
<item name="android:layout_width">fill_parent</item>
</style>
C、 <resources>
<item name="android:layout_width">fill_parent</item>
</resources>
D、 <resources>
<style name="android:layout_width">fill_parent</style>
</resources>
10. 在android中使用Menu时可能需要重写的方法有(ac)。(多选)
A、onCreateOptionsMenu()
B、onCreateMenu()
C、onOptionsItemSelected()
D、onItemSelected()
11. 在SQL Server Management Studio 中运行下列T-SQL语句,其输出值(c)。
SELECT @@IDENTITY
A、可能为0.1
B、可能为3
C、 不可能为-100
D、肯定为0
12. 在SQL Server 2005中运行如下T-SQL语句,假定SALES表中有多行数据,执行查询之 后的结果是(d)。
BEGIN TRANSACTION A
Update SALES Set qty=30 WHERE qty<30
BEGIN TRANSACTION B
Update SALES Set qty=40 WHERE qty<40
Update SALES Set qty=50 WHERE qty<50
Update SALES Set qty=60 WHERE qty<60
COMMITTRANSACTION B
COMMIT TRANSACTION A
A、SALES表中qty列最小值大于等于30
B、SALES表中qty列最小值大于等于40
C、SALES表中qty列的数据全部为50
D、SALES表中qty列最小值大于等于60
13. 在android中使用SQLiteOpenHelper这个辅助类时,可以生成一个数据库,并可以对数据库版本进行管理的方法可以是(ab)
A、getWriteableDatabase()
B、getReadableDatabase()
C、getDatabase()
D、getAbleDatabase()
14. android 关于service生命周期的onCreate()和onStart()说法正确的是(ad)(多选题)
A、当第一次启动的时候先后调用onCreate()和onStart()方法
B、当第一次启动的时候只会调用onCreate()方法
C、如果service已经启动,将先后调用onCreate()和onStart()方法
D、如果service已经启动,只会执行onStart()方法,不在执行onCreate()方法
15. 下面是属于GLSurFaceView特性的是(abc)(多选)
A、管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图
view上。
B、管理一个EGL display,它能让opengl把内容渲染到上述的surface上。
C、让渲染器在独立的线程里运作,和UI线程分离。
D、可以直接从内存或者DMA等硬件接口取得图像数据
16. 下面在AndroidManifest.xml文件中注册BroadcastReceiver方式正确的(a)
A、<receiver android:name="NewBroad">
<intent-filter>
<action
android:name="android.provider.action.NewBroad"/>
<action>
</intent-filter>
</receiver>
B、<receiver android:name="NewBroad">
<intent-filter>
android:name="android.provider.action.NewBroad"/>
</intent-filter>
</receiver>
C、<receiver android:name="NewBroad">
<action
android:name="android.provider.action.NewBroad"/>
<action>
</receiver>
D、<intent-filter>
<receiver android:name="NewBroad">
<action>
android:name="android.provider.action.NewBroad"/>
<action>
</receiver>
</intent-filter>
17. 关于ContenValues类说法正确的是(a)
A、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的
名是String类型,而值都是基本类型
B、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的
名是任意类型,而值都是基本类型
C、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中的
名,可以为空,而值都是String类型
D、他和Hashtable比较类似,也是负责存储一些名值对,但是他存储的名值对当中
的名是String类型,而值也是String类型
18. 我们都知道Hanlder是线程与Activity通信的桥梁,如果线程处理不当,你的机器就会变得越慢,那么线程销毁的方法是(a)
A、onDestroy()
B、onClear()
C、onFinish()
D、onStop()
19. 下面退出Activity错误的方法是(c)
A、finish()
B、抛异常强制退出
C、System.exit()
D、onStop()
20. 下面属于android的动画分类的有(ab)(多项)
A、Tween B、Frame C、Draw D、Animation
21. 下面关于Android dvm的进程和Linux的进程,应用程序的进程说法正确的是(d)
A、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,不一定拥有一个独立 的Dalvik虚拟机实例.而每一个DVM都是在Linux 中的一个进程,所以说可以认为是同一个概念.
B、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,不一定拥有一个独立的Dalvik虚拟机实例.而每一个DVM不一定都是在Linux 中的一个进程,所以说不是一个概念.
C、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例.而每一个DVM不一定都是在Linux 中的一个进程,所以说不是一个概念.
D、DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik虚拟机实例.而每一个DVM都是在Linux 中的一个进程,所以说可以认为是同一个概念.
22. Android项目工程下面的assets目录的作用是什么b
A、放置应用到的图片资源。
B、主要放置多媒体等数据文件
C、放置字符串,颜色,数组等常量数据
D、放置一些与UI相应的布局文件,都是xml文件
23. 关于res/raw目录说法正确的是(a)
A、 这里的文件是原封不动的存储到设备上不会转换为二进制的格式
B、 这里的文件是原封不动的存储到设备上会转换为二进制的格式
C、 这里的文件最终以二进制的格式存储到指定的包中
D、 这里的文件最终不会以二进制的格式存储到指定的包中
24. 下列对android NDK的理解正确的是(abcd )
A、 NDK是一系列工具的集合
B、 NDK 提供了一份稳定、功能有限的 API 头文件声明。
C、 使 “Java+C” 的开发方式终于转正,成为官方支持的开发方式
D、 NDK 将是 Android 平台支持 C 开发的开端
- 填空题
25. android中常用的四个布局是FrameLayout,LinearLayout,RelativeLayout和TableLayout。
26. android 的四大组件是activity,service,broadcast和contentprovider。
27. java.io包中的objectinputstream和objectoutputstream类主要用于对对象(Object)的读写。
28. android 中service的实现方法是:startservice和bindservice。
29. activity一般会重载7个方法用来维护其生命周期,除了onCreate(),onStart(),onDestory() 外还有onrestart(),onresume(),onpause(),onstop()。
30. android的数据存储的方式sharedpreferences,文件,SQlites数据库,contentprovider,网络五大储存方式。
31. 当启动一个Activity并且新的Activity执行完后需要返回到启动它的Activity来执行 的回调函数是onActivityForResult()。
33. 程序运行的结果是:_____good and gbc__________。
public class Example{
String str=new String("good");
char[]ch={'a','b','c'};
public static void main(String args[]){
Example ex=new Example();
ex.change(ex.str,ex.ch);
System.out.print(ex.str+" and ");
Sytem.out.print(ex.ch);
}
public void change(String str,char ch[]){
str="test ok";
ch[0]='g';
}
}
34. 在android中,请简述jni的调用过程。(8分)
1)安装和下载Cygwin,下载 Android NDK
2)在ndk项目中JNI接口的设计
3)使用C/C++实现本地方法
4)JNI生成动态链接库.so文件
5)将动态链接库复制到java工程,在java工程中调用,运行java工程即可
35. 简述Android应用程序结构是哪些?(7分)
Android应用程序结构是:
Linux Kernel(Linux内核)、Libraries(系统运行库或者是c/c++核心库)、Application
Framework(开发框架包)、Applications(核心应用程序)
36. 请继承SQLiteOpenHelper实现:(10分)
1).创建一个版本为1的“diaryOpenHelper.db”的数据库,
2).同时创建一个 “diary” 表(包含一个_id主键并自增长,topic字符型100
长度, content字符型1000长度)
3).在数据库版本变化时请删除diary表,并重新创建出diary表。
public class DBHelper extends SQLiteOpenHelper {
public final static String DATABASENAME = "diaryOpenHelper.db";
public final static int DATABASEVERSION = 1;
//创建数据库
public DBHelper(Context context,String name,CursorFactory factory,int version)
{
super(context, name, factory, version);
}
//创建表等机构性文件
public void onCreate(SQLiteDatabase db)
{
String sql ="create table diary"+
"("+
"_id integer primary key autoincrement,"+
"topic varchar(100),"+
"content varchar(1000)"+
")";
db.execSQL(sql);
}
//若数据库版本有更新,则调用此方法
public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion)
{
String sql = "drop table if exists diary";
db.execSQL(sql);
this.onCreate(db);
}
}
37. 页面上现有ProgressBar控件progressBar,请用书写线程以10秒的的时间完成其进度显示工作。(10分)
答案
public class ProgressBarStu extends Activity {
private ProgressBar progressBar = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.progressbar);
//从这到下是关键
progressBar = (ProgressBar)findViewById(R.id.progressBar);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int progressBarMax = progressBar.getMax();
try {
while(progressBarMax!=progressBar.getProgress())
{
int stepProgress = progressBarMax/10;
int currentprogress = progressBar.getProgress();
progressBar.setProgress(currentprogress+stepProgress);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thread.start();
//关键结束
}
}
38. 请描述下Activity的生命周期。
必调用的三个方法:onCreate() --> onStart() --> onResume(),用AAA表示
(1)父Activity启动子Activity,子Actvity退出,父Activity调用顺序如下
AAA --> onFreeze() --> onPause() --> onStop() --> onRestart() --> onStart(),onResume() …
(2)用户点击Home,Actvity调用顺序如下
AAA --> onFreeze() --> onPause() --> onStop() -- Maybe --> onDestroy() – Maybe
(3)调用finish(), Activity调用顺序如下
AAA --> onPause() --> onStop() --> onDestroy()
(4)在Activity上显示dialog, Activity调用顺序如下
AAA
(5)在父Activity上显示透明的或非全屏的activity,Activity调用顺序如下
AAA --> onFreeze() --> onPause()
(6)设备进入睡眠状态,Activity调用顺序如下
AAA --> onFreeze() --> onPause()
39. 如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?
onSaveInstanceState()
当你的程序中某一个Activity A在运行时,主动或被动地运行另一个新的Activity B,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被收回的就直接执行onResume(),跳过onCreate()了。
40. 如何将一个Activity设置成窗口的样式。
在AndroidManifest.xml 中定义Activity的地方一句话android:theme="@android:style/Theme.Dialog"或android:theme="@android:style/Theme.Translucent"就变成半透明的
41. 如何退出Activity?如何安全退出已调用多个Activity的Application?
先来说一下原理。我们知道,Activity有四种启动模式,分别为:standard(默认模式)、singleTop、singleTask、singleInstance。本方式需要使用的就是singleTask启动模式。
如果设置一个Activity的启动模式为singleTask,那么每次启动此Activity时系统都会检查当前任务栈中是否已经存在此Activity的实例。如果已经存在,则不再创建此Activity新的实例,而是调用已存在的Activity的onNewIntent()方法,并把intent作为此方法的参数传递给它。然后它就会被置于栈顶,并把它之前的所有的Activity移除掉。
原理实现
(我们先将进入应用的第一个Activity称为BaseActivity)。明白了基本原理之后就好办了,先将BaseActivity的启动模式设置为singleTask,并重写此Activity的onNewIntent()方法用来结束自己,之后会在此Activity上进入其他Activity进行数量不定的跳转。在需要退出时只需在当前Activity上调用startActivity(this,BaseActivity.class)会首先将除BaseActivity外的所有Activity结束掉,然后会自动调用BaseActivity的onNewIntent()结束掉自己,这样所有Activity都完美的退出了。
图解实现
为了便于理解,使用下图演示此方式的具体实现过程。
代码实现
第一步:设置BaseActivity的启动模式为singleTask
android:launchMode="singleTask"
第二步:重写BaseActivity的onNewIntent()方法
//声明一个静态常量,用作退出BaseActivity的Tag
public static final String EXIST = "exist";
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent != null) {//判断其他Activity启动本Activity时传递来的intent是否为空
//获取intent中对应Tag的布尔值
boolean isExist = intent.getBooleanExtra(EXIST, false);
//如果为真则退出本Activity
if (isExist) {
this.finish();
}
}
}
第三步:在需要退出应用的Activity中启动BaseActivity
Intent intent = new Intent(this,BaseActivity.class);
//传递退出所有Activity的Tag对应的布尔值为true
intent.putExtra(BaseActivity.EXIST, true);
//启动BaseActivity
startActivity(intent);
为了编程方便,最好定义一个Activity基类,处理这些共通问题。
42. 请介绍下Android中常用的五种布局。
FrameLayout(框架布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)
43. 请介绍下Android的数据存储方式。
一.SharedPreferences方式是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。其存储位置在/data/data/<包名>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。实现SharedPreferences存储的步骤如下:
一、根据Context获取SharedPreferences对象
二、利用edit()方法获取Editor对象。
三、通过Editor对象存储key-value键值对数据。
四、通过commit()方法提交数据。
SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
二.文件存储方式: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。
三.SQLite数据库方式 是一个轻量级的数据库,支持基本SQL语法,是常被采用的一种数据存储方式。Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的API。其只有五种数据类型,分别是:
NULL: 空值
INTEGER: 整数
REAL: 浮点数
TEXT: 字符串
BLOB: 大数据
四.内容提供器(Content provider)方式是Android平台中,在不同应用程序之间实现数据共享的一种机制。一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。并且此种方式忽略了底层的数据存储实现,ContentProvider提供了一种统一的通过Uri实现数据操作的方式。其步骤为:
1. 在当前应用程序中定义一个ContentProvider。
2. 在当前应用程序的AndroidManifest.xml中注册此ContentProvider
3. 其他应用程序通过ContentResolver和Uri来获取此ContentProvider的数据。
五. 网络存储方式 需要与Android 网络数据包打交道,关于Android 网络数据包的详细说明,请阅读Android SDK引用了Java SDK的哪些package?。
44. 请介绍下ContentProvider是如何实现数据共享的。
创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。ContentResolver:当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用 ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver使用insert、delete、update、query方法,来操作数据。
45. 如何启用Service,如何停用Service。
Android中的service类似于windows中的service,service一般没有用户操作界面,它运行于系统中不容易被用户发觉,
可以使用它开发如监控之类的程序。
一。步骤
第一步:继承Service类
public class SMSService extends Service { }
第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:
<service android:name=".DemoService" />
二。Context.startService()和Context.bindService
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可
以启动Service,但是它们的使用场合有所不同。
1.使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。
2.采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并
不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用
onDestroy()方法。
3.采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,
。接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会
导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务
解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()-->onDestroy()方法。
三。Service的生命周期
1.Service常用生命周期回调方法如下:
onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,
服务也只被创建一次。 onDestroy()该方法在服务被终止时调用。
2. Context.startService()启动Service有关的生命周期方法
onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。
多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
3. Context.bindService()启动Service有关的生命周期方法
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,
当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
备注:
1. 采用startService()启动服务
Intent intent = new Intent(DemoActivity.this, DemoService.class);
startService(intent);
2.Context.bindService()启动
Intent intent = new Intent(DemoActivity.this, DemoService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
//unbindService(conn);//解除绑定
46. 注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意。
2.起到了一个通知的作用,比如在service中要通知主程序,更新主程序的UI等。因为service是没有界面的,所以不能直接获得主程序中的控件,这样我们就只能在主程序中实现一个广播接受者专门用来接受service发过来的数据和通知了。
Android广播机制(两种注册方法)
在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,不过我们可以搞一个信息防火墙。具体的代码:
public class SmsBroadCastReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle = intent.getExtras();
Object[] object = (Object[])bundle.get("pdus");
SmsMessage sms[]=new SmsMessage[object.length];
for(int i=0;i<object.length;i++)
{
sms[0] = SmsMessage.createFromPdu((byte[])object[i]);
Toast.makeText(context, "来自"+sms[i].getDisplayOriginatingAddress()+" 的消息是:"+sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show();
}
//终止广播,在这里我们可以稍微处理,根据用户输入的号码可以实现短信防火墙。
abortBroadcast();
}
}
当实现了广播接收器,还要设置广播接收器接收广播信息的类型,这里是信息:android.provider.Telephony.SMS_RECEIVED
我们就可以把广播接收器注册到系统里面,可以让系统知道我们有个广播接收器。这里有两种,一种是代码动态注册:
//生成广播处理
smsBroadCastReceiver = new SmsBroadCastReceiver();
//实例化过滤器并设置要过滤的广播
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
//注册广播
BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver, intentFilter);
一种是在AndroidManifest.xml中配置广播
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="spl.broadCastReceiver"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BroadCastReceiverActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--广播注册-->
<receiver android:name=".SmsBroadCastReceiver">
<intent-filter android:priority="20">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
<uses-sdk android:minSdkVersion="7" />
<!-- 权限申请 -->
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
</manifest>
两种注册类型的区别是:
1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
可以使用的场景如下:
1.同一app内部的同一组件内的消息通信(单个或多个线程之间);
2.同一app内部的不同组件之间的消息通信(单个进程);
3.同一app具有多个进程的不同组件之间的消息通信;
4.不同app之间的组件之间消息通信;
5.Android系统在特定情况下与App之间的消息通信。
47. 请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
Handler简介:
一个Handler允许你发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联。每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联。当你创建一个新的Handler时,它就和创建它的线程绑定在一起了。这里,线程我们也可以理解为线程的MessageQueue。从这一点上来看,Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler负责执行他们。
Handler有两个主要的用途:(1)确定在将来的某个时间点执行一个或者一些Message和Runnable对象。(2)在其他线程(不是Handler绑定线程)中排入一些要执行的动作。
Scheduling Message,即(1),可以通过以下方法完成:
post(Runnable):Runnable在handler绑定的线程上执行,也就是说不创建新线程。
postAtTime(Runnable,long):
postDelayed(Runnable,long):
sendEmptyMessage(int):
sendMessage(Message):
sendMessageAtTime(Message,long):
sendMessageDelayed(Message,long):
post这个动作让你把Runnable对象排入MessageQueue,MessageQueue受到这些消息的时候执行他们,当然以一定的排序。sendMessage这个动作允许你把Message对象排成队列,这些Message对象包含一些信息,Handler的hanlerMessage(Message)会处理这些Message.当然,handlerMessage(Message)必须由Handler的子类来重写。这是编程人员需要作的事。
当posting或者sending到一个Hanler时,你可以有三种行为:当MessageQueue准备好就处理,定义一个延迟时间,定义一个精确的时间去处理。后两者允许你实现timeout,tick,和基于时间的行为。
当你的应用创建一个新的进程时,主线程(也就是UI线程)自带一个MessageQueue,这个MessageQueue管理顶层的应用对象(像activities,broadcast receivers等)和主线程创建的窗体。你可以创建自己的线程,并通过一个Handler和主线程进行通信。这和之前一样,通过post和sendmessage来完成,差别在于在哪一个线程中执行这么方法。在恰当的时候,给定的Runnable和Message将在Handler的MessageQueue中被Scheduled。
Message简介:
Message类就是定义了一个信息,这个信息中包含一个描述符和任意的数据对象,这个信息被用来传递给Handler.Message对象提供额外的两个int域和一个Object域,这可以让你在大多数情况下不用作分配的动作。
尽管Message的构造函数是public的,但是获取Message实例的最好方法是调用Message.obtain(),或者Handler.obtainMessage()方法,这些方法会从回收对象池中获取一个。
MessageQueue简介:
这是一个包含message列表的底层类。Looper负责分发这些message。Messages并不是直接加到一个MessageQueue中,而是通过MessageQueue.IdleHandler关联到Looper。
你可以通过Looper.myQueue()从当前线程中获取MessageQueue。
Looper简介:
Looper类被用来执行一个线程中的message循环。默认情况,没有一个消息循环关联到线程。在线程中调用prepare()创建一个Looper,然后用loop()来处理messages,直到循环终止。
大多数和message loop的交互是通过Handler。
下面是一个典型的带有Looper的线程实现。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
48. AIDL的全称是什么?如何工作?能处理哪些类型的数据?
AIDL的英文全称是Android Interface Define Language
当A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的
A工程:
首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get。ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中含有aidl文件接口的get方法。
说明一:aidl文件的位置不固定,可以任意
然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。
其次需要在AndroidManifest.xml文件中配置MyService类,代码如下:
<!-- 注册服务 -->
<service android:name=".MyService">
<intent-filter>
<!-- 指定调用AIDL服务的ID -->
<action android:name="net.blogjava.mobile.aidlservice.RemoteService" />
</intent-filter>
</service>
为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID,正是有了这个ID,B工程才能找到A工程实现通信。
说明:AIDL并不需要权限
B工程:
首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务
绑定AIDL服务就是将RemoteService的ID作为intent的action参数。
说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的报名正确,我们不能修改RemoteService.java文件
bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), serviceConnection, Context.BIND_AUTO_CREATE);
ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService类中继承了RemoteService.stub类的内部类的对象。
49. 请解释下Android程序运行时权限与文件系统权限的区别。
运行时权限Dalvik( android授权)
文件系统 linux 内核授权
50. 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?请说明原由。
通过直接发送Uri把参数带过去,或者通过manifest里的intentfilter里的data属性
51. 你如何评价Android系统?优缺点。
答:Android平台手机 5大优势:
一、开放性
在优势方面,Android平台首先就是其开发性,开发的平台允许任何移动终端厂商加入到Android联盟中来。显著的开放性可以使其拥有更多的开发者,随着用户和应用的日益丰富,一个崭新的平台也将很快走向成熟。开放性对于Android的发展而言,有利于积累人气,这里的人气包括消费者和厂商,而对于消费者来讲,随大的受益正是丰富的软件资源。开放的平台也会带来更大竞争,如此一来,消费者将可以用更低的价位购得心仪的手机。
二、挣脱运营商的束缚
在过去很长的一段时间,特别是在欧美地区,手机应用往往受到运营商制约,使用什么功能接入什么网络,几乎都受到运营商的控制。从去年iPhone 上市 ,用户可以更加方便地连接网络,运营商的制约减少。随着EDGE、HSDPA这些2G至3G移动网络的逐步过渡和提升,手机随意接入网络已不是运营商口中的笑谈,当你可以通过手机IM软件方便地进行即时聊天时,再回想不久前天价的彩信和图铃下载业务,是不是像噩梦一样?互联网巨头Google推动的Android终端天生就有网络特色,将让用户离互联网更近。
三、丰富的硬件选择
这一点还是与Android平台的开放性相关,由于Android的开放性,众多的厂商会推出千奇百怪,功能特色各具的多种产品。功能上的差异和特色,却不会影响到数据同步、甚至软件的兼容,好比你从诺基亚 Symbian风格手机 一下改用苹果 iPhone ,同时还可将Symbian中优秀的软件带到iPhone上使用、联系人等资料更是可以方便地转移,是不是非常方便呢?
四、不受任何限制的开发商
Android平台提供给第三方开发商一个十分宽泛、自由的环境,不会受到各种条条框框的阻扰,可想而知,会有多少新颖别致的软件会诞生。但也有其两面性,血腥、暴力、情色方面的程序和游戏如可控制正是留给Android难题之一。
五、无缝结合的Google应用
如今叱诧互联网的Google已经走过10年度历史,从搜索巨人到全面的互联网渗透,Google服务如地图、邮件、搜索等已经成为连接用户和互联网的重要纽带,而Android平台手机将无缝结合这些优秀的Google服务。
再说Android的5大不足:
一、安全和隐私
由于手机 与互联网的紧密联系,个人隐私很难得到保守。除了上网过程中经意或不经意留下的个人足迹,Google这个巨人也时时站在你的身后,洞穿一切,因此,互联网的深入将会带来新一轮的隐私危机。
二、首先开卖Android手机的不是最大运营商
众所周知,T-Mobile在23日,于美国纽约发布 了Android首款手机G1。但是在北美市场,最大的两家运营商乃AT&T和Verizon,而目前所知取得Android手机销售权的仅有 T-Mobile和Sprint,其中T-Mobile的3G网络相对于其他三家也要逊色不少,因此,用户可以买账购买G1,能否体验到最佳的3G网络服务则要另当别论了!
三、运营商仍然能够影响到Android手机
在国内市场,不少用户对购得移动定制机不满,感觉所购的手机被人涂画了广告一般。这样的情况在国外市场同样出现。Android手机的另一发售运营商Sprint就将在其机型中内置其手机商店程序。
四、同类机型用户减少
在不少手机论坛都会有针对某一型号的子论坛,对一款手机的使用心得交流,并分享软件资源。而对于Android平台手机,由于厂商丰富,产品类型多样,这样使用同一款机型的用户越来越少,缺少统一机型的程序强化。举个稍显不当的例子,现在山寨机泛滥,品种各异,就很少有专门针对某个型号山寨机的讨论和群组,除了哪些功能异常抢眼、颇受追捧的机型以外。
五、过分依赖开发商缺少标准配置
在使用PC端的Windows Xp系统的时候,都会内置微软Windows Media Player这样一个浏览器程序,用户可以选择更多样的播放器,如Realplay或暴风影音等。但入手开始使用默认的程序同样可以应付多样的需要。在 Android平台中,由于其开放性,软件更多依赖第三方厂商,比如Android系统的SDK中就没有内置音乐 播放器,全部依赖第三方开发,缺少了产品的统一性。
52. 什么是ANR 如何避免它?
答:ANR:Application Not Responding,五秒
在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:
对输入事件(如按键、触摸屏事件)的响应超过5秒
意向接受器(intentReceiver)超过10秒钟仍未执行完毕
Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。
因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。
53. 什么情况会导致Force Close ?如何避免?能否捕获导致其的异常?
答:一般像空指针啊,可以看起logcat,然后对应到程序中 来解决错误
54. Android本身的api并未声明会抛出异常,则其在运行时有无可能抛出runtime异常,你遇到过吗?诺有的话会导致什么问题?如何解决?
答: 会,比如nullpointerException。我遇到过,比如textview.setText()时,textview没有初始化。会导致程序无法正常运行出现forceclose。打开控制台查看logcat信息找出异常信息并修改程序。
55. 简要解释一下activity、 intent 、intent filter、service、Broadcase、BroadcaseReceiver
答:一个activity呈现了一个用户可以操作的可视化用户界面
一个service不包含可见的用户界面,而是在后台无限地运行
可以连接到一个正在运行的服务中,连接后,可以通过服务中暴露出来的借口与其进行通信
一个broadcast receiver是一个接收广播消息并作出回应的component,broadcast receiver没有界面
intent:content provider在接收到ContentResolver的请求时被激活。
activity, service和broadcast receiver是被称为intents的异步消息激活的。
一个intent是一个Intent对象,它保存了消息的内容。对于activity和service来说,它指定了请求的操作名称和待操作数据的URI
Intent对象可以显式的指定一个目标component。如果这样的话,android会找到这个component(基于manifest文件中的声明)并激活它。但如果一个目标不是显式指定的,android必须找到响应intent的最佳component。
它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个component的intent filter告诉android该component能处理的intent。intent filter也是在manifest文件中声明的。
56. IntentService有何优点?
答:IntentService 的好处
* Acitivity的进程,当处理Intent的时候,会产生一个对应的Service
* Android的进程处理器现在会尽可能的不kill掉你
* 非常容易使用
57. 横竖屏切换时候activity的生命周期?
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
2、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
3、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?
解答:可以将dictionary.db文件复制到Eclipse Android工程中的res aw目录中。所有在res aw目录中的文件不会被压缩,这样可以直接提取该目录中的文件。可以将dictionary.db文件复制到res aw目录中
58. 如何将打开res aw目录中的数据库文件?
解答:在Android中不能直接打开res aw目录中的数据库文件,而需要在程序第一次启动时将该文件复制到手机内存或SD卡的某个目录中,然后再打开该数据库文件。复制的基本方法是使用getResources().openRawResource方法获得res aw目录中资源的 InputStream对象,然后将该InputStream对象中的数据写入其他的目录中相应文件中。在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法来打开任意目录中的SQLite数据库文件。
59. Android引入广播机制的用意?
答:a:从MVC的角度考虑(应用程序内)
其实回答这个问题的时候还可以这样问,android为什么要有那4大组件,现在的移动开发模型基本上也是照搬的web那一套MVC架构,只不过是改了点嫁妆而已。android的四大组件本质上就是为了实现移动或者说嵌入式设备上的MVC架构,它们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据交互。
b:程序间互通消息(例如在自己的应用程序内监听系统来电)
c:效率上(参考UDP的广播协议在局域网的方便性)
d:设计模式上(反转控制的一种应用,类似监听者模式)
60. Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
DVM指dalivk的虚拟机。每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。而每一个DVM都是在Linux 中的一个进程,所以说可以认为是同一个概念。
61. sim卡的EF 文件有何作用
sim卡的文件系统有自己规范,主要是为了和手机通讯,sim本 身可以有自己的操作系统,EF就是作存储并和手机通讯用的
62. 嵌入式操作系统内存管理有哪几种, 各有何特性
页式,段式,段页,用到了MMU,虚拟空间等技术
63. 什么是嵌入式实时操作系统, Android 操作系统属于实时操作系统吗?
嵌入式实时操作系统是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统。主要用于工业控制、 军事设备、 航空航天等领域对系统的响应时间有苛刻的要求,这就需要使用实时系统。又可分为软实时和硬实时两种,而android是基于linux内核的,因此属于软实时。
64. 一条最长的短信息约占多少byte?
中文70(包括标点),英文160,160个字节。
65. android中的动画有哪几类,它们的特点和区别是什么?
两种,一种是Tween动画、还有一种是Frame动画。Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
66. 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。
67. 说说mvc模式的原理,它在android中的运用
模型(model)对象:是应用程序的主体部分, 对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。
视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。
控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,响应用户出发的相关事件,交给m层处理。
在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。 Event( 事件 ) 导致 Controller 改变 Model 或 View ,或者同时改变两者。只要 Controller 改变了 Models 的数据或者属性,所有依赖的 View 都会自动更新。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中显示。
68. DDMS和TraceView的区别?
DDMS是一个程序执行查看器,在里面可以看见线程和堆栈等信息,TraceView是程序性能分析器 。
69. java中如何引用本地语言
可以用JNI(java native interface java 本地接口)接口 。
70. 谈谈Android的IPC(进程间通信)机制
IPC是内部进程通信的简称, 是共享"命名管道"的资源。Android中的IPC机制是为了让Activity和Service之间可以随时的进行交互,故在Android中该机制,只适用于Activity和Service之间的通信,类似于远程方法调用,类似于C/S模式的访问。通过定义AIDL接口文件来定义IPC接口。Servier端实现IPC接口,Client端调用IPC接口本地代理。
71. NDK是什么
NDK是一些列工具的集合,NDK提供了一系列的工具,帮助开发者迅速的开发C/C++的动态库,并能自动将so和java 应用打成apk包。
NDK集成了交叉编译器,并提供了相应的mk文件和隔离cpu、平台等的差异,开发人员只需简单的修改mk文件就可以创建出so
2、给contentView设置tag(setTag()),传入一个viewHolder对象,用于缓存要显示的数据,可以达到图像数据异步加载的效果。
3、如果listview需要显示的item很多,就要考虑分页加载。比如一共要显示100条或者更多的时候,我们可以考虑先加载20条,等用户拉到列表底部的时候再去加载接下来的20条。
标准启动模式,也是activity的默认启动模式。在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对象。如果Activity A的启动模式为standard,并且A已经启动,在A中再次启动Activity A,即调用startActivity(new Intent(this,A.class)),会在A的上面再次启动一个A的实例,即当前的桟中的状态为A–>A。
singleTop
如果一个以singleTop模式启动的activity的实例已经存在于任务桟的桟顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中。举例来说,如果A的启动模式为singleTop,并且A的一个实例已经存在于栈顶中,那么再调用startActivity(new Intent(this,A.class))启动A时,不会再次创建A的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。这是任务桟中还是这有一个A的实例。
如果以singleTop模式启动的activity的一个实例已经存在与任务桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例。
singleTask
谷歌的官方文档上称,如果一个activity的启动模式为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。如果系统中已经存在这样的一个activity则会重用这个实例,并且调用他的onNewIntent()方法。即,这样的一个activity在系统中只会存在一个实例。
singleInstance
总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。
布局优化(优化布局结构,优化处理逻辑)
内存优化(使用合适的数据对象,避免不必要的对象对象创建,避免内存泄漏)
其他(集中捕获异常,避免频繁的网络请求,优化业务策略)
参考:
Android性能调优具体技巧 20+条(干货不止一点点)
http://hukai.me/android-training-performance-tips/
Android界面性能调优
优化布局结构
- 减少UI布局层级
- 尽量避免在视图层级的顶层使用相对布局 RelativeLayout 。相对布局 RelativeLayout 比较耗资源,因为一个相对布局 RelativeLayout 需要两次度量来确保自己处理了所有的布局关系,而且这个问题会伴随着视图层级中的相对布局 RelativeLayout 的增多,而变得更严重;
- 布局层级一样的情况建议使用线性布局 LinearLayout 代替相对布局 RelativeLayout,因为线性布局 LinearLayout 性能要更高一些;确实需要对分支进行相对布局 RelativeLayout 的时候,可以考虑更优化的网格布局 GridLayout ,它已经预处理了分支视图的关系,可以避免两次度量的问题;
- 相对复杂的布局建议采用相对布局 RelativeLayout ,相对布局 RelativeLayout 可以简单实现线性布局 LinearLayout 嵌套才能实现的布局;
- 不要使用绝对布局 AbsoluteLayout ;
- 将可重复使用的组件抽取出来并用 标签进行重用。如果应用多个地方的 UI 用到某个布局,就将其写成一个布局部件,便于各个 UI 重用。
- 使用 merge 标签减少布局的嵌套层次
- 去掉多余的不可见背景。有多层背景颜色的布局,只留最上层的对用户可见的颜色即可,其他用户不可见的底层颜色可以去掉,减少无效的绘制操作;
- 尽量避免使用 layoutweight 属性。使用包含 layoutweight 属性的线性布局 LinearLayout 每一个子组件都需要被测量两次,会消耗过多的系统资源。在使用 ListView 标签与 GridView 标签的时候,这个问题显的尤其重要,因为子组件会重复被创建。平分布局可以使用相对布局 RelativeLayout 里一个 0dp 的 view 做分割线来搞定,如果不行,那就……;
优化处理逻辑
- 按需载入视图。某些不怎么重用的耗资源视图,可以等到需要的时候再加载,提高UI渲染速度;
- 使用 ViewStub 标签来加载一些不常用的布局;
- 尽量避免不必要的耗资源操作,节省宝贵的运算时间;
- 避免在 UI 线程进行繁重的操作。耗资源的操作(比如 IO 操作、网络操作、SQL 操作、列表刷新等)耗资源的操作应用后台进程去实现,不能占用 UI 线程,UI 线程是主线程,主线程是保持程序流畅的关键,应该只操作那些核心的 UI 操作,比如处理视图的属性和绘制;
- 最小化唤醒机制。我们常用广播来接收那些期望响应的消息和事件,但过多的响应超过本身需求的话,会消耗多余的 Android 设备性能和资源。所以应该最小化唤醒机制,当应用不关心这些消失和事件时,就关闭广播,并慎重选择那些要响应的 Intent 。
检测工具
- Hierarchy View:Hierarchy View 在Android SDK里自带,常用来查看界面的视图结构是否过于复杂,用于了解哪些视图过度绘制,又该如何进行改进。
- Lint:Lint 是 ADT 自带的静态代码扫描工具,可以给 XML 布局文件和 项目代码中不合理的或存在风险的模块提出改善性建议。
- Systrace:Systrace 在Android DDMS 里自带,可以用来跟踪 graphics 、view 和 window 的信息,发现一些深层次的问题。很麻烦,限制大,实际调试中我基本用不到。
- Tracker:Track 在 Android DDMS里自带,是个很棒的用来跟踪构造视图的时候哪些方法费时,精确到每一个函数,无论是应用函数还是系统函数,我们可以很容易地看到掉帧的地方以及那一帧所有函数的调用情况,找出问题点进行优化。
- OverDraw:通过在 Android 设备的设置 APP 的开发者选项里打开 “ 调试 GPU 过度绘制 ” ,来查看应用所有界面及分支界面下的过度绘制情况,方便进行优化。
- GPU 呈现模式分析:通过在 Android 设备的设置 APP 的开发者选项里启动 “ GPU 呈现模式分析 ” ,可以得到最近 128 帧 每一帧渲染的时间,分析性能渲染的性能及性能瓶颈。
- StrictMode:通过在 Android 设备的设置 APP 的开发者选项里启动 “ 严格模式 ” ,来查看应用哪些操作在主线程上执行时间过长。当一些操作违背了严格模式时屏幕的四周边界会闪烁红色,同时输出 StrictMode 的相关信息到 LOGCAT 日志中。
- Animator duration scale:通过在 Android 设备的设置 APP 的开发者选项里打开 “ 窗口动画缩放 ” / “ 过渡动画缩放 ” / “ 动画程序时长缩放 ”,来加速或减慢动画的时间,以查看加速或减慢状态下的动画是否会有问题。
- Show hardware layer updates:通过在 Android 设备的设置 APP 的开发者选项里启动 “ 显示硬件层更新 ”,当 Flash 硬件层在进行更新时会显示为绿色。使用这个工具可以让你查看在动画期间哪些不期望更新的布局有更新,方便你进行优化,以获得应用更好的性能。
布局
1、相应的 layout 资源目录(分为 layout 默认、layout-land 横屏、layout-large大屏幕竖屏、layout-large-land 大屏幕横屏)
2、百分比布局 (API 地址)
图片
1、文件放入相应的drawable资源目录
2、采用 .9 图片
3、采用矢量图
长度单位
1、dimen.xml文件放入相应的 values 资源目录
78.多线程
1个进程中可以开启多条线程,每条线程可以并发(同时)执行不同的任务 ,多线程技术可以提高程序的执行效率
2.多线程的原理
同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
思考:如果线程非常非常多,会发生什么情况? * CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源 * 每条线程被调度执行的频次会降低(线程的执行效率降低)
3.多线程的优缺点
通过并发提高程序的执行效率
能适当提高资源利用率(CPU、内存利用率)
3.2 多线程的缺点
开启线程需要占用一定的内存空间(默认情况下,每一条线程都占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能,线程越多,CPU在调度线程上的开销就越大,程序设计更加复杂:比如线程之间的通信、多线程的数据共享
get 和 post 区别:
GET 提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456。POST 方法是把提交的数据放在HTTP包的Body中。
GET 提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
GET 方式需要使用Request.QueryString 来取得变量的值,而POST方式通过Request.Form来获取变量的值。
GET 方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码.
类型名称 | 类型定义 | 类型取值 |
---|---|---|
boolean | 布尔值,作二元判断 | true, false |
byte | 8位有符号整数 | 最小值-2^7,最大值2^7-1 |
short | 16位有符号整数 | 最小值-2^15,最大值 2^15 - 1 |
int | 32位有符号整数 | 最小值(-2^31),最大值(2^31-1) |
long | 64位有符号整数 | -2^63~(2^63-1) |
float | 32位浮点数 | 1.4E-45~3.4028235E38 |
double | 64位浮点数 | 4.9E-324~1.7976931348623157E308 |
char | 16位Unicode字符 | 不适用 |
2). 实现Parcelable接口,这里Android的部分类比如Bitmap类就已经实现了,同时Parcelable在Android AIDL中交换数据也
FLAG_ACTIVITY_BROUGHT_TO_FRONT
这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。
FLAG_ACTIVITY_CLEAR_TOP
如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方 的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。
例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。
上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为 “multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创 建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实 例的onNewIntent()中。
这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任 何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager处启动一个Activity。
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果设置,这将在Task的Activity stack中设置一个还原点,当Task恢复时,需要清理Activity。也就是说,下一次Task带着 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它),这个Activity和它之 上的都将关闭,以至于用户不能再返回到它们,但是可以回到之前的Activity。
这在你的程序有分割点的时候很有用。例如,一个e-mail应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity来显示。这个 Activity应该作为e-mail应用程序Task的一部分,因为这是用户在这个Task中触发的操作。然而,当用户离开这个Task,然后从主画面 选择e-mail app,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的Activity在下 次用户返回到mail程序时都将全部清除。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置,新的Activity不会在最近启动的Activity的列表中保存。
FLAG_ACTIVITY_FORWARD_RESULT
如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个 新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的 Activity。
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),那么,系统会帮你设定。
FLAG_ACTIVITY_MULTIPLE_TASK
不要使用这个标志,除非你自己实现了应用程序启动器。与FLAG_ACTIVITY_NEW_TASK结合起来使用,可以禁用把已存的Task送入前台的 行为。当设置时,新的Task总是会启动来处理Intent,而不管这是是否已经有一个Task可以处理相同的事情。
由于默认的系统不包含图形Task管理功能,因此,你不应该使用这个标志,除非你提供给用户一种方式可以返回到已经启动的Task。
如果FLAG_ACTIVITY_NEW_TASK标志没有设置,这个标志被忽略。
FLAG_ACTIVITY_NEW_TASK
如果设置,这个Activity会成为历史stack中一个新Task的开始。一个Task(从启动它的Activity到下一个Task中的 Activity)定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台;在某个特定Task中的所有Activity总是保持相 同的次序。
这个标志一般用于呈现“启动”类型的行为:它们提供用户一系列可以单独完成的事情,与启动它们的Activity完全无关。
使用这个标志,如果正在启动的Activity的Task已经在运行的话,那么,新的Activity将不会启动;代替的,当前Task会简单的移入前台。参考FLAG_ACTIVITY_MULTIPLE_TASK标志,可以禁用这一行为。
这个标志不能用于调用方对已经启动的Activity请求结果。
FLAG_ACTIVITY_NO_ANIMATION
如果在Intent中设置,并传递给Context.startActivity()的话,这个标志将阻止系统进入下一个Activity时应用 Acitivity迁移动画。这并不意味着动画将永不运行——如果另一个Activity在启动显示之前,没有指定这个标志,那么,动画将被应用。这个标 志可以很好的用于执行一连串的操作,而动画被看作是更高一级的事件的驱动。
FLAG_ACTIVITY_NO_HISTORY
如果设置,新的Activity将不再历史stack中保留。用户一离开它,这个Activity就关闭了。这也可以通过设置noHistory特性。
FLAG_ACTIVITY_NO_USER_ACTION
如果设置,作为新启动的Activity进入前台时,这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()。
典型的,一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台。这个回调在Activity的生命周期中标记一个合适的点,并关闭一些Notification。
如果一个Activity通过非用户驱动的事件,如来电或闹钟,启动的,这个标志也应该传递给Context.startActivity,保证暂停的Activity不认为用户已经知晓其Notification。
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在Intent中设置,并传递给Context.startActivity(),这个标志将引发已经运行的Activity移动到历史stack的顶端。
例如,假设一个Task由四个Activity组成:A,B,C,D。如果D调用startActivity()来启动Activity B,那么,B会移动到历史stack的顶端,现在的次序变成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话,那么这 个标志将被忽略。
FLAG_ACTIVITY_SINGLE_TOP
如果设置,当这个Activity位于历史stack的顶端运行时,不再启动一个新的。
84.Android 中的context,activity,application有何区别?
相同点:activity,application都是context的子类
不同点:维护的生命周期不同,context维护的是当前的activity 的生命周期,application维护的是整个项目的生命周期。
避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context (继承类:public class GApplication extends Application)
3. 尽量使用静态类(全局),避免非静态的内部类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化
1) Context是一个抽象类,其具体实现在ContextImpl类中。
2) Context:描述的是访问application环境的全局信息,通过它可以访问application的资源和相关的类,其主要功能如下:
• 启动Activity
• 启动和停止Service
• 发送广播消息(Intent)
• 注册广播消息(Intent)接收者
• 可以访问APK中各种资源(如Resources和AssetManager等)
• 可以访问Package的相关信息
• APK的各种权限管理
1、优化一:复用convertView
Android系统本身为我们考虑了ListView的优化问题,在复写的Adapter的类中,比较重要的两个方法是getCount()和getView()。界面上有多少个条显示,就会调用多少次的getView()方法;因此如果在每次调用的时候,如果不进行优化,每次都会使用View.inflate(….)的方法,都要将xml文件解析,并显示到界面上,这是非常消耗资源的:因为有新的内容产生就会有旧的内容销毁,所以,可以复用旧的内容。
优化:
在getView()方法中,系统就为我们提供了一个复用view的历史缓存对象convertView,当显示第一屏的时候,每一个item都会新创建一个view对象,这些view都是可以被复用的;如果每次显示一个view都要创建一个,是非常耗费内存的;所以为了节约内存,可以在convertView不为null的时候,对其进行复用
public View getView(int pos, View convertView, ViewGroup parent){ if (convertView == null) { convertView = mInflater.inflate( R.layout.list_item, null); } ((TextView) convertView.findViewById(R.id.text)). setText(DATA[pos]); ((ImageView) convertView.findViewButId(R.id.icon)). setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2); return convertView; }
2、优化二:缓存item条目的引用——ViewHolder
findViewById()这个方法是比较耗性能的操作,因为这个方法要找到指定的布局文件,进行不断地解析每个节点:从最顶端的节点进行一层一层的解析查询,找到后在一层一层的返回,如果在左边没找到,就会接着解析右边,并进行相应的查询,直到找到位置。因此可以对findViewById进行优化处理,需要注意的是:
特点:xml文件被解析的时候,只要被创建出来了,其孩子的id就不会改变了。根据这个特点,可以将孩子id存入到指定的集合中,每次就可以直接取出集合中对应的元素就可以了。
优化:
在创建view对象的时候,减少布局文件转化成view对象的次数;即在创建view对象的时候,把所有孩子全部找到,并把孩子的引用给存起来
①定义存储控件引用的类ViewHolder
这里的ViewHolder类需要不需要定义成static,根据实际情况而定,如果item不是很多的话,可以使用,这样在初始化的时候,只加载一次,可以稍微得到一些优化
不过,如果item过多的话,建议不要使用。因为static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了。
static class ViewHolder{
//定义item中相应的控件
}
②创建自定义的类:ViewHolder holder = null;
③将子view添加到holder中:
在创建新的listView的时候,创建新的ViewHolder,把所有孩子全部找到,并把孩子的引用给存起来
通过view.setTag(holder)将引用设置到view中
通过holder,将孩子view设置到此holder中,从而减少以后查询的次数
④在复用listView中的条目的时候,通过view.getTag(),将view对象转化为holder,即转化成相应的引用,方便在下次使用的时候存入集合。
通过view.getTag(holder)获取引用(需要强转)
static class ViewHolder { TextView text; ImageView icon; } public View getView(int pos, View convertView, ViewGroup parent){ ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item, null); holder = new ViewHolder(); holder.text = (TextView) convertView.findViewById( R.id.text)); holder.icon = (ImageView) convertView.findViewButId( R.id.icon)); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text.setText(DATA[pos]); holder.icon.setImageBitmap((pos & 1) == 1 ? mIcon1 : mIcon2); return convertView; }
二、ListView中数据的分批及分页加载:
需求:ListView有一万条数据,如何显示;如果将十万条数据加载到内存,很消耗内存
解决办法:
优化查询的数据:先获取几条数据显示到界面上
进行分批处理—优化了用户体验
进行分页处理—优化了内存空间
说明:
一般数据都是从数据库中获取的,实现分批(分页)加载数据,就需要在对应的DAO中有相应的分批(分页)获取数据的方法,如findPartDatas ()
1、准备数据:
在dao中添加分批加载数据的方法:findPartDatas ()
在适配数据的时候,先加载第一批的数据,需要加载第二批的时候,设置监听检测何时加载第二批
2、设置ListView的滚动监听器:setOnScrollListener(new OnScrollListener{….})
①、在监听器中有两个方法:滚动状态发生变化的方法(onScrollStateChanged)和listView被滚动时调用的方法(onScroll)
②、在滚动状态发生改变的方法中,有三种状态:
手指按下移动的状态: SCROLL_STATE_TOUCH_SCROLL: // 触摸滑动
惯性滚动(滑翔(flgin)状态): SCROLL_STATE_FLING: // 滑翔
静止状态: SCROLL_STATE_IDLE: // 静止
3、对不同的状态进行处理:
分批加载数据,只关心静止状态:关心最后一个可见的条目,如果最后一个可见条目就是数据适配器(集合)里的最后一个,此时可加载更多的数据。在每次加载的时候,计算出滚动的数量,当滚动的数量大于等于总数量的时候,可以提示用户无更多数据了。
三、ListView中图片的优化:详看OOM异常中图片的优化
1、处理图片的方式:
如果自定义Item中有涉及到图片等等的,一定要狠狠的处理图片,图片占的内存是ListView项中最恶心的,处理图片的方法大致有以下几种:
①、不要直接拿路径就去循环decodeFile();使用Option保存图片大小、不要加载图片到内存去
②、拿到的图片一定要经过边界压缩
③、在ListView中取图片时也不要直接拿个路径去取图片,而是以WeakReference(使用WeakReference代替强引用。
比如可以使用WeakReference mContextRef)、SoftReference、WeakHashMap等的来存储图片信息,是图片信息不是图片哦!
④、在getView中做图片转换时,产生的中间变量一定及时释放
2、异步加载图片基本思想:
1)、 先从内存缓存中获取图片显示(内存缓冲)
2)、获取不到的话从SD卡里获取(SD卡缓冲)
3)、都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)
原理:
优化一:先从内存中加载,没有则开启线程从SD卡或网络中获取,这里注意从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅。
优化二:与此同时,在adapter里有个busy变量,表示listview是否处于滑动状态,如果是滑动状态则仅从内存中获取图片,没有的话无需再开启线程去外存或网络获取图片。
优化三:ImageLoader里的线程使用了线程池,从而避免了过多线程频繁创建和销毁,有的童鞋每次总是new一个线程去执行这是非常不可取的,好一点的用的AsyncTask类,其实内部也是用到了线程池。在从网络获取图片时,先是将其保存到sd卡,然后再加载到内存,这么做的好处是在加载到内存时可以做个压缩处理,以减少图片所占内存。
Tips:这里可能出现图片乱跳(错位)的问题:
图片错位问题的本质源于我们的listview使用了缓存convertView,假设一种场景,一个listview一屏显示九个item,那么在拉出第十个item的时候,事实上该item是重复使用了第一个item,也就是说在第一个item从网络中下载图片并最终要显示的时候,其实该item已经不在当前显示区域内了,此时显示的后果将可能在第十个item上输出图像,这就导致了图片错位的问题。所以解决之道在于可见则显示,不可见则不显示。在ImageLoader里有个imageViews的map对象,就是用于保存当前显示区域图像对应的url集,在显示前判断处理一下即可。
四、ListView的其他优化:
1、尽量避免在BaseAdapter中使用static 来定义全局静态变量:
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了。
2、尽量使用getApplicationContext:
如果为了满足需求下必须使用Context的话:Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题
3、尽量避免在ListView适配器中使用线程:
因为线程产生内存泄露的主要原因在于线程生命周期的不可控制。之前使用的自定义ListView中适配数据时使用AsyncTask自行开启线程的,这个比用Thread更危险,因为Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了线程执行池(ThreadPoolExcutor),这个类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。解决办法如下:
①、将线程的内部类,改为静态内部类。
②、在线程内部采用弱引用保存Context引用
Intent 的定义
Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service之间的交互。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
·
Intent属性的设置,包括以下几点:(以下为XML中定义,当然也可以通过Intent类的方法来获取和设置)
(1)Action,使用android:name特性来指定对响应的动作名。动作名必须是独一无二的字符串。
(2)Data,也就是执行动作要操作的数据
Android中采用指向数据的一个URI来表示,如在联系人应用中,一个指向某联系人的URI可能为:content://contacts/1。对于不同的动作,其URI数据的类型是不同的(可以设置type属性指定特定类型数据),如ACTION_EDIT指定Data为文件URI,打电话为tel:URI,访问网络为http:URI,而由content provider提供的数据则为content: URIs。
(3)type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
(4)category(类别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。
(5)component(组件),指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。
(6)extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。
Intent-Filter的定义
IntentFilter就是用于描述intent的各种属性, 比如action, category等
一些属性设置的例子:
<action android:name="com.example.project.SHOW_CURRENT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:mimeType="image/*" />
<data android:scheme="http" android:type="video/*" />
关于IntentFilter的几点注意事项:
(1).android.intent.action.MAIN 与 android.intent.category.LAUNCHER
android.intent.action.MAIN决定一个应用程序最先启动那个组件
android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里(说白了就是是否在桌面上显示一个图标)
这两个属性组合情况:
第一种情况:有MAIN,无LAUNCHER,程序列表中无图标
原因:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
第二种情况:无MAIN,有LAUNCHER,程序列表中无图标
原因:android.intent.action.MAIN决定应用程序最先启动的Activity,如果没有Main,则不知启动哪个Activity,故也不会有图标出现
所以这两个属性一般成对出现。
如果一个应用中有两个组件intent-filter都添加了android.intent.action.MAIN和
android.intent.category.LAUNCHER这两个属性, 则这个应用将会显示两个图标, 写在前面的组件先运行。
(2).关于隐式intent
每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 "android.intent.category.DEFAULT",所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 "android.intent.category.DEFAULT" category,不然将导致 Intent 匹配失败.
比如说一个activity组件要想被其他组件通过隐式intent调用, 则其在manifest.xml中的声明如下:
<activity android:name="com.gesture.QGestureListActivity">
<intent-filter>
<action android:name="com.google.test" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
(3).关于intent-filter匹配优先级
首先查看Intent的过滤器(intent-filter),按照以下优先关系查找:action->data->category
(4).android.intent.category.LAUNCHER与android.intent.category.HOME的区别
android.intent.category.LAUNCHER:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里,就是android开机后的主程序列表。
android.intent.category.HOME:按住“HOME”键,该程序显示在HOME列表里。
Android系统从下往上分为Linux内核层(linux kerner),运行库(runtime library),应用程序框架层,应用程序层
linuxkernel:负责硬件的驱动程序、网络、电源、系统安全以及内存管理等功能。
libraries和 androidruntime:libraries:即c/c++函数库部分,大多数都是开放源代码的函数库,例如webkit,该函数库负责 android网页浏览器的运行
applicationframework(应用软件架构),Java应用程序开发人员主要是使用该层封装好的api进行快速开发。
applications:该层是java的应用程序层,android内置e-mail、即时通信工具、浏览器、mp3播放 器等处于该层,java开发人员开发的程序也处于该层,而且和内置的应用程序具有平等的位置,可以调用内置的应用程序,也可以替换内置的应用程序。
1、src目录是源代码目录,所有允许用户修改的Java文件和用户自己添加的java文件都保存在这个目录中
2、gen目录是1.5版本新增的目录,用来保存ADT自动生成的java文件,例如R.java或AIDL文件
注意:R.java文件(非常重要)
a) R.java文件是ADT自动生成的文件,包含对drawable、layout和values目录内的资源的引用指针,Android程序能够直接通过R类引用目录中的资源
b) R.java文件不能手工修改,如果向资源目录中增加或删除了资源文件,则需要在工程名称上右击,选择Refresh来更新R.java文件中的代码
c) R类包含的几个内部类,分别与资源类型相对应,资源ID便保存在这些内部类中,例如子类drawable表示图像资源,内部的静态变量icon表示资源名称,其资源ID为0x7f020000。一般情况下,资源名称与资源文件名相同
3、android.jar文件是Android程序所能引用的函数库文件,Android通过平台所支持API都包含在这个文件中
4、assets目录用来存放原始格式的文件,例如音频文件、视频文件等二进制格式文件。此目录中的资源不能被R.java文件索引。,所以只能以资截流的形式读取。一般情况下为空
5、main.xml文件,是界面布局文件,利用XML语言描述的用户界面
6、res目录res是存放Android项目的各种资源文件,该目录里存放了android应用所用的全部资源,包括图片资源、字符串资源、样式资源、尺寸资源等等。
7、bin目录用于存放生成的目标文件,如Java的二进制文件、资源打包文件(.apk后缀)、Dalvik虚拟机的可执行文件性文件(.dex后缀)
8、AndroidManifest.xml是XML格式的Android程序声明文件,包含了Android系统运行Android程序前所必须掌握的重要信息,这些信息包含应用程序名称、图标、包名称、模块组成、授权和SDK最低版本等,而且每个Android程序必须在根目录下包含一个AndroidManifest.xml文件
AndroidMainfest.xml文件:
1) AndroidManifest.xml文件的根元素是manifest,包含了xmlns:android、package、android:versionCode和android:versionName共4个属性
2) xmlns:android定义了Android的命名空间,值为http://schemas.android.com/apk/res/android
3) package定义了应用程序的包名称
4) android:versionCode定义了应用程序的版本号,是一个整数值,数值越大说明版本越新,但仅在程序内部使用,并不提供给应用程序的使用者
5) android:versionName定义了应用程序的版本名称,是一个字符串,仅限于为用户提供一个版本标识
6) manifest元素仅能包含一个application元素,application元素中能够声明Android程序中最重要的四个组成部分,包括Activity、Service、BroadcastReceiver和ContentProvider,所定义的属性将影响所有组成部分
7) 第6行属性android:icon定义了Android应用程序的图标,其中@drawable/icon是一种资源引用方式,表示资源类型是图像,资源名称为icon,对应的资源文件为res/drawable目录下的icon.png
8) 第7行属性android:label则定义了Android应用程序的标签名称
8、default.properties文件记录Android工程的相关设置,该文件不能手动修改,需右键单击工程名称,选择“Properties”进行修改