返回 登录
0

Android面试题整理附答案(二)

  1. 什么是Activity?
    四大组件之一,一般的,一个用户交互界面对应一个activity
    setContentView() ,// 要显示的布局
    , activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件.
    button.setOnclickLinstener{

}

开发常用的的有ListActivity , PreferenceActivity ,TabAcitivty等…

如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity.
进度对话框的显示与销毁 doubanservice

  1. 请描述一下Activity 生命周期。
    生命周期描述的是一个类 从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法..
    在这个过程中 会针对不同的生命阶段会调用不同的方法

Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:oncreate ondestroy onstop onstart onresume onpause
其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;
onStart可见与onStop不可见;onResume可编辑(即焦点)与onPause;
对话框的弹出, Activity.this
对话框是activity的一部分.
这6个方法是相对应的,那么就只剩下一个onRestart方法了,这个方法在什么时候调用呢?
答案就是:在Activity被onStop后,但是没有被onDestroy,在再次启动此Activity时就调用onRestart(而不再调用onCreate)方法;

如果被onDestroy了,则是调用onCreate方法。

最后讲自己项目中的经验,比如说豆瓣客户端每次进入某个界面的时候都要看到最新的数据,这个刷新列表的操作 就放在onStart()的方法里面.
fillData() 这样保证每次用户看到的数据都是最新的.

多媒体播放, 播放来电话. onStop() 视频, 视频声音设置为0 , 记录视频播放的位置 mediaplayer.pause();
onStart() 根据保存的状态恢复现场. mediaplayer.start();

在读文档的时候 还发现 activity还有两个方法 onPostResume() 和 OnPostCreate()这两个生命周期的方法,不过开发的时候没有用到过.

  1. 两个Activity之间跳转时必然会执行的是哪几个方法。

一般情况比如说有两个activity,分别叫A,B ,当在A里面激活B组件的时候, A 会调用 onPause()方法,然后B 调用onCreate() ,onStart(), OnResume() ,

这个时候B覆盖了窗体, A会调用onStop()方法. 如果B呢 是个透明的,或者是对话框的样式, 就不会调用onStop()方法

  1. 横竖屏切换时候Activity的生命周期。
    这个生命周期跟清单文件里的配置有关系
    1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期
    默认首先销毁当前activity,然后重新加载
    Onpause onstop ondestory oncreate onstart onresume

2、设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

游戏开发中, 屏幕的朝向都是写死的.

  1. 如何将一个Activity设置成窗口的样式。
    可以自定义一个activity的样式,详细见手机卫士的程序详细信息
    android:theme=”@style/FloatActivity”
    E:\day9\mobilesafe\res\values\style

  2. 你后台的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);
}

  1. 如何退出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>();

每一个activity在执行oncreate()方法的时候 lists.add(this);
Ondestory() lists.remove(this);
lists.add(activity);

for(Activity activity: lists)
{
activity.finish();
}

3、发送特定广播:
在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
//给某个activity 注册接受接受广播的意图
registerReceiver(receiver, filter)

//如果过接受到的是 关闭activity的广播 就调用finish()方法 把当前的activity finish()掉

4、递归退出
在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
404 退出程序
OnActivityResult();

讲一讲你对activity的理解
把上面的几点用自己的心得写出来

  1. service是否在main thread中执行, service里面是否能执行耗时的操作?
    默认情况,如果没有显示的指定service所运行的进程, Service和activity是运行在当前app所在进程的main thread(UI主线程)里面
    service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
    在子线程中执行 new Thread(){}.start();

特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,
让service在另外的进程中执行

  1. 两个Activity之间怎么传递数据?
    基本数据类型可以通过. Intent 传递数据
    extras.putDouble(key, value)
    intent.putExtra(name, value)
    // 通过intent putExtra 方法 基本数据类型 都传递
    Bundle bundle = new Bundle();
    bundle.putShort(key, value);
    intent.putExtras(bundle);
    intent.putExtras(bundle)

获取到激活他的 getIntent();
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
Bundle 类似map的集合
intent.getStringExtra(“key”,”value”);
intent.getBooleanExtra(“key”,”value”)

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();
    stu.setId("10001");
    stu.setName("zs");
    oos.writeObject(stu);


    FileInputStream fis = new FileInputStream(file);
    ObjectInputStream ois = new ObjectInputStream(fis);
     Student stu1 = (Student) ois.readObject();
    System.out.println(stu1.getName());

Parcelable 和 Serializable

Parcelable 把对象序列化到android操作系统 的一块公用的内存空间
文件/网络

//传递数据的引用
intent.setData(Uri)
Uri.fromFile(); //大图片的传递
contentResolver.getInputStream(uri);

  1. 怎么让在启动一个Activity是就启动一个service?
    在activity的onCreate()方法里面 startService();

  2. 同一个程序,但不同的Activity是否可以放在不同的Task任务栈中?
    比方说在激活一个新的activity时候, 给intent设置flag
    Intent的flag添加FLAG_ACTIVITY_NEW_TASK singleinstance 单独的任务栈
    这个被激活的activity就会在新的task栈里面…
    Intent intent = new Intent(A.this,B.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);

  3. Activity怎么和service绑定,怎么在activity中启动自己对应的service?

startService() 一旦被创建 调用着无关 没法使用service里面的方法
bindService () 把service 与调用者绑定 ,如果调用者被销毁, service会销毁
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

    }

}
  1. 14 .什么是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的话会抛出异常。

  1. 不用service,B页面为音乐播放,从A跳转到B,再返回,如何使音乐继续播放?
    这个问题问的很山寨.默认不做任何处理,B里面的音乐都能播放.
    遇到问题, 可以随机应变,灵活发挥,多考虑些细节,比如说这个题就可以这样说,说说你对startActivityForResult的理解()
    A开启B的时候,用startActivityForResult()方法, B返回的时候把播放的状态信息返回给A ,A继续播放音乐.

  2. 什么是IntentService?有何优点?
    普通的service ,默认运行在ui main 主线程
    Sdk给我们提供的方便的,带有异步处理的service类,
    异步处理的方法 OnHandleIntent()
    OnHandleIntent() 处理耗时的操作

  3. 什么时候使用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.Broadcast receiver捕获到一个事件之后,可以起一个service来完成一个耗时的操作.  

Broadcast receiver生命周期 和 响应时间很短

3.远程的service如果被启动起来,可以被多次bind, 但不会重新create.  索爱手机X10i的人脸识别的service可以被图库使用,可以被摄像机,照相机等程序使用.

18. 请描述一下Intent 和 Intent Filter。
Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。
通过Intent 可以实现各种系统组件的调用与激活.
Intent filter: 可以理解为邮局或者是一个信笺的分拣系统…
这个分拣系统通过3个参数来识别
Action: 动作 Intent.ation_view
Data: 数据uri uri mime
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 指定数据的位置、端口、和路径。如下:

管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

  1. 谈谈对Android NDK的理解。
    native develop kit 只是一个交叉编译的工具 .so
    1.什么时候用ndk, 实时性要求高,游戏,图形渲染,
    opencv (人脸识别) , ffmpeg , rmvb mp5 avi 高清解码. ffmpeg, opencore.

2.为什么用ndk,ndk的优点 ,缺点,

我们项目中那些地方用到了ndk, c opengl

  1. 谈谈Android的优点和不足之处。
    1、开放性,开源 ophone 阿里云( 完全兼容android) 乐os
    2、挣脱运营商束缚
    3、丰富的硬件选择 mtk android
    4、不受任何限制的开发商
    5、无缝结合的Google应用

缺点也有5处:
1、安全问题、隐私问题
2、卖手机的不是最大运营商
3、运营商对Android手机仍然有影响
4、山寨化严重
5、过分依赖开发商,缺乏标准配置 版本过多

  1. 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 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用

  1. Android UI中的View如何刷新。

在主线程中 拿到view调用Invalide()方法,查看画画板里面更新imageview的方法

在子线程里面可以通过postInvalide()方法;
iv.invalidate();

    new Thread(){
        public void run(){
            iv.postInvalidate();
        }
    }.start();
  1. 简单描述下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只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。

  1. 什么是ANR 如何避免它?
    在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择让程序继续运行,但是,他们在使用你的应用程序时,并不希望每次都要处理这个对话框。因此,在程序里对响应性能的设计很重要,这样,系统不会显示ANR给用户。
    Activity 5秒 broadcast10秒

耗时的操作 worker thread里面完成,
handler message…AsynsTask , intentservice.等…

  1. 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动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。

  1. 说说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中显示。

  1. 通过点击一个网页上的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 find grep tail vi gcc make ifconfig
startup dhcp
70 JNI调用常用的两个参数
JNIEnv *env, jobject javaThis
71. 书写出android工程的目录结构
src
android. jar
asset
res
gen
manifest

  1. ddms 和traceview的区别.
    daivilk debug manager system
    1.在应用的主activity的onCreate方法中加入Debug.startMethodTracing(“要生成的traceview文件的名字”);
    2.同样在主activity的onStop方法中加入Debug.stopMethodTracing();
    3.同时要在AndroidManifest.xml文件中配置权限

    3.重新编译,安装,启动服务,测试完成取对应的traceview文件(adb pull /sdcard/xxxx.trace)。
    4.直接在命令行输入traceview xxxxtrace,弹出traceview窗口,分析对应的应用即可。

traceview 分析程序执行时间和效率

KPI : key performance information : 关键性能指标:
splash界面不能超过5秒
从splash 界面加载mainactivity 不能超过0.7秒

73, 同步异步的理解,什么是同步,什么是异步,多次调用异步方法会出现什么问题.

  1. 利用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);
        }
    }
};

}

总结:
关于项目
在就是你项目经验,一定要突出你遇到什么难点,然后是怎么解决的!把问题引导到你熟悉的领域,或者知识点上,尽量将每个技术点细节凸显出来,

心态:
什么样的面试官都有,去面试的时候要做好一切心理准备,不管是技术还是基础都得扎实。一个人的交谈能力也很重要,总之不是非常标准的普通话, 最起码你说的得让别人听得懂,而且得把面试官讲得非常彻底,这样你获得offer的机会更大,谈工资也有优势~~

评论