1. 什么是Activity?
四大组件之一,一般的,一个用户交互界面对应一个activity
setContentView() ,// 要显示的布局
button.setOnclickLinstener{
}
, activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件.
我开发常用的的有FragmentActivitiy,ListActivity , PreferenceActivity ,TabAcitivty等…
如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
① 抽取相同的代码
② 细化activity的生命周期 oncreate() findveiwbyid initview initdata 添加点击事件
2. 请描述一下Activity 生命周期。
生命周期描述的是一个类 从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法..
在这个过程中 会针对不同的生命阶段会调用不同的方法
Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:oncreate ondestroy onstop onstart onresume onpause
其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;
onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause;
这6个方法是相对应的,那么就只剩下一个onRestart方法了,这个方法在什么时候调用呢?
答案就是:在Activity被onStop后,但是没有被onDestroy,在再次显示此Activity时就调用onRestart(而不再调用onCreate)方法;
如果被onDestroy了,则是调用onCreate方法。
最后讲自己项目中的经验,比如说手机卫士每次进入某个界面的时候都要看到最新的数据,这个刷新列表的操作 就放在onStart()的方法里面.这样保证每次用户看到的数据都是最新的.
多媒体播放, 播放来电话. onStop() 视频, 视频声音设置为0 , 记录视频播放的位置 mediaplayer.pause();
onStart() 根据保存的状态恢复现场. mediaplayer.start();
在读文档的时候 还发现 activity还有两个方法 onPostResume() 和 OnPostCreate()这两个生命周期的方法,不过开发的时候没有用到过.
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|screenSize”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
游戏开发中, 屏幕的朝向都是写死的.
5. 如何将一个Activity设置成窗口的样式。
可以自定义一个activity的样式
android:theme=”@android:style/Theme.Dialog”
6. 你后台的Activity被系统回收怎么办?
如果后台的Activity由于某原因被系统回收可了,如何在被系统回收之前保存当前状态?
除了在栈顶的activity,其他的activity都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.
protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong(“id”, 1234567890); } public void onCreate(Bundle savedInstanceState) { //判断 savedInstanceState是不是空. //如果不为空就取出来 super.onCreate(savedInstanceState); }
7. 如何退出Activity?如何安全退出已调用多个Activity的Application?
抛异常不靠谱 系统会帮助把应用恢复起来
全局变量 不靠谱(慎用) 如果使用的话 一定要跟着非空判断 需要保存的内容 通过序列化 或者把对象转换成 json xml的字符串保存到本地
退出activity 直接调用 finish () 方法 . //用户点击back键 就是退出一个activity
退出activity 会执行 onDestroy()方法 .
1、抛异常强制退出:
该方法通过抛异常,使程序Force Close。
验证可以,但是,需要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
//安全结束进程 android.os.Process.killProcess(android.os.Process.myPid());
A->B->c
2、记录打开的Activity:
每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
List
lists = new ArrayList(); lists.add(activity); for(Activity activity: lists) { activity.finish(); }
3、发送特定广播: LocalBroadcastManager
在需要结束应用时,发送一个特定的广播,每个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掉.
8. service是否在main thread中执行, service里面是否能执行耗时的操作?
默认情况,如果没有显示的指定service所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面
service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
在子线程中执行 new Thread(){}.start();
Thread.currentThread().getName();
特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让service在另外的进程中执行
9. 两个Activity之间怎么传递数据?
基本数据类型可以通过. Intent 传递数据
extras.putDouble(key, value) intent.putExtra(name, value) // 通过intent putExtra 方法 基本数据类型 都传递 intent.getStringExtra(“key”,”value”); intent.getBooleanExtra(“key”,”value”) Bundle bundle = new Bundle(); bumdle.putShort(key, value); intent.putExtras(bumdle); intent.putExtras(bundle)
Application 全局里面存放 对象 ,自己去实现自己的application的这个类,基础系统的application , 每个activity都可以取到
让对象实现 implements Serializable 接口把对象存放到文件上.
让类实现Serializable 接口,然后可以通过 ObjectOutputStream //对象输出流
File file = new File(“c:\1.obj”); FileOutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos); Student stu = new Student(); oos.writeObject(stu); //从文件中把对象读出来 ObjectInputStream ois = new ObjectInputStream(arg0); Student stu1 = (Student) ois.readObject();
文件/网络
intent.setData(Uri) Uri.fromFile(); //大图片的传递
实现Parcelable
10. 怎么让在启动一个Activity时就启动一个service?
在activity的onCreate()方法里面 startService();
11. 同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
Singleinstance 运行在另外的单独的任务栈里面
Singletask 使用场景 应用的主界面
Singletop 使用场景 新闻类应用 新闻详情页 可以作为singletop 避免在栈顶创建多个实例
比方说在激活一个新的activity时候, 给intent设置flag
Intent的flag添加FLAG_ACTIVITY_NEW_TASK
这个被激活的activity就会在新的task栈里面…
Intent intent = new Intent(A.this,B.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
12. Activity怎么和service绑定,怎么在activity中启动自己对应的service?
startService() 一旦被创建 调用者无关 没法使用service里面的方法 onCreate->onStartCommand 多次调用startService多次执行onStartCommand stopService
bindService () 把service 与调用者绑定 ,如果调用者被销毁, service会销毁 onCreate->onBind()(只会执行一次)onServiceConnected 这个会执行多次 unbindService
bindService() 我们可以使用service 里面的方法
bindService(). 让activity能够访问到 service里面的方法
构建一个intent对象,
Intent service = new Intent(this,MyService.class);
通过bindService的方法去启动一个服务,
bindService(intent, new MyConn(), BIND_AUTO_CREATE);
ServiceConnection 对象(重写onServiceConnected和OnServiceDisconnected方法) 和BIND_AUTO_CREATE.
private class myconn implements ServiceConnection { public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub //可以通过IBinder的对象 去使用service里面的方法 } public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } }
推送 动态注册广播接收者 长连接 放到服务中
13. 14 .什么是Service以及描述下它的生命周期。Service有哪些启动方法,有什么区别,怎样停用Service?
在Service的生命周期中,被回调的方法比Activity少一些,只有onCreate, onStartCommand, 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() 处理耗时的操作 子线程处理完毕耗时操作后会自动退出
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(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
1.Service的特点可以让他在后台一直运行,可以在service里面创建线程去完成耗时的操作.
2.Broadcast receiver捕获到一个事件之后,可以起一个service来完成一个耗时的操作.
3.远程的service如果被启动起来,可以被多次bind, 但不会重新create. 索爱手机X10i的人脸识别的service可以被图库使用,可以被摄像机,照相机等程序使用.
18. 请描述一下Intent 和 Intent Filter。 IPC RPC android中进程间通信
Ipc inter process communication 进程间通信
Rpc remote processure call 远程过程调用
通过Intent Activity Service BroadCastReceiver
通过AIDL rpc 调用其他进程中的方法
通过内容提供者 ContentProvider
通过Socket
Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
通过Intent 可以实现各种系统组件的调用与激活.
Intent filter: 可以理解为邮局或者是一个信笺的分拣系统…
这个分拣系统通过3个参数来识别
Action: 动作 view
Data: 数据uri uri
Category : 而外的附加信息
Action 匹配
Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 Intent Filter 可以包含多个 Action。在 AndroidManifest.xml 的 Activity 定义时可以在其 节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如:
……
如果我们在启动一个 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 携带外部数据给目标组件。在 节点中,通过 节点匹配外部数据。
mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:
19. Intent传递数据时,可以传递哪些类型数据?
l 一般的基本数据类型,及对应的数组
l String及对应的数组、ArrayList
l Serializable、Parcelable及对应的数组、ArrayList
l 数据的uri, intent.setData() intent.getData();
20. 说说Activity,Intent,Service是什么关系。
麦当劳和麦当娜的关系是什么关系?遇到这样的问题千万不要被绕进去,不要去真的去说他们的关系.
这种问题,就讲下activity,讲一下service,说一下 通过intent去激活组件,传递数据.
说自己项目中有这样一个网络更新的功能,显示界面就用的activity, 后台有个service每隔半小时都去访问下服务器获取更新的数据…
开启服务用的是intent来开启
21. 请描述一下Broadcast Receiver。
广播分两种 有序广播、无序广播
指定接收者的广播 . 是不可以被拦截掉的
abortBroadcast();
系统有很多广播:sd卡挂载,手机重启,广播通知,低电量,电量改变,音乐改变、来电,来短信等….
手机卫士中自定义一个broadcast receiver
sms_received
来获取短信到来的广播, 根据黑名单来判断是否拦截该短信.
画画板生成图片后,发送一个sd挂载的通知,通知系统的gallery去获取到新的图片.
Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse(“file://”+Environment.getExternalStorageDirectory()));
sendBroadcast(intent);
LocalBroadcastManager 自定义的广播或者接收自定义广播的接收者 尽量使用LocalBroadcastManager 发送或注册 避免受其它应用影响
应用场景 开机自启动 进程保活(接收广播 电量变化 网络状态变化)
22. 在manifest和代码中如何注册和使用 broadcast receiver 。
设置广播接收者的优先级,设置广播接受者的action名字 等…
详细见工程代码.
23. 请介绍下ContentProvider是如何实现数据共享的。
通过事先约定好的协议,把自己的数据通过uri的形式共享出去。协议就是使用在uri上面的,通过uir能知道要操作的是哪一个资源。
UirMatcher.add(authories ,子路径,匹配码)
Content://authories/子路径
android 系统下 不同程序 数据默认是不能共享访问
Uri.匹配 每一个路径 对应一张表
需要去实现一个类去继承ContentProvider
public class PersonContentProvider extends ContentProvider{ public boolean onCreate(){ //.. } query(Uri, String[], String, String[], String) insert(Uri, ContentValues) update(Uri, ContentValues, String, String[]) delete(Uri, String, String[]) }
24. 请介绍下Android的数据存储方式。
数据库 orm object relation mapping 对象关系映射
Ormlite 反射 greendao 代码生成器 帮你写代码
Greendao效率高
操作数据插入到表中跟操作集合一样 不需要会sql语句
文件
sdcard
//包名/files/
Enviroment
context.openFileInput
openFileOutput
数据库 sqlite //包名/databases/xxx.db
SQLiteOpenHelper
Oncreate
表结构初始化
Onupgrade(SQliteDatabase, olderversion, newversion)
处理数据库升级
Getwriteabledatabase
SQLiteDatabase Getreadabledatabase
SharedPreference //包名/shared_prefs 通过sp保存敏感数据需要加密 可以还原 不能拿到原文 md5 sha
能够保存数据类型 int float boolean long string set
Sp保存对象 如果是javabean 可以把数据转换成json进行保存 直接存对象是不能存的
网络 socket tcp udp , http httpurlconnection
网络存储需要注意数据的缓存、同步、认证等一些细节
25. 为什么要用ContentProvider?它和sql的实现上有什么差别?
ContentProvider最重要的作用就是把用户的私有数据共享出来。
屏蔽数据存储的细节,对用户透明,用户只需要关心操作数据的uri就可以了
不同app之间共享,操作数据
Sql也有增删改查的方法.
但是contentprovider 还可以去增删改查本地文件. xml文件的读取,更改,
网络数据读取更改
Content://authories/子路径
Contentresolver
用没用过数据库 存了哪些内容 使用的时候用没用过orm框架
SQLiteDatabase
SQLiteOpenHelper
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*480 800*480.apk fwvga 854*480
指定平板机型的游戏开发中经常用到绝对布局 widget 绝对布局
4K:4096×2160
指定机型的平板游戏开发机顶盒开发。. 2.3 3.0
1. 界面布局 任务管理器 gridview
2. 手机 任务管理 listview
RelativeLayout
相对布局可以理解为某一个元素为参照物,来定位的布局方式。主要属性有:
相对于某一个元素
android:layout_below=”@id/aaa” 该元素在 id为aaa的下面
android:layout_toLeftOf=”@id/bbb” 改元素的左边是bbb
相对于父元素的地方
android:layout_alignParentLeft=”true” 在父元素左对齐
android:layout_alignParentRight=”true” 在父元素右对齐
TableLayout
表格布局类似Html里面的Table。每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素,设定他的对齐方式 android:gravity=”” 。
每一个布局都有自己适合的方式,另外,这五个布局元素可以相互嵌套应用,做出美观的界面。
oa 自动化 生成报表 ,图标 表示
27. 谈谈UI中, Padding和Margin有什么区别?
Margin:一个控件与另一个控件之间的间距
Padding:一个控件的内容与边框之间间距
28. widget相对位置的完成在activity的哪个生命周期阶段实现。
这个题没看懂…
widget可以理解成桌面小控件,
也可以理解成 某个button, imageview这样的控件…
onmeasure() // 计算 控件在屏幕上的位子、大小
onLayout
某个view 要显示在界面 ondraw 被显示到界面上的 .
android.widget.Button
29. 请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。
handlerThread
①Looper和MessageQueue创建 主线程
prepareMainLooper();
ThreadLocal 保存这个Looper 线程级单例 保证线程和Looper的对应关系 Looper在创建的时候创建了一个MessageQueue对象 通过Loop中的一个final成员变量保存起来
主线程不能再创建looper
子线程要想使用消息机制 要调用Looper.Prepare()方法 new Handler();
②Looper.loop(); 让消息队列循环起来
死循环 阻塞 ActivityThread main方法
Msg.target.dispatchMessage();
③ 发消息 handler.sendMessage() sendMessageAtTime(); messageQueue.enqueueMessage()
MessageQueue 消息队列如何保存消息 mMessage 消息队列的第一条消息
Message.next属性
④消息的创建 Message.obtain();
Message.recycle() 回收消息 msg.what = 0 msg.obj = null
Message mpool
50条
30. AsyncTask 原理?如何使用
3.0之后默认是串行的线程池 (一次只有一个线程在执行其余任务在排队)
如果要并行执行 需要自己写线程池 executeOnExecuter方法
31. 请解释下Android程序运行时权限与文件系统权限的区别。
Android程序执行需要读取到安全敏感项必需在androidmanifest.xml中声明相关权限请求, 打电话,访问网络,获取坐标,读写sd卡,读写联系人等..安装的时候会提示用户…
文件系统的权限是linux权限. 比如说sharedpreference里面的Context.Mode.private Context.Mode.world_read_able Context.Mode_world_writeable
如果创建的文件夹或目录没有指定权限,那么默认继承父目录的权限
1是,0否,最高权限111,即7,3组权限都最高,即777
openFileInput
openFileOutput(文件名,mode)
普通权限 Internet 蓝牙
危险权限 跟用户隐私相关 短信 电话 通信录 电话记录 sd卡 麦克风 摄像头 bodySensor
32. 系统上安装了多种浏览器,能否指定某浏览器访问指定页面?
找到对应的浏览器的意图,传递数据URI , 激活这个意图
Intent intent = new Intent(); intent.setClassName(packageName, className); intent.setData(Uri)
Activity 如果配置了intent-filter 或者没有intent-filter但是设置了Exported = true
都可以用 intent.setClassName(packageName, className); 打开
如果没有intent-filter 也没设置Exported = true 只能在自己的应用中打开
33. 对android主线程的运用和理解。
主ui线程不能执行耗时的操作,
34. 对android虚拟机的理解,包括内存管理机制垃圾回收机制。
与JVM之间的区别
Dalvik 基于寄存器,而 JVM 基于栈。(ARM 寄存器较多 16个)
Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码。android程序编译完之后生产.class文件,还有通过aapt工具生成的R.class等,然后dx工具会把.class文件处理成.dex文件,最终资源文件和.dex文件等打包成.apk文件。
垃圾回收
垃圾回收包含两个过程:
判定阶段,也就是判断哪些对象可以被回收,
收集阶段,是指具体的回收策略。
判定阶段主要有两种方式
引用计数,对象每多一个引用计数加1,少一个引用计数减1,计数为0时就表示这个对象可以被回收了。但是引用计数有个缺点,不能判断循环引用的情况,所以就有了下面的方式
根搜索,从一些根对象(GCRoot)开始遍历搜索,如果一个对象无法被搜索到,说明这个对象可以被回收了。
可以作为GCRoot的对象:
1 一些虚拟机栈中的对象;2 方法区中的类静态属性对象;3 方法区中的常量对象;4 Native栈中JNI的引用对象
收集阶段主要有四种方式
(mark-sweep) Android采用的垃圾回收机制
标记清除,最简单的算法,讲标记好的对象直接清除,速度快,但效率不高,内存碎片
复制算法,每次使用可用内存的一半,收集时将可用对象复制到另一半内存,回收这一半
标记整理,将存活对象整理到内存区域的一端,剩余部分回收
(jvm)
分代回收,将内存区域按对象存活周期划分为青年代和老年代等,不同区域采用上面不同的收集算法。(大部分对象创建之后很快就没用了,每次GC回收的对象90%都是上次GC之后创建的,如果对象可以活过一个GC周期那么在后续几次GC中变成垃圾的几率很小)
虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M 。
谈谈加载图片的时候怎么处理大图片的,d System.gc();
垃圾回收,没有引用的对象,在某个时刻会被系统gc掉.
Dalvik与ART androidruntime
Android5.0 之前使用Dalvik虚拟机,之后使用ART虚拟机,下面是一些比较:
Dalvik在运行时将字节码转换为机器码,ART在安装的时候就转换为机器码,这样安装好的应用会占用更大的空间,但是运行时少了转换的时间,所以运行更快
ART提供了更好的垃圾回收表现,将垃圾回收时,程序的暂停次数由两次(分析、清理)减少到一次;程序暂停时,并行的进行垃圾回收处理;回收新近分配的、生命期短的对象,垃圾回收器花费的时间更少
Android垃圾回收 根搜索判定方式 标记清理的回收方式 (dalvik) art(标记清理 分带回收)
减少应用卡顿的方法 避免大量创建小对象 如果需要大量的小对象 可以搞对象池 跟Message类似 16ms刷新一帧
JVM 分代回收
35. Framework层启动流程,
- 在init.rc中配置Zygote启动参数
2.启动Socket服务端口
当Zygote服务从app_process开始启动后,会启动一个Dalvik虚拟机,虚拟机第一个执行的java类就是ZygoteInit.java,该类第一个重要的工作就是启动一个Socket服务端口,该Socket端口用于接收启动新进程的命令。
3.加载preload-classes
在Zygote类的main()函数中,创建完Socket服务端后还不能立即孵化出新的进程,因为这个“卵”还没有必须的“核酸”,这个“核酸”就是指预装的Framework大部分类及资源。
4.加载preload-resources
preload-resources包含两类资源,一类是drawable资源,一类是color资源。加载这些资源是在preloadResource()函数中完成的,该函数调用preloadDrawable()和preloadColorStateLists()加载这两类资源,原理就是把这些资源读出来放到一个全局变量中,只要该类对象不被销毁,这些全局变量就会一直保存。
启动java虚拟机
Zygote进程中 包含了 socket服务端 预加载的framework层的类和资源(图片 color)
Fork 分叉出第一个进程 SystemServer
5.使用fork启动新的进程
fork是Linux系统的一个系统调用,作用就是复制当前进程产生一个新的进程。除了进程id不同,新进程将拥有和原始进程完全相同的进程信息。进程的信息包括该进程所打开的文件描述符列表、所分配的内存等。当新进程被创建后,两个进程将共享已经分配的内存空间,如果其中一个需要向内存中写入数据时,操作系统才复制一份目标地址空间,并将要写的数据写入到新的地址中。这种“仅当写的时候才复制”的机制可以最大限度的在多个进程中共享物理内存。
SystemServer 进程是如何启动的?
SystemServer进程是Zygote孵化出的第一个进程,然后再配置SystemServer进程的环境。
1.启动各种系统服务线程
SystemServer进程在Android运行环境中扮演了“神经中枢”的作用,APK应用中能够直接交互的大部分系统服务都在该进程中运行,常见的有WindowManagerServer(Wms)、ActivityManagerService(Ams)、PackageManagerServer(Pms),这些系统服务都是以一个线程的方式存在于SystemServer进程中。
2.启动第一个Activity
当以上服务线程都启动后,其中Ams服务是systemReady()调用完成最后启动的,在Ams的systemReady()函数的最后一段代码则发出了启动任务队列中最上面一个Activity消息。
在Ams的startHomeActivityLocked()中,系统发出了一个category字段包含CATEGORY_HOME的intent,代码如下:
intent.setComponent(mTopComponent); if(mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL){ intent.addCategory(Intent.CATEGORY_HOME); }
只要应用声明自己能够响应该Intent,那么就可以被认为是Home程序。当系统中有多个程序能够响应该Intent时,系统会弹出一个对话框,让用户选择启动哪个程序,也允许用户记住该选择。
到此第一个Activity就启动了。
Init.c 解析init.rc 以服务的形式启动zygote进程
zygoteInit.java
Zygote进程中 包含了 socket服务端 预加载的framework层的类和资源(图片 color) 创建dvm/art
分叉一个进程 systemserver 启动各种系统的服务 systemReady
startHomeActivityLocked()启动launcher
36. android本身的一些限制,比如apk包大小限制,读取大文件时的时间限。
64k方法数限制 多dex 65536
Java->.class->dex
Class1.dex
Class2.dex
64k方法数包括你自己写的方法 也包括引入的三方库的方法
三方库精简方法数 progard混淆 可以避免64k方法问题
这个问题问的有问题, apk包大小限制不好说,
极品飞车有100M 还是能装到手机上,
世面google market 上大程序 主程序 很小 5~10M 下载sdcard
15分钟之内 申请退款
apk包,精简包, 素材存放在服务器. 游戏程序.
.class->.dex 一个dex最多包含64k个方法
Multidex 多个dex 减少方法数
①引入别人jar包的时候 可以只用自己有用的部分
64k 分包 方法数不能超过65536个 multidex
Android Dalvik 可执行文件.dex中的java方法数不能超过64k
单个.dex文件最多能引用的方法数是65536个
AndroidFramework 和第三方函数库以及APP自身的方法
解决方法:
5.0之前 (api level 21) 拆分dex classes.dex主文件
Google MultiDex Support Library
/extras/android/support/multidex/目录中找到
5.0之后 art 支持从apk文件中加载多个.dex
尽量避免 64k 三方的库 可以只使用有用的部分
Proguard混淆
37. 如何加载的音乐信息,如何改善其效率。
Android提供mediascanner,mediaStore等接口, 音乐文件的信息都会存放到系统的数据库表中,可以通过content provider获取,
显示出来,改善效率,是个常见问题, 可以从以下几个方面作答,
分批加载数据, 延时加载数据, 合理使用缓存等…
38. ListView如何提高其效率?
复用convertview , 历史的view对象
减少子孩子查询的次数 viewholder
异步加载数据, 分页加载数据,
使用静态的view对象 避免创建过多的view.
减少加载item的时间
缓存
异步
延迟加载
用空间换时间
16ms 刷新一次 60fps
39. 启动应用后,改变系统语言,应用的语言会改变么?
Intent.ACTION_LOCALE_CHANGED
i18n
在工程res文件下添加对应语种的values文件,ar:阿拉伯语, en:英语 zh_rCN: 简体中文
在strings.xml和arrays.xml需要国际化的字符串进行相应得翻译
//应用内配置语言 Resources resources =getResources();//获得res资源对象 Configuration config = resources.getConfiguration();//获得设置对象 DisplayMetrics dm = resources.getDisplayMetrics(); config.locale = Locale.SIMPLIFIED_CHINESE; //简体中文 resources.updateConfiguration(config, dm);
40. 启动一个程序,可以主界面点击图标进入,也可以从一个程序中跳转过去,二者有什么区别?
Intent mIntent = new Intent(); mIntent.setClassName(“com.android.calculator2”,”com.android.calculator2.Calculator”); mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(mIntent);
41. Android程序与Java程序的区别?
简单地说,一种是操作系统,一种是开发语言。具体来说,Android是一种基于Linux的开放源码操作系统,主要用于便携设备(智能手机,平板电脑)。Java是一种面向对象的编程语言,它的最大的特点就是开源和免费,这因为如此,中国的大部分大型的软件系统是用Java开发的。
Android和Java的联系:
Android的应用层上的应用程序是用Java编写的,以Java作为开发语言,但是,Java并不等同于Android,因为Android SDK引用了Java SDK的大部分,少数部分被Android SDK所抛弃。
所以,要想从事Android的开发,就必须有Java基础。
Android程序用android sdk开发,java程序用javasdk开发.
Android SDK引用了大部分的Java SDK,少数部分被Android SDK抛弃,比如说界面部分,java.awt swing package除了java.awt.font被引用外,其他都被抛弃,在Android平台开发中不能使用。
将Java 游戏或者j2me程序移植到Android平台的过程中,
Android SDK 与Java SDK的区别是很需要注意的地方。
42. 手写一个单例模式,能不能保证使用时对象的唯一性
a、饿汉式和懒汉式
b、这两种方法都不能保证使用时对象的唯一性。比如,当对象是可序列化的,保存对象到本地后,每次反序列化都是生成了一个新的对象。
c、最好的实现单例模式的方案为,编写一个包含单个元素的枚举。程序员无法自己new出枚举对象,保证了只能有一个对象。同时枚举的序列化机制也不会在反序列化时创建出新的对象,保证对象的唯一性。Enum{
}
工厂
简单工厂
工厂方法
抽象工厂
模板 适配器 装饰
43. 如何避免OOM
a. 图片过大导致OOM
Android 中用bitmap时很容易内存溢出,比如报如下错误:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget。
解决方法:
方法1: 等比例缩小图片 BitmapFactory.Options inSamplesize = 2
方法2:使用LruCache机制管理图片。限制图片的内存上限,并及时地进行recyle()操作 提高效率 节省流量
方法3:使用加载图片框架处理图片,如专业处理加载图片的ImageLoader图片加载框架。
服务端控制: ①确保下载的每一张图片都符合ImageView控件的大小 200*100 150*75 (ImageServer 处理图片服务器)
②低流量模式 2g 3g
③急速模式 不加载图片 使用默认占位图
b.界面切换导致oom
c.查询数据库没有关闭cursor
d.内存泄露导致oom
子线程加载数据 activity开子线程 及时退出线程
子线程代码执行完了 线程自动会被回收
While(flag&&)
static handler泄露
Context泄露
一个应用几个上下文
Application Activity Service
largeHeap = true
多个进程
申请native堆 malloc 突破dalvik的限制
OOM原因 java虚拟机 要申请的内存<可用堆内存 dalvik/art大小固定的 6G内存
避免OOM
①代码 图片压缩 资源释放 handler/匿名内部类 使用的时候要注意如果有长时间执行的任务当组件销毁时需要退出未执行完的任务
②服务器配合 图片可以返回多种尺寸 列表中加载小图
③ 增加自己应用堆内存的占用量 清单文件 largeHeap 多个进程 申请native堆
44. dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念
a、每个dvm虚拟机都是linux里面的一个进程.
b、dvm的进程是dalivk虚拟机进程,每个android程序都运行在自己的进程里面,
c、三个进程不是一个概念,但是在使用中由于一个dvm虚拟机就是一个linux进程,同时一个虚拟机只运行一个应用,所以也默认三者是同一个可以统一使用。
45. 开发过程中使用到哪些自定义控件
pull2RefreshListView 下拉刷新
LazyViewPager 只加载当前页
SlidingMenu 侧栏菜单
ToggleButton 滑动的开关
View/ ViewGroup绘制
测量 onMeasure onMeasure
布局 onLayout
绘制 onDraw
动画
touch事件
Activity->ViewGroup->View
一个touch事件 由一个down 0~n个move 一个up组成 down事件比较重要的
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
ViewGroup 的onTouchEvent down返回true onInterceptTouchEvent 拦截了move事件 move 和up都由ViewGroup处理
View 的onTouchEvent down返回 true cancel事件
requestDisallowInterceptTouchEvent 请求不拦截 只对move和up有效
46. 如何判断是否有SD卡?
配置文件中有sd卡的权限, 通过environment的静态方法,
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
47. 项目如何向低版本兼容
a、样式兼容:
(1)使用兼容包中的样式,如v7\v4 中的Compat 相关样式。
(2)定义多个不同value文件夹,不同版本指定不同样式。
b、布局兼容:
定义多个不同layout-verson(verson为版本数字) 的文件夹,不同版本指定不同的布局文件。
c、高版本代码兼容方式:
(1)尽量使用兼容包中的API,如getSupportActionBar, getSupportFragmentManager() 等。
(2)使用系统Version 来判断,使低版本系统不能执行高版本代码。同时使用 @TargetApi 来消除eclipse、AS 等工具报错。
Dimens 常用分辨率 1280 720 1920*1080 2k 2560 1440 16:9屏幕
底部虚拟按键 占用屏幕分辨率 1800*1080
48. 介绍一下你的项目架构
架构是程序的骨架,确定了总体的接口,要求具体的子类实现细节处理。并不是非要用到反射、注解等高级技术才能叫架构。
a、界面架构 BaseActivity,BaseFragmen。拆解onCreate过程为initView、initListener、initData
b、网络架构 volley 13年谷歌开发大会 okhttp 14年 android-async-http
c、图片、文件、数据库等数据数据管理架构 orm greendao ormLite
BitmapFun sample
Picasso
Fresco
Android-universal-Image-Loader
49. 谈谈对Android NDK的理解。
大公司/金融相关/硬件
图片处理/视频 / 登陆 密码的加密/ fork 进程 做推送进程的保活
美图秀秀
看懂别人写的c 需要传递的参数
Jni java->c
处理图片的方法( 接收两个参数 一个是int类型数组的指针 数组的长度)
Bitmap-> int[] ->jni javaint类型数组 -> c int* jni.h
processPic(int*p , int length);
Jni.h 结构体 jniNativeinterface 定义了一系列函数指针 函数指针 ① java基本数据类型和C基本数据类型的相互转换 ② c 通过反射的方式 回调java方法 操作java类的成员变量
声明本地方法 native
Android.mk
Application.mk
本地方法命名规则 Java_包名类名本地方法名(JNIEnv* , jobject) jclass
native develop kit 只是一个交叉编译的工具 .so
Jni 推送进程保活 推送 后台开一个service 维持一个跟服务端的长连接 tcp 10 30分钟(心跳包)
fork c进程
保活联盟 极光 百度 个推 信鸽 友盟 /华为 小米 走系统的通道 透传/非透传 收到推送之后的操作 只能调用api指定的方法
TabHostActivity 3.0过时
金融类
可逆 dex (手机的用户信息) 不可逆 md5 sha (用户名 密码)
不可逆 md5 sha 不能获取原文 密码的保存
可逆 des 可以获取原文
对称 非对称
购物类应用 订单提交到服务端 加密 可逆加密
用户名 密码 不可逆
1.什么时候用ndk, 实时性要求高,游戏,图形渲染, opencv (人脸识别) , ffmpeg , rmvb mp5 avi 高清解码. ffmpeg, opencore.
2.为什么用ndk
我们项目中那些地方用到了ndk,
进程保活 长连接一般都在service里 保证service不被杀死 或者说 杀死了能再启动起来
广播接收者 接受系统广播 开机 网络变化 应用卸载安装 电量变化
通过forkC进程 做进程守护 jni 5.0一下有效 40%
注册推送服务 收到推送触发操作 小米/华为
保活联盟
50. 谈谈Android的优点和不足之处。
1、开放性,开源 ophone 阿里云( 完全兼容android)
2、挣脱运营商束缚
3、丰富的硬件选择 mtk android
4、不受任何限制的开发商
5、无缝结合的Google应用
缺点也有5处:
1、安全问题、隐私问题
2、卖手机的不是最大运营商
3、运营商对Android手机仍然有影响
4、山寨化严重(碎片化)
5、过分依赖开发商,缺乏标准配置
51. Android系统中GC什么情况下会出现内存泄露呢?视频编解码/内存泄露
检测内存泄露 工具
Leakcanery
导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器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引用这些对象。 Oncreate)(){ New Thread(){ Run(){ While(true){ } } }.start(); }
Java 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用
52. Android UI中的View如何刷新。
在主线程中 拿到view调用Invalide()方法
在子线程里面可以通过postInvalide()方法;
View view; view.invalidate();//主线程 view.postInvalidate();//子线程 requestLayout();
53. 简单描述下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只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。
54. 什么是ANR 如何避免它?
在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
耗时的操作 worker thread里面完成, handler message…AsynTask , intentservice.等…
55. android中的动画有哪几类,它们的特点和区别是什么?
帧动画, 补间动画, 属性动画;
l 帧动画(Frame Animation)一般用于图片的切换,实现生成连续的gif图效果
l 补间动画(Tween Animation)分为平移(Translate)、旋转(Rotate)、缩放(Scale)、不透明度(Alpha);补间动画只是改变了View的显示效果
l 属性动画(Property Animation),Android3.0 (API11)及以后出现的功能,3.0之前的版本可使用github第三方开源库nineoldandroids.jar进行支持。支持对所有View能更新的属性的动画,如translationX水平平移, translationY竖直平移,alpha透明度, left左边位置, rotation旋转角度, scale缩放等,
l 属性动画不仅能实现补间动画的所有效果,而且是对view或任意对象的属性的不断进行的值操作。比如一个Button的位移,补间动画只是重绘了view,并没有真正的去改变Button的位置,点击事件还是停留在原来的位置,而属性动画就是在真正改变Button的位置;
56. 说说mvc/mvp模式的原理,它在android中的运用。
a、MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。
b、Android里MVC模式的使用随处都可以见到。最基本的就是控件对象,xml布局文件,Activity类。以及数据集合,ListView,Adapter。
57,java中的soft reference是个什么东西
a、StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收
b、SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存
c、WeekReference 在每次GC时都被回收
d、在以前的开发里,图片的缓存多数使用软引用,保证内存不足时图片能够及时被回收。在Android2.3版本之后软引用的功能被修改为弱引用一样,导致图片总是要不断重新加载,性能很差。新的图片缓存实现都是LruCache机制。
58,说说LruCache底层原理
a、LruCache使用一个LinkedHashMap简单的实现内存的缓存,没有软引用,都是强引用。如果添加的数据大于设置的最大值,就删除最先缓存的数据来调整内存。
b、通过构造方法初始化的maxSize值,它表示这个缓存的最大值是多少。一般都是可用的内存大小的八分之一, Runtime.getRuntime().maxMemory() / 8,
c、插入图片时首先会判断插入后的size大小是否超过maxSize,如果超过了,就删除最长时间未使用的缓存。这个操作将一直循环下去,直到size比maxSize小或者缓存为空。
59,udp连接和TCP的不同之处 http
Tcp/ip 协议族
4层 http 应用层协议 tcp/udp ip 物理
http socket
http 提交方式 7种 trace delete put head option
常用的2种 get post
Get 参数通过url拼接 长度限制 浏览器限制 2k~8k
Post 通过请求体 以流的形式传到服务端
响应码 200 302 304 404 500 206 Range
UDP
l 将数据及源和目的封装成数据包中,不需要建立连接
l 每个数据报的大小在限制在64k内
l 因无连接,是不可靠协议
l 不需要建立连接,速度快
TCP
l 建立连接,形成传输数据的通道
l 在连接中进行大数据量传输
l 通过3次握手完成连接,是可靠协议
l 必须建立连接,效率会稍低
UDP应用:视频会议、聊天程序、桌面共享等对于一些丢失数据不是很重要的软件,类似于生活中的对讲机
TCP 应用:下载,类似现实生活中的打电话
http->TCP->IP->底层硬件协议
TCP/UTP 流的传输 http 对流的封装 rtsp 直播的协议
60, android开发中怎么去调试bug
逻辑错误
1.断点 debug
2. logcat
Wiki
知识库
接口文档
业务流程说明
Jira(分配任务 监督任务进度 处理bug 跟进bug状态)
无法复现
已解决
以后解决
无法解决
关闭任务
开始处理
重新打开
bug重开数据 1 a b c d
分配任务
61.service里面可以弹土司么
可以
62.手写算法
a、一般面试考察的都是计算机入门的基本算法,比如排序和查找,并且会要求在纸上手写Java代码或伪代码。
b、排序最基础的是冒泡排序。如果可以使用快速排序,可以认为学习能力优秀。
c、查找最基础的算法是有序数组的折半查找。
d、对于复杂的测试,比如让现场写一个自定义控件。可以分析一下实现思路,尽量不要在现场写代码,除非有极大的把握完成。第一思路不清晰,不一定能实现出来,第二实现过程中难免会有很多bug,在现场环境下会极大的打击自信。工作里都是一周以上才能完成一个自定义控件,并不是像我们上课,一天可以写好几个。。。
//继承view
//
63. JNI调用常用的两个参数
JNIEnv *env, jobject javaThis
64. 书写出android工程的目录结构
src
android. jar
asset
res
gen
manifest
65. 利用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 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Listen for button clicks Button button = (Button) findViewById(R.id.submit); button.setOnClickListener(calcBMI); } private OnClickListener calcBMI = new OnClickListener() { @Override public void onClick(View v) { DecimalFormat nf = new DecimalFormat("0.00"); EditText fieldheight = (EditText) findViewById(R.id.height); EditText fieldweight = (EditText) findViewById(R.id.weight); double height = Double.parseDouble(fieldheight.getText().toString()) / 100; double weight = Double.parseDouble(fieldweight.getText().toString()); double BMI = weight / (height * height); TextView result = (TextView) findViewById(R.id.result); result.setText("Your BMI is " + nf.format(BMI)); // Give health advice TextView fieldsuggest = (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 = new OnClickListener() { @Override public void onClick(View v) { DecimalFormat nf = new DecimalFormat(“0.00”); double height = Double.parseDouble(field_height.getText().toString()) / 100; double weight = Double.parseDouble(field_weight.getText().toString()); double BMI = weight / (height * height); // Present result view_result.setText("Your BMI 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 { private Button button_calc; private EditText field_height; private EditText field_weight; private TextView view_result; private TextView view_suggest; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViews(); setListensers(); } // 定义 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); } // Listen for button clicks private void setListeners() { calcbutton.setOnClickListener(calcBMI); } private Button.OnClickListener calcBMI = new Button.OnClickListener() { public void onClick(View v) { DecimalFormat nf = new DecimalFormat("0.0"); double height = Double.parseDouble(field_height.getText().toString()) / 100; double weight = Double.parseDouble(field_weight.getText().toString()); double BMI = 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); } } }; }
66. Android都有哪些解析数据的方法,你通常用哪种,说说它们的优缺点。
xml
l DOM
l SAX
l Pull
json
Google Gson
67. Application类的作用
l 查看文档:Application类是为了那些需要保存全局变量设计的基本类
l android框架的一个系统组件
l 单例
l 生命周期最长
68. 描述一下Android的系统架构
/** 图片下载接口 */ public class ImageLoader { ImageCache mCache = new MemoryCache(); public void loadImage(String url, ImageView imageView){ Bitmap bmp = mCache.get(url); If(bmp == null){ //异步加载图片并缓存 }else{ imageView.setImageBitmap(bmp); } } } Public interface ImageCache { Public Bitmap getPic(Sring url); Public void getPicFroSdcard(Sring url,Bitmap bmp); }
需要背出来的一些经典例子
写一个单例
public class Singlton { private static final Singlton instance = new Singlton(); private Singlton() { } public static Singlton getInstance() { return instance; } }
菲波那契数列(Fibonacci)
求Fibonacci数列:1,1,2,3,5,8,…第40个数的值。
public static int fibonacci(int n) { if (n == 1 || n == 2) { return 1; } else { return fibonacci(n - 1) + fibonacci(n - 2); } }
打印菲波那契数数列(Fibonacci)
如n = 6,则顺序打印出6个Fibonacci数列:1, 1, 2 ,3, 5, 8
public static void printFibonacci(int n) { int f1 = 1; int f2 = 1; for (int i = 0; i < n; i++) { if (i < 2) { System.out.print(“1, “); } else { int temp = f1; f1 = f2; f2 = temp + f2; System.out.print(f2 + “, “); } } }
冒泡排序法(BubbleSort)
public static int[] bubbleSort(int[] arr) { for(int i = arr.length -1;i > 0; i–){ for(int j = 0; j < i; j++) { if(arr[j] > arr[j+1]) swap(arr, j, j+1); } } return arr; } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
求n的阶乘(Factorial)
随便给一参数n,n不小于0,假如n=3,则算出1 * 2 * 3 = 6,如n=5,则算出1 * 2 * 3 * 4 * 5 = ?
public static int factorial(int n) { if (n == 1) { return 1; } else { return n * factorial(n - 1); } }
三方登录 sharesdk 友盟 微信 微博 QQ QQ空间 支付
Oauth认证 当前应用到要登录的应用上 注册 申请一个appkey
发起三方登录 打开微博的登录界面 用户输入用户名 密码 并且把权限 appkey 一起传到微博的服务端
令牌 token 返回当前应用 token(用户 权限)令牌有有效期
需要把答案准备好的非技术题:
l 请自我介绍一下
l 为什么辞职(公司的项目完成了,没新东西可以做了。外包公司里面对项目质量要求不高,上线太快,学习不到西。 之前在其它地方工作, 觉得北京发展更大)
l 职业生涯规划
l 说说你的优点
l 说说你的缺点
l 平时怎么学习的,用什么时间学习,上什么网站、看什么书 www.google.com stackoverflow github csdn http://android-developers.blogspot.com/ android开发周报
l 你有什么需要问我的吗
l 期望薪资(外包公司 没有年终奖 避税)(避税 差不多全额公积金)
基本工资 30% 绩效工资
大公司 年终奖 1~3个月
l 你了解过我们公司吗
小公司 创业公司 比较关心项目
大公司 基本不看项目
如果是计算机科班毕业 工作年限不长 数据结构算法 java基础
如果工作年限比较久 也不是计算机相关专业 数据结构算法 java基础问道这些知识点儿概率会低一些
日活 下载量越大的应用下载的数据和日均活跃用户的数据越靠近
靠什么挣钱
总结
关于项目
在就是你项目经验,一定要突出你遇到什么难点,然后是怎么解决的!把问题引导到你熟悉的领域,或者知识点上,尽量将每个技术点细节凸显出来,
面试时间一般是30分钟
回答问题的时候,尽量多说一些,相关知识点,往项目
答笔试题的时候,可以手机百度。
心态
什么样的面试官都有,去面试的时候要做好一切心理准备,不管是技术还是基础都得扎实。一个人的交谈能力也很重要,总之不是非常标准的普通话, 最起码你说的得让别人听得懂,而且得把面试官讲得非常彻底,这样你获得offer的机会更大,谈工资也有优势~~
Devstore
简历准备 项目的个数 时间 每个项目之间间隔不要超过一个月 可以有迭代(最好有迭代)
注意技术点 ①提到的技术点 一定会说 ②项目中用到的技术点时间
迭代 ①加功能 ②改bug ③UI调整(改版) ④重构 小团队 3人左右 1个月一版
投简历 如果没有电话
安排面试
面试结束 及时记录问题 及时修复问题 如果面试了10家左右还是没有offer
面试过程的非技术问题
简历
面试安排
面试过程