赞
踩
1. 什么是Activity?
四大组件之一,一般的,一个用户交互界面对应一个activity
setContentView() ,// 要显示的布局
2. 请描述一下Activity 生命周期。
共有七个周期函数:
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
1.完整生命周期: 即一个activity从出现到消失,对应的周期方法是从onCreate到onDestroy
2.可见生命周期:从onStart()到onStop()方法,在这个周期中,用户可以看见Activity,但不一定能够与之交互,这两个方法可以随着状态的变化被执行多次。
3.前景生命周期:从onResume()到onPause()方法,在这个周期中,Activity处在其它Activity之前,即在Activity栈的最顶端,负责与用户进行交互,伴随着状态的变化,这两个方法可以被执行多次。
3. 两个Activity之间跳转时必然会执行的是哪几个方法。
一般情况比如说有两个activity,分别叫A,B ,当在A里面激活B组件的时候, A 会调用onPause()方法,然后B 调用onCreate() ,onStart(), OnResume() ,这个时候B覆盖了窗体, A会调用onStop()方法. 如果B呢是个透明的,或者是对话框的样式, 就不会调用onStop()方法
4. 横竖屏切换时候Activity的生命周期。
这个生命周期跟清单文件里的配置有关系
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期
默认首先销毁当前activity,然后重新加载
2、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
游戏开发中, 屏幕的朝向都是写死的.
5. 如何将一个Activity设置成窗口的样式。
可以自定义一个activity的样式,详细见手机卫士的程序详细信息
android:theme="@style/FloatActivity"
E:\day9\mobilesafe\res\values\style
6. 你后台的Activity被系统回收怎么办?如果后台的Activity由于某原因被系统回收可了,如何在被系统回收之前保存当前状态?
除了在栈顶的activity,其他的activity都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.
protected void onSaveInstanceState(BundleoutState) {
super.onSaveInstanceState(outState);
outState.putLong("id",1234567890);
}
public void onCreate(BundlesavedInstanceState) {
//判断savedInstanceState是不是空.
//如果不为空就取出来
super.onCreate(savedInstanceState);
}
7. 如何退出Activity?如何安全退出已调用多个Activity的Application?
退出activity 直接调用finish () 方法. //用户点击back键就是退出一个activity
退出activity 会执行onDestroy()方法.
1、抛异常强制退出:
该方法通过抛异常,使程序Force Close。
验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
//安全结束进程 android.os.Process.killProcess(android.os.Process.myPid());
2、记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
List<Activity> lists ; 在application 全集的环境里面
lists = new ArrayList<Activity>();
lists.add(activity);
for(Activity activity: lists)
{
activity.finish();
}
3、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
//给某个activity 注册接受接受广播的意图
registerReceiver(receiver,filter)
//如果过接受到的是关闭activity的广播 就调用finish()方法把当前的activity finish()掉
4、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
上面是网上的一些做法.
其实可以通过intent的flag 来实现.. intent.setFlag(FLAG_ACTIVITY_CLEAR_TOP)激活一个新的activity,然后在新的activity的oncreate方法里面finish掉.
Intent intent = new Intent(this,B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
局限性:所有的activity的启动模式都要是默认的启动模式
8.service是否在mainthread中执行, service里面是否能执行耗时的操作?
默认情况,如果没有显示的指定service所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面
service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件)
在子线程中执行new Thread(){}.start();
特殊情况,可以在清单文件配置service 执行所在的进程,让service在另外的进程中执行
<service android:process="cn.itcast.xxx"></service>
9. 两个Activity之间怎么传递数据?
基本数据类型可以通过. Intent 传递数据
extras.putDouble(key, value)
intent.putExtra(name, value)
// 通过intent putExtra 方法基本数据类型都传递
Bundlebundle = new Bundle();
bumdle.putShort(key, value);
intent.putExtras(bundle);
intent.putExtras(bundle)
获取到激活他的 getIntent();
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
intent.getStringExtra("key","value");
intent.getBooleanExtra("key","value")
Application 全局里面存放对象,自己去实现自己的application的这个类,基础系统的application, 每个activity都可以取到
让对象实现implements Serializable 接口把对象存放到文件上.
让类实现Serializable 接口,然后可以通过ObjectOutputStream //对象输出流
Filefile = new File("c:\\1.obj");
FileOutputStreamfos = new FileOutputStream(file);
ObjectOutputStream oos = newObjectOutputStream(fos);
Studentstu = new Student();
stu.setId("10001");
stu.setName("zs");
oos.writeObject(stu);
FileInputStreamfis = new FileInputStream(file);
ObjectInputStreamois = new ObjectInputStream(fis);
Student stu1 = (Student) ois.readObject();
System.out.println(stu1.getName());
Parcelable 和Serializable
Parcelable 把对象序列化到android操作系统的一块公用的内存空间
文件/网络
intent.setData(Uri)
Uri.fromFile(); //大图片的传递
contentResolver.getInputStream(url);
10. 怎么让在启动一个Activity是就启动一个service?
在activity的onCreate()方法里面startService();
11. 同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
比方说在激活一个新的activity时候, 给intent设置flag
Intent的flag添加FLAG_ACTIVITY_NEW_TASK
这个被激活的activity就会在新的task栈里面…
Intentintent = new Intent(A.this,B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
12.Activity怎么和service绑定,怎么在activity中启动自己对应的service?
startService() 一旦被创建 调用着无关 没法使用service里面的方法
bindService () 把service 与调用者绑定 ,如果调用者被销毁,service会销毁
bindService() 我们可以使用service里面的方法
bindService(). 让activity能够访问到 service里面的方法
构建一个intent对象,
Intent service = newIntent(this,MyService.class);
通过bindService的方法去启动一个服务,
bindService(intent, new MyConn(),BIND_AUTO_CREATE);
ServiceConnection对象(重写onServiceConnected和OnServiceDisconnected方法) 和BIND_AUTO_CREATE.
privateclass myconn implements ServiceConnection
{
publicvoid onServiceConnected(ComponentName name, IBinder service) {
//TODO Auto-generated method stub
//可以通过IBinder的对象去使用service里面的方法
}
publicvoid onServiceDisconnected(ComponentName name) {
//TODO Auto-generated method stub
}
}
13.什么是Service以及描述下它的生命周期。Service有哪些启动方法,有什么区别,怎样停用Service?
在Service的生命周期中,被回调的方法比Activity少一些,只有onCreate, onStart, onDestroy,
onBind和onUnbind。
通常有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。
1 通过startService
Service会经历 onCreate 到onStart,然后处于运行状态,stopService的时候调用onDestroy方法。
如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。
2 通过bindService
Service会运行onCreate,然后是调用onBind,这个时候调用者和Service绑定在一起。调用者退出了,Srevice就会调用onUnbind->onDestroyed方法。
所谓绑定在一起就共存亡了。调用者也可以通过调用unbindService方法来停止服务,这时候Srevice就会调用onUnbind->onDestroyed方法。
需要注意的是如果这几个方法交织在一起的话,会出现什么情况呢?
一个原则是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又bindService,Service只被创建一次。
如果先是bind了,那么start的时候就直接运行Service的onStart方法,如果先是start,那么bind的时候就直接运行onBind方法。
如果service运行期间调用了bindService,这时候再调用stopService的话,service是不会调用onDestroy方法的,service就stop不掉了,只能调用UnbindService, service就会被销毁
如果一个service通过startService 被start之后,多次调用startService 的话,service会多次调用onStart方法。多次调用stopService的话,service只会调用一次onDestroyed方法。
如果一个service通过bindService被start之后,多次调用bindService的话,service只会调用一次onBind方法。
多次调用unbindService的话会抛出异常。
15. 不用service,B页面为音乐播放,从A跳转到B,再返回,如何使音乐继续播放?
这个问题问的很山寨.默认不做任何处理,B里面的音乐都能播放.
遇到问题, 可以随机应变,灵活发挥,多考虑些细节,比如说这个题就可以这样说,说说你对startActivityForResult的理解()
A开启B的时候,用startActivityForResult()方法, B返回的时候把播放的状态信息返回给A ,A继续播放音乐.
16. 什么是IntentService?有何优点?
普通的service ,默认运行在ui main 主线程
Sdk给我们提供的方便的,带有异步处理的service类,
异步处理的方法 OnHandleIntent()
OnHandleIntent() 处理耗时的操作
17. 什么时候使用Service?
拥有service的进程具有较高的优先级
官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。
1.如果service正在调用onCreate, onStartCommand或者onDestory方法,那么用于当前service的进程相当于前台进程以避免被killed。
2.如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3.如果客户端已经连接到service(bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4.如果service可以使用startForeground(true)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
1.Service的特点可以让他在后台一直运行,可以在service里面创建线程去完成耗时的操作. 天气预报widget TimerTask Timer 定期执行timertask
2.Broadcastreceiver捕获到一个事件之后,可以起一个service来完成一个耗时的操作.
Broadcast receiver生命周期和响应时间很短
3.远程的service如果被启动起来,可以被多次bind, 但不会重新create. 索爱手机X10i的人脸识别的service可以被图库使用,可以被摄像机,照相机等程序使用.
18. 请描述一下Intent 和IntentFilter。
Android中通过Intent 对象来表示一条消息,一个Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个Intent 对象,消息“目的地”是必须的,而内容则是可选项。
通过Intent 可以实现各种系统组件的调用与激活.
Intent filter: 可以理解为邮局或者是一个信笺的分拣系统…
这个分拣系统通过3个参数来识别
Action: 动作 view
Data: 数据uri uri
Category : 而外的附加信息
Action 匹配
Action 是一个用户定义的字符串,用于描述一个Android 应用程序组件,一个Intent Filter 可以包含多个Action。在AndroidManifest.xml 的Activity 定义时可以在其<intent-filter >节点指定一个Action 列表用于标示Activity 所能接受的“动作”,例如:
<intent-filter >
<actionandroid:name="android.intent.action.MAIN" />
<actionandroid:name="cn.itcast.action" />
……
</intent-filter>
如果我们在启动一个Activity 时使用这样的Intent 对象:
Intent intent =new Intent();
intent.setAction("cn.itcast.action");
那么所有的Action 列表中包含了“cn.itcast”的Activity 都将会匹配成功。
Android 预定义了一系列的Action 分别表示特定的系统动作。这些Action 通过常量的方式定义在android.content. Intent中,以“ACTION_”开头。我们可以在Android 提供的文档中找到它们的详细说明。
URI 数据匹配
一个Intent 可以通过URI 携带外部数据给目标组件。在<intent-filter >节点中,通过<data/>节点匹配外部数据。
mimeType 属性指定携带外部数据的数据类型,scheme指定协议,host、port、path 指定数据的位置、端口、和路径。如下:
<data android:mimeType="mimeType"android:scheme="scheme"
android:host="host" android:port="port"android:path="path"/>
电话的uri tel: 12345
http://www.baidu.com
自己定义的uri itcast://cn.itcast/person/10
如果在Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时URI 数据匹配才会成功。
Category 类别匹配
<intent-filter >节点中可以为组件定义一个Category 类别列表,当Intent 中包含这个列表的所有项目时Category 类别匹配才会成功。
默认是DEFAULT
19.Intent传递数据时,可以传递哪些类型数据?
1.一般的基本数据类型 Intent .putextra() intent.getStringextra();
2.数据的uri,intent.setData() intent.getData();
20. 说说Activity,Intent,Service是什么关系。
麦当劳和麦当娜的关系是什么关系?
这种问题,就讲下activity,讲一下service,说一下通过intent去激活组件,传递数据.
说自己项目中有这样一个网络更新的功能,显示界面就用的activity, 后台有个service每隔半小时都去访问下服务器获取更新的数据…
开启服务用的是intent来开启
21. 请描述一下Broadcast Receiver。
有很多广播接收者,系统已经实现了.
广播分两种
有序广播
无序广播
指定接收者的广播. 是不可以被拦截掉的
<intent-filterandroid:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
onReceive() 方法.
abortBroadcast();
有序广播有一个特例
sendOrderedBroadcast(intent, receiverPermission, resultReceiver,scheduler, initialCode, initialData, initialExtras);
resultReceiver 广播接受者如果我们显示的指定了广播接收者
无论如何都会接受广播时间abortBroadcast(); 的方法不会终止广播时间
Sticky
sendStickyBroadcast(intent) // 阴魂不散的广播
Wifi设置
用于接收系统的广播通知, 系统会有很多sd卡挂载,手机重启,广播通知,低电量,来短信等,一个apk的安装成功….
手机卫士中自定义一个broadcastreceiver
<intent-filter android:> <action> sms_received</action> </intent-filter>
来获取短信到来的广播, 根据黑名单来判断是否拦截该短信.
画画板生成图片后,发送一个sd挂载的通知,通知系统的gallery去获取到新的图片.
Intent intent = newIntent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+Environment.getExternalStorageDirectory()));
sendBroadcast(intent);
22. 在manifest和代码中如何注册和使用broadcast receiver 。
设置广播接收者的优先级,设置广播接受者的action名字等…
详细见工程代码.
<intent-filter android:priority="1000">
<actionandroid:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
<receiverandroid:name=".SmsReceiver">
<intent-filterandroid:priority="1000">
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
<receiverandroid:name=".BootCompleteReceiver">
<intent-filter>
<actionandroid:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
代码中注册,如果代码没有执行,就接受不到广播事件
registerReceiver(receiver, filter)
23. 请介绍下ContentProvider是如何实现数据共享的。
把自己的数据通过uri的形式共享出去
android 系统下不同程序数据默认是不能共享访问
需要去实现一个类去继承ContentProvider
publicclass PersonContentProvider extends ContentProvider{
publicboolean onCreate(){
//..
}
query(Uri, String[], String, String[],String)
insert(Uri, ContentValues)
update(Uri, ContentValues, String, String[])
delete(Uri, String, String[])
}
content:// 代表contentprovider
技巧: 1.看urlmarcher.
2. 根据匹配码查看增删改查的具体实现
24. 请介绍下Android的数据存储方式。
文件 访问权限. sdcard
<data>/<data> context.openFileInput(name) 默认是私有的访问权限
数据库sqlite
SharedPreference <data>/<data>/shared_preps Context.modeprivate
网络 socket tcp udp ,
http httpurlconnection
ftp的网络
25. 为什么要用ContentProvider?它和sql的实现上有什么差别?
屏蔽数据存储的细节,对用户透明,用户只需要关心操作数据的uri就可以了,对应的参数 .
不同app之间共享,操作数据
但是contentprovider还可以去增删改查本地文件. xml文件的读取,更改,
网络数据读取更改
Sql也有增删改查的方法.
26. 请介绍下Android中常用的五种布局。
FrameLayout(帧布局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局)
FrameLayout
从屏幕的左上角开始布局,叠加显示, 实际应用播放器的暂停按钮.
LinearLayout
线性布局,这个东西,从外框上可以理解为一个div,他首先是一个一个从上往下罗列在屏幕上。每一个LinearLayout里面又可分为垂直布局
(android:orientation="vertical")和水平布局(android:orientation="horizontal"
)。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。
AbsoluteLayout
绝对布局犹如div指定了absolute属性,用X,Y坐标来指定元素的位置android:layout_x="20px"
android:layout_y="12px"
qq斗地主 qq游戏大厅 800*480800*480.apk fwvga 854*480
指定平板机型的游戏开发中经常用到绝对布局 widget 绝对布局
指定机型的平板游戏开发. 2.3 3.0
1. 界面布局 任务管理器 gridview
2. 手机任务管理 listview
lephone
lepad
RelativeLayout
相对布局可以理解为某一个元素为参照物,来定位的布局方式。主要属性有:
相对于某一个元素
android:layout_below="@id/aaa" 该元素在 id为aaa的下面
android:layout_toLeftOf="@id/bbb" 改元素的左边是bbb
相对于父元素的地方
android:layout_alignParentLeft="true" 在父元素左对齐
android:layout_alignParentRight="true"在父元素右对齐
TableLayout <table>
表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素,设定他的对齐方式 android:gravity="" 。
每一个布局都有自己适合的方式,另外,这五个布局元素可以相互嵌套应用,做出美观的界面。
oa 自动化生成报表 ,图标表示
css div
webview
27. 谈谈UI中, Padding和Margin有什么区别?
Padding 文字对边框, margin是控件与控件之间的距离
28.widget相对位置的完成在activity的哪个生命周期阶段实现。
这个题没看懂…
widget可以理解成桌面小控件,
也可以理解成某个button, imageview这样的控件…
onmeasure() // 计算控件在屏幕上的位子
某个view 要显示在界面 ondraw 被显示到界面上的
29. 请解释下在单线程模型中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(Messagemsg) {
// process incoming messageshere
}
};
Looper.loop();
}
}
30.AIDL的全称是什么?如何工作?
Android interface definition language(android接口定义语言) ,
用来跨进程的访问方法,
访问远程的服务的方法. 如何工作 day7 queryStudent .
手机卫士 Itelephony 接口挂断电话.
31. 请解释下Android程序运行时权限与文件系统权限的区别。
Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求, 打电话,访问网络,获取坐标,读写sd卡,读写联系人等..安装的时候会提示用户…
文件系统的权限是linux权限. 比如说sharedpreference里面的Context.Mode.private Context.Mode.world_read_able Context.Mode_world_writeable
777自己同组其他
root 是危险的行为
32. 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?
找到对应的浏览器的意图,传递数据URI , 激活这个意图
Intent intent = new Intent();
intent.setClassName(packageName, className);
Intent.setdata(uri);
33. 对android主线程的运用和理解。
主ui线程不能执行耗时的操作,
34. 对android虚拟机的理解,包括内存管理机制垃圾回收机制。
虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M ,
谈谈加载图片的时候怎么处理大图片的,
垃圾回收,没有引用的对象,在某个时刻会被系统gc掉.
System.gc(); 不是立刻去执行垃圾回收.
手机电视. 视频点播. Onstop() 通知gc();
别的界面图片白板.
遇到一个不可复现的bug, 不解决 won't fix
35.Framework工作方式及原理,Activity是如何生成一个view的,机制是什么。
反射 , 配置文件
可以讲下activity的源码,比如说每个activity里面都有window.callback和keyevent.callback,一些回调的接口或者函数吧.框架把activity创建出来就会调用里面的这些回调方法,会调用activity生命周期相关的方法.
setContentView();
普通的情况:
Activity创建一个view是通过 ondraw 画出来的, 画这个view之前呢,还会调用onmeasure方法来计算显示的大小.
Surfaceview 直接操作硬件 opengl .
图像要想被显示到界面上, 需要设备显卡, 显存.
写到显存.
36. android本身的一些限制,比如apk包大小限制,读取大文件时的时间限。
这个问题问的有问题,apk包大小限制不好说,
极品飞车有100M 还是能装到手机上,
世面google market 上大程序 主程序很小 5~10M 下载sdcard
15分钟之内申请退款
apk包,精简包, 素材存放在服务器. 游戏程序.
读大文件的时间限制应该是main线程里面的时间限制吧.5秒.
37. 如何加载的音乐信息,如何改善其效率。
Android提供mediascanner,mediaStore等接口, 音乐文件的信息都会存放到系统的数据库表中,可以通过content provider获取,
显示出来,改善效率,是个常见问题, 可以从以下几个方面作答,
分批加载数据, 延时加载数据, 合理使用缓存等...
Java虚拟机, 目标, 加快java程序执行速度
预先加载一些都会的使用的大的class的字节码, 提前加载.
时间换时间
空间换时间
38.ListView如何提高其效率?
复用convertview, 历史的view对象
异步加载数据, 分页加载数据,onscallLinster();
Static class ViewHolder
使用静态的view对象避免创建过多的view.
把下载后的数据缓存到数据库里
客户端和服务器协同作战 .
Http 请求
If-modify-since : 检查数据是否更新 1.html 2001年 302 拿缓存
39. 启动应用后,改变系统语言,应用的语言会改变么?
会
40. 启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?
区别是根据activity在manifest里面的配置,这个activity可能会放在不同的task栈里面
intent设置的flag flag_new_task
41.Android程序与Java程序的区别?
Android程序用android sdk开发,java程序用javasdk开发.
Android SDK引用了大部分的Java SDK,少数部分被AndroidSDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。
android sdk 添加工具jar httpclient ,pull openGL
将Java 游戏或者j2me程序移植到Android平台的过程中,
Android SDK 与Java SDK的区别是很需要注意的地方。
1.6的不支持 httpUrlconning 获取 last-modified信息的处理
simpleDataFormat
42.Android中Task任务栈的分配。
假如有三个Activity A B C,A跳到B,然后B跳到C,现在需要从C跳到A如何传递数据而且使效率最高呢?
首先我们来看下Task的定义,Google是这样定义Task的:a task is what the user experiences as an "application."It's a group of related activities, arranged in a stack. A task is a stack ofactivities, not a class or an element in the manifest file. 这意思就是说Task实际上是一个Activity栈,通常用户感受的一个Application就是一个Task。从这个定义来看,Task跟Service或者其他Components是没有任何联系的,它只是针对Activity而言的。
Activity有不同的启动模式, 可以影响到task的分配
Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多Activity,Task结束。
事件 Task栈(粗体为栈顶组件)
点开Email应用,进入收件箱(Activity A) A
选中一封邮件,点击查看详情(Activity B) AB
点击回复,开始写新邮件(Activity C) ABC
写了几行字,点击选择联系人,进入选择联系人界面(Activity D) ABCD
选择好了联系人,继续写邮件 ABC
写好邮件,发送完成,回到原始邮件 AB
点击返回,回到收件箱 A
退出Email程序 null
如上表所示,是一个实例。从用户从进入邮箱开始,到回复完成,退出应用整个过程的Task栈变化。这是一个标准的栈模式,对于大部分的状况,这样的Task模型,足以应付,但是,涉及到实际的性能、开销等问题,就会变得残酷许多。
比如,启动一个浏览器,在Android中是一个比较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。但与此同时,用浏览器打开一些内容,又是一般应用都会有的一个需求。设想一下,如果同时有十个运行着的应用(就会对应着是多个Task),都需要启动浏览器,这将是一个多么残酷的场面,十个Task栈都堆积着很雷同的浏览器Activity,
是多么华丽的一种浪费啊。
于是你会有这样一种设想,浏览器Activity,可不可以作为一个单独的Task而存在,不管是来自那个Task的请求,浏览器的Task,都不会归并过去。这样,虽然浏览器Activity本身需要维系的状态更多了,但整体的开销将大大的减少,这种舍小家为大家的行为,还是很值得歌颂的
standard", "singleTop","singleTask", "singleInstance"。
standard模式,是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。
而singleTop模式,基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视...)。这个模式,降低了位于栈顶时的一些重复开销,更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity,再一级级退出的时候,这是怎么样的用户体验...),很适合一些会有更新的列表Activity展示。一个活生生的实例是,在Android默认提供的应用中,浏览器(Browser)的书签Activity(BrowserBookmarkPage),就用的是singleTop。
singleTask,和singleInstance,则都采取的另辟Task的蹊径。
标志为singleTask的Activity,最多仅有一个实例存在,并且,位于以它为根的Task中。所有对该Activity的请求,都会跳到该Activity的Task中展开进行。singleTask,很象概念中的单件模式,所有的修改都是基于一个实例,这通常用在构造成本很大,但切换成本较小的Activity中。最典型的例子,还是浏览器应用的主Activity(名为Browser...),它是展示当前tab,当前页面内容的窗口。它的构造成本大,但页面的切换还是较快的,于singleTask相配,还是挺天作之合的。
singleInstance显得更为极端一些。在大部分时候singleInstance与singleTask完全一致,唯一的不同在于,singleInstance的Activity,是它所在栈中仅有的一个Activity,如果涉及到的其他Activity,都移交到其他Task中进行。这使得singleInstance的Activity,像一座孤岛,彻底的黑盒,它不关注请求来自何方,也不计较后续由谁执行。在Android默认的各个应用中,很少有这样的Activity,在我个人的工程实践中,曾尝试在有道词典的快速取词Activity中采用过,
是因为我觉得快速取词入口足够方便(从notification中点选进入),并且会在各个场合使用,应该做得完全独立。
大的apk 拆成很多小的apk
●Activity的android:taskAffinity=""属性姻缘关系
1.配置后当启动这个activity时就先去找有没有activity的亲和力属性相同有就加入这个
activity所在的任务中没有就新开任务
2.affinity起作用需要的条件而者具备一个:
1.intent包含FLAG_ACTIVITY_NEW_TASK标记
2.activity元素启用了allowTaskReparenting属性.
43. 在Android中,怎么节省内存的使用,怎么主动回收内存?
回收已经使用的资源,
合理的使用缓存
合理设置变量的作用范围… application 对象
//未来的某一段时间执行
System.gc();
44. 不同工程中的方法是否可以相互调用?
可以,列举aidl访问远程服务的例子.
45. 在Android中是如何实现判断区分电话的状态,去电,来电、未接来电?
Day8 showAddressService.java
46.dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
Dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面,
每个android程序系统都会给他分配一个单独的liunx uid(user id),
每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程.
47.sim卡的EF 文件有何作用
Sim卡相关的东西,没接触过
48. 如何判断是否有SD卡?
配置文件中有sd卡的权限, 通过environment的静态方法,
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
49. 嵌入式操作系统内存管理有哪几种,各有何特性。
页式,段式,段页,等…
50. 什么是嵌入式实时操作系统, Android 操作系统属于实时操作系统吗?
实时操作系统是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统。主要用于工业控制、军事设备、航空航天等领域对系统的响应时间有苛刻的要求,这就需要使用实时系统。又可分为软实时和硬实时两种,而android是基于linux内核的,因此属于软实时。
硬实时. 火星探测车.
软实时.
51. 一条最长的短信息约占多少byte?
中文70(包括标点),英文160,160个字节这个说法不准确,
要跟手机制式运营商等信息有关.
做实验,看源码
ArrayList<String> msgs =sms.divideMessage(message);
for (String msg : msgs) {
sms.sendTextMessage(phoneNumber, null, msg, pi, null);
}
52.Linux中跨进程通信的几种方式。
linux编程
# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
# 有名管道 (named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
# 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 ( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
# 共享内存( shared memory ):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
# 套接字( socket ) :套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
53. 谈谈对Android NDK的理解。
native develop kit 只是一个交叉编译的工具 .so
1.什么时候用ndk, 实时性要求高,游戏,图形渲染,
opencv (人脸识别) , ffmpeg ,rmvb mp5 avi 高清解码. ffmpeg,opencore.
2.为什么用ndk,ndk的优点 ,缺点 ,
我们项目中那些地方用到了ndk,
54. 谈谈Android的优点和不足之处。
1、开放性,开源ophone 阿里云( 完全兼容android)
2、挣脱运营商束缚
3、丰富的硬件选择 mtk android
4、不受任何限制的开发商
5、无缝结合的Google应用
缺点也有5处:
1、安全问题、隐私问题
2、卖手机的不是最大运营商
3、运营商对Android手机仍然有影响
4、山寨化严重
5、过分依赖开发商,缺乏标准配置版本过多
55.Android系统中GC什么情况下会出现内存泄露呢?
视频编解码/内存泄露
检测内存泄露 工具
导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。
Java带垃圾回收的机制,为什么还会内存泄露呢?
Vector v = new Vector(10);
for(int i = 1; i < 100; i++) {
Object o = new Object();
v.add(o);
o = null;
}//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。
Java 内存泄露的根本原因就是保存了不可能再被访问的变量类型的引用
56.Android UI中的View如何刷新。
在主线程中 拿到view调用Invalide()方法,查看画画板里面更新imageview的方法
在子线程里面可以通过postInvalide()方法;
57. 简单描述下Android 数字签名。
Android 数字签名
在Android系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系
Android系统要求每一个安装进系统的应用程序都是经过数字证书签名的,数字证书的私钥则保存在程序开发者的手中。Android将数字证书用来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序。
这个数字证书并不需要权威的数字证书签名机构认证(CA),它只是用来让应用程序包自我认证的。
同一个开发者的多个程序尽可能使用同一个数字证书,这可以带来以下好处。
(1)有利于程序升级,当新版程序和旧版程序的数字证书相同时,Android系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名。
(2)有利于程序的模块化设计和开发。Android系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块。
在签名时,需要考虑数字证书的有效期:
(1)数字证书的有效期要包含程序的预计生命周期,一旦数字证书失效,持有改数字证书的程序将不能正常升级。
(2)如果多个程序使用同一个数字证书,则该数字证书的有效期要包含所有程序的预计生命周期。
(3)Android Market强制要求所有应用程序数字证书的有效期要持续到2033年10月22日以后。
Android数字证书包含以下几个要点:
(1)所有的应用程序都必须有数字证书,Android系统不会安装一个没有数字证书的应用程序
(2)Android程序包使用的数字证书可以是自签名的,不需要一个权威的数字证书机构签名认证
(3)如果要正式发布一个Android,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt插件或者ant工具生成的调试证书来发布。
(4)数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。
58. 什么是ANR 如何避免它?
在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
Activity 5秒 broadcast10秒
耗时的操作 worker thread里面完成, handler message…AsynTask , intentservice.等…
59.android中的动画有哪几类,它们的特点和区别是什么?
两种,一种是Tween动画、还有一种是Frame动画。
Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化;
可以通过布局文件,可以通过代码
1、 控制View的动画
a) alpha(AlphaAnimation)
渐变透明
b) scale(ScaleAnimation)
渐变尺寸伸缩
c) translate(TranslateAnimation)
画面转换、位置移动
d) rotate(RotateAnimation)
画面转移,旋转动画
2、 控制一个Layout里面子View的动画效果
a) layoutAnimation(LayoutAnimationController)
b) gridAnimation(GridLayoutAnimationController)
另一种Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
62. 说说mvc模式的原理,它在android中的运用。
MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。
Android中界面部分也采用了当前比较流行的MVC框架,在Android中M就是应用程序中二进制的数据,V就是用户的界面。Android的界面直接采用XML文件保存的,界面开发变的很方便。在Android中C也是很简单的,一个Activity可以有多个界面,只需要将视图的ID传递到setContentView(),就指定了以哪个视图模型显示数据。
在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中显示。
63. 通过点击一个网页上的url 就可以完成程序的自动安装,描述下原理
Day11 AddJavascriptInterface
new Object{
callphone();
installapk();
}
64,Service和Activity在同一个线程吗
默认情况同一线程 main主线程 ui线程
65,java中的soft reference是个什么东西
StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于JVM 内,当没有任何对象指向它时 GC 执行后将会被回收
SoftReference 会尽可能长的保留引用直到JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存
应用详细见豆瓣客户端图片的缓存
66,udp连接和TCP的不同之处
tcp/滑动窗口协议. 拥塞控制.
udp不关心数据是否达到,是否阻塞
画面优先. tcp
流畅优先 udp
67,android开发中怎么去调试bug
逻辑错误 1.断点 debug 2. logcat , 界面布局,显示hierarchyviewer.bat
68.service里面可以弹土司么 ? 可以
69.写10个简单的linux命令
cat ls ps psw wc mv rm cd ping tracert findgrep tail vi gcc make ifconfig
startup dhcp
70JNI调用常用的两个参数
JNIEnv *env, jobject javaThis
71. 书写出android工程的目录结构
src
android. jar
asset
res
gen
manifest
72.ddms 和traceview的区别.
daivilk debug manager system
1.在应用的主activity的onCreate方法中加入Debug.startMethodTracing("要生成的traceview文件的名字");
2.同样在主activity的onStop方法中加入Debug.stopMethodTracing();
3.同时要在AndroidManifest.xml文件中配置权限
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
3.重新编译,安装,启动服务,测试完成取对应的traceview文件(adb pull/sdcard/xxxx.trace)。
4.直接在命令行输入traceviewxxxxtrace,弹出traceview窗口,分析对应的应用即可。
traceview 分析程序执行时间和效率
KPI : key performance information : 关键性能指标:
splash界面不能超过5秒
从splash 界面加载mainactivity不能超过0.7秒
73, 同步异步的理解,什么是同步,什么是异步,多次调用异步方法会出现什么问题.
74. 利用mvc的模式重构代码
1) 重构前的代码Bmi.java:
package com.demo.android.bmi;
import java.text.DecimalFormat;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class Bmi extends Activity {
/**Called when the activity is first created. */
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Listen for button clicks
Buttonbutton = (Button) findViewById(R.id.submit);
button.setOnClickListener(calcBMI);
}
privateOnClickListener calcBMI = new OnClickListener() {
@Override
publicvoid onClick(View v) {
DecimalFormatnf = new DecimalFormat("0.00");
EditTextfieldheight = (EditText) findViewById(R.id.height);
EditTextfieldweight = (EditText) findViewById(R.id.weight);
doubleheight = Double.parseDouble(fieldheight.getText().toString()) / 100;
doubleweight = Double.parseDouble(fieldweight.getText().toString());
doubleBMI = weight / (height * height);
TextViewresult = (TextView) findViewById(R.id.result);
result.setText("YourBMI is " + nf.format(BMI));
//Give health advice
TextViewfieldsuggest = (TextView) findViewById(R.id.suggest);
if(BMI > 25) {
fieldsuggest.setText(R.string.advice_heavy);
}else if (BMI < 20) {
fieldsuggest.setText(R.string.advice_light);
}else {
fieldsuggest.setText(R.string.advice_average);
}
}
};
}
Step1:抽取所有界面元件的声明和定义,整合到单独一个函数findViews()中;
// 声明 view
private Button button_calc;
private EditText field_height;
private EditText field_weight;
private TextView view_result;
private TextView view_suggest;
// 定义
private void findViews() {
button_calc= (Button) findViewById(R.id.submit);
field_height= (EditText) findViewById(R.id.height);
field_weight= (EditText) findViewById(R.id.weight);
view_result= (TextView) findViewById(R.id.result);
view_suggest= (TextView) findViewById(R.id.suggest);
}
此部分即是MVC中的V:View视图。
Step2:抽取程序的逻辑(即界面元件的处理逻辑),整合到函数setListensers()中;
//Listen for button clicks
private void setListensers() {
button_calc.setOnClickListener(calcBMI);
}
此部分即是MVC中的C:Controller控制器。
接着,onCreate()就显得非常简洁、明了了:
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
setListensers();
}
Step3:修改按钮监听器calcBMI中相应的部分(主要是变量已经在视图部分定义了);
private OnClickListener calcBMI = newOnClickListener() {
@Override
publicvoid onClick(View v) {
DecimalFormatnf = new DecimalFormat("0.00");
doubleheight = Double.parseDouble(field_height.getText().toString()) / 100;
doubleweight = Double.parseDouble(field_weight.getText().toString());
doubleBMI = weight / (height * height);
//Present result
view_result.setText("YourBMI is " + nf.format(BMI));
//Give health advice
if(BMI > 25) {
view_suggest.setText(R.string.advice_heavy);
}else if (BMI < 20) {
view_suggest.setText(R.string.advice_light);
}else {
view_suggest.setText(R.string.advice_average);
}
}
};
总之,此重构的目的无非是使程序的脉络更加清晰,即让人一眼望去,就能很容易地分辨出界面(View)应该写在哪里,程序逻辑(Controller)应该写在哪里,最终使维护和扩展代码变得更加容易!
其实,重构很简单,通读代码,感觉哪边不太爽,就改那边吧!(我目前的感受)
一个良好的代码应该是能让人感到舒服的!
2) 重构后的代码Bmi.java:
package com.demo.android.bmi;
import java.text.DecimalFormat;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class Bmi extends Activity {
privateButton button_calc;
privateEditText field_height;
privateEditText field_weight;
privateTextView view_result;
privateTextView view_suggest;
/**Called when the activity is first created. */
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
setListensers();
}
//定义
privatevoid findViews() {
button_calc= (Button) findViewById(R.id.submit);
field_height= (EditText) findViewById(R.id.height);
field_weight= (EditText) findViewById(R.id.weight);
view_result= (TextView) findViewById(R.id.result);
view_suggest= (TextView) findViewById(R.id.suggest);
}
//Listen for button clicks
privatevoid setListeners() {
calcbutton.setOnClickListener(calcBMI);
}
privateButton.OnClickListener calcBMI = new Button.OnClickListener() {
publicvoid onClick(View v) {
DecimalFormatnf = new DecimalFormat("0.0");
doubleheight = Double.parseDouble(field_height.getText().toString()) / 100;
doubleweight = Double.parseDouble(field_weight.getText().toString());
doubleBMI = weight / (height * height);
//Present result
view_result.setText(getText(R.string.bmi_result)+ nf.format(BMI));
//Give health advice
if(BMI > 25) {
view_suggest.setText(R.string.advice_heavy);
}else if (BMI < 20) {
view_suggest.setText(R.string.advice_light);
}else {
view_suggest.setText(R.string.advice_average);
}
}
};
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。