上一篇文章介绍了Android的菜单机制,并动手做了一个实验来探究动态菜单的实验机制。这一篇将重点介绍Activity的生命周期,通过一个简单的实验来摸索状态转换的机制,最后介绍NotePad中使用的自定义控件技术。

Activity的生命周期

Activity类中有许多onXXX形式的函数可以重载,比如onCreate,onStart,onStop,onPause,那么它们的调用顺序到底是如何的呢?下面就通过一个实验来进行分析。在做这个实验之前,我们先得知道如何在Android中进行Log输出的。

我们要使用的是android.util.log类,这个类相当的简单易用,因为它提供的全是一些静态方法:

Log.v(Stringtag,Stringmsg); // VERBOSE
Log.d(Stringtag,Stringmsg); // DEBUG
Log.i(Stringtag,Stringmsg); // INFO
Log.w(Stringtag,Stringmsg); // WARN
Log.e(Stringtag,Stringmsg); // ERROR

前面的tag是由我们定义的一个标识,一般可以用类名_方法名来定义。要在Eclipse中查看输出的log信息,需要打开LogcatWindowàShow ViewàotheràAndroidàLogCat即可打开)

实验一

我们要做的实验非常简单,就是有两个Activity(我这里分别叫做frmLoginhello2,t它们各自有一个button,可以从第一个跳到第二个,也可以从第二个跳回到第一个。

配置文件AndroidManifest.xml非常简单,第二个activity并没有多余的信息需要指定。

< application android:icon ="@drawable/icon" android:label ="@string/app_name" >
< activity android:name =".frmLogin"
android:label
="@string/app_name" >
< intent-filter >
< action android:name ="android.intent.action.MAIN" />
< category android:name ="android.intent.category.LAUNCHER" />
</ intent-filter >
</ activity >
< activity android:name ="hello2" android:label ="@string/app_name" >
</ activity >
</ application >

第一个activity的代码如下:

public class frmLogin extends Activity
{
private final static StringTAG = " FrmLogin " ;

/** Calledwhentheactivityisfirstcreated. */
@Override
public void onCreate(BundlesavedInstanceState)
{
super .onCreate(savedInstanceState);
Log.v(TAG,
" onCreate " );
setContentView(R.layout.main);
this .setViewOneCommand();
}

public void setViewOneCommand()
{
Buttonbtn
= (Button)findViewById(R.id.btnGo);
btn.setOnClickListener(
new View.OnClickListener()
{
public void onClick(Viewv)
{
Intentintent
= new Intent();
intent.setClass(frmLogin.
this ,hello2. class );
startActivity(intent);
finish();
}
});
ButtonbtnExit
= (Button)findViewById(R.id.btnExit);
btnExit.setOnClickListener(
new View.OnClickListener()
{
public void onClick(Viewv)
{
frmLogin.
this .finish();
}
});
}

@Override
protected void onDestroy()
{
super .onDestroy();
Log.v(TAG,
" onDestroy " );
}

@Override
protected void onPause()
{
super .onPause();
Log.v(TAG,
" onPause " );

}

@Override
protected void onRestart()
{
super .onRestart();
Log.v(TAG,
" onRestart " );
}

@Override
protected void onResume()
{
super .onResume();
Log.v(TAG,
" onResume " );
}

@Override
protected void onStart()
{
super .onStart();
Log.v(TAG,
" onStart " );
}

@Override
protected void onStop()
{
super .onStop();
Log.v(TAG,
" onStop " );
}
}

我在每个onXXX方法中都加入了log方法,值得注意的一点是按钮单击事件处理函数中,在最后我调用了finish();待会我会将此行注释掉进行对比实验。

第二个activity的代码和第一个完全一样,只是将setClass的两个参数反一下,这样就可以简单地实现在两个Activity界面中来回切换的功能了。

下面开始实验,第一个实验室从第一个activity跳到第二个activity(此时第一个关闭),然后从第二个跳回第一个(此时第二个关闭)

运行后观察LogCat,得到如下画面:


然后来进行第二个实验,对代码进行调整,我们把第一个activity中的finish()注释掉,从第一个activity跳到第二个(此时第一个没有关闭),然后第二个直接关闭(则第一个会重新来到前端),结果如图所示,可以看出调用了FrmLoginonRestart而不是onStart,因为第一个activity只是stop,而并没有被destory掉。


前面两个实验都很好理解,可第三个实验就让我不明白了,过程如下:从第一个activity跳到第二个activity(此时第一个不关闭),然后第二个跳回第一个(此时第二个也不关闭),然后第一个再跳回第二个(此时第一个不关闭),照上面来推断,应该还是会调用onRestart才对,可实际上它调用的却是onStartwhy???


这里先不讨论例子了,来看看官方文档对Activity生命周期的介绍。

1.AndroidActivity Stack来管理多个Activity,所以呢,同一时刻只会有最顶上的那个Activity是处于active或者running状态。其它的Activity都被压在下面了。

2.如果非活动的Activity仍是可见的(即如果上面压着的是一个非全屏的Activity或透明的Activity),它是处于paused状态的。在系统内存不足的情况下,paused状态的Activity是有可被系统杀掉的。只是不明白,如果它被干掉了,界面上的显示又会变成什么模样?看来下回有必要研究一下这种情况了。

3.几个事件的配对可以比较清楚地理解它们的关系。CreateDestroy配成一对,叫entrie lifetime,在创建时分配资源,则在销毁时释放资源;往上一点还有StartStop一对,叫visible lifetime,表达的是可见与非可见这么一个过程;最顶上的就是ResumePause这一对了,叫foreground lifetime,表达的了是否处于激活状态的过程。

4.因此,我们实现的Activity派生类,要重载两个重要的方法:onCreate()进行初始化操作,onPause()保存当前操作的结果。

除了Activity Lifecycle以外,Android还有一个Process Lifecycle的说明:

在内存不足的时候,Android是会主动清理门户的,那它又是如何判断哪个process是可以清掉的呢?文档中也提到了它的重要性排序:

1.最容易被清掉的是empty process,空进程是指那些没有Activity与之绑定,也没有任何应用程序组件(如Services或者IntentReceiver)与之绑定的进程,也就是说在这个process中没有任何activity或者service之类的东西,它们仅仅是作为一个cache,在启动新的Activity时可以提高速度。它们是会被优先清掉的。因此建议,我们的后台操作,最好是作成Service的形式,也就是说应该在Activity中启动一个Service去执行这些操作。

2.接下来就是background activity了,也就是被stop掉了那些activity所处的process,那些不可见的Activity被清掉的确是安全的,系统维持着一个LRU列表,多个处于backgroundactivity都在这里面,系统可以根据LRU列表判断哪些activity是可以被清掉的,以及其中哪一个应该是最先被清掉。不过,文档中提到在这个已被清掉的Activity又被重新创建的时候,它的onCreate会被调用,参数就是onFreeze时的那个Bundle。不过这里有一点不明白的是,难道这个Activitykilled时,Android会帮它保留着这个Bundle吗?

3.然后就轮到service process了,这是一个与Service绑定的进程,由startService方法启动。虽然它们不为用户所见,但一般是在处理一些长时间的操作(例如MP3的播放),系统会保护它,除非真的没有内存可用了。

4.接着又轮到那些visible activity了,或者说visible process。前面也谈到这个情况,被PausedActivity也是有可能会被系统清掉,不过相对来说,它已经是处于一个比较安全的位置了。

5.最安全应该就是那个foreground activity了,不到迫不得已它是不会被清掉的。这种process不仅包括resume之后的activity,也包括那些onReceiveIntent之后的IntentReceiver实例。

Android Application的生命周期的讨论中,文档也提到了一些需要注意的事项:因为Android应用程序的生存期并不是由应用本身直接控制的,而是由Android系统平台进行管理的,所以,对于我们开发者而言,需要了解不同的组件ActivityServiceIntentReceiver的生命,切记的是:如果组件的选择不当,很有可能系统会杀掉一个正在进行重要工作的进程。

自定义控件

这里主要介绍下编辑日志中使用的一个自定义EditText控件,它的效果如下图:


主要功能就是在文本语句之间绘制分割线。

public static class LinedEditText extends EditText
{
private RectmRect;
private PaintmPaint;
// weneedthisconstructorforLayoutInflater
public LinedEditText(Contextcontext,AttributeSetattrs)
{
super (context,attrs);
mRect
= new Rect();
mPaint
= new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(
0x800000FF );
}
@Override
protected void onDraw(Canvascanvas)
{
int count = getLineCount();
Rectr
= mRect;
Paintpaint
= mPaint;
for ( int i = 0 ;i < count;i ++ )
{
int baseline = getLineBounds(i,r);
canvas.drawLine(r.left,baseline
+ 1 ,r.right,baseline + 1 ,paint);
}
super .onDraw(canvas);
}
}

主要工作就是重载onDraw方法,利用从TextView继承下来的getLineCount函数获取文本所占的行数,以及getLineBounds来获取特定行的基准高度值,而且这个函数第二个参数会返回此行的外包装值。再利用这些值绘制这一行的线条。

为了让界面的View使用自定义的EditText类,必须在配置文件中进行设置

< view xmlns:android ="http://schemas.android.com/apk/res/android"
class
="com.example.android.notepad.NoteEditor$LinedEditText"
android:id
="@+id/note"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent"
android:background
="@android:color/transparent"
android:padding
="5dip"
android:scrollbars
="vertical"
android:fadingEdge
="vertical"
android:gravity
="top"
android:textSize
="22sp"
android:capitalize
="sentences"
/>

这里class="com.example.android.notepad.NoteEditor$LinedEditText"就指明了应当使用自定义的LinedEditText类。

更多相关文章

  1. activity 生命周期
  2. android bionic缺失pthread_cancel的解决方法
  3. Android四大组件之Activity---生命周期那些你可能不知道的事
  4. Android(安卓)Material Design 详解(使用support v7兼容5.0以下系
  5. 绝对让你理解Android中的Context
  6. Android(安卓)Studio自动生成带系统签名的apk
  7. Android(安卓)service与Thread
  8. Android(安卓)事件传递机制
  9. android 积累一点关于fragment的知识

随机推荐

  1. ListView为什么要使用convertView和ViewH
  2. Android(安卓)消息机制学习
  3. Android(安卓)设置Dialog不允许返回或搜
  4. android 蓝牙隐藏对话框 后台配对
  5. Android实现定时执行某个任务
  6. android HAL层代码
  7. Android(安卓)微信分享icon黑边代码解决
  8. Android(安卓)提交数据到服务器的四种方
  9. 64Ubuntu报错Failed to get the adb vers
  10. 每次吃一点AndroidのAS问题大集合