Android Activity 详述 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

    activity类处于android.app包中,继承关系:

    extends ContextThemeWrapper

    implements LayoutInflater.Factory2 Window.Callback KeyEvent.CallbackView.OnCreateContextMenuListenerComponentCallbacks2

java.lang.Object?android.content.Context?android.content.ContextWrapper?android.view.ContextThemeWrapper?android.app.Activity

Activity 简介

    Activity是什么呢?Activity是一个应用程序提供与用户进行交流的界面,

Android Activity 详述

。每个Activity都可以通过布局来呈现自己的用户界面,一个应用程序通常包括很多Activity,其中有一个被称为主Activity,这是程序第一次启动所展示的,例如很多程序都有的欢迎界面。将Activity设置成主Activity可以通过配置AndroidManifest.xml文件,将如下代码复制到activity的标签之中:

<intent-filter><category android:name="android.intent.category.LAUNCHER"></category></intent-filter>

    一个Activity可以启动另一个Activity来实现不同的表现,当一个Activity启动后,它被压入一个stack中,获得焦点,当用户按了back按钮后,当前的Activity从stack中弹出(即被destroyed),先前的Activity被释放从新获得焦点。这些涉及到Activity的生命周期,后面将进行讨论。

    怎么创建一个Activity呢?通过继承父类Activity,来创建一个属于自己的Activity,这要求你需要实现Activity父类的回调方法,这些方法在Activity的生命周期中的不同状态被调用,如:创建,暂停,释放,销毁。其中有两个最重要的回调方法:

    1.onCreate()

    这个方法在Activity被创建时被调用,在这个方法应该初始化各个控件,通过调用setContentView(R.layout.xxx)方法定义布局来展现Activity的用户界面,其中R.layout.xxx为Activity的XML布局文件。

    2.onPause()

    这个方法在用户离开当前Activity时被调用,这就需要在这个方法中保存用户与当前Activity的会话,比如在EditText中输入的值。用户在返回当前Activity时,还应该显示离开时所填写的值。

    当然每创建一个Activity都需要在AndroidManifest.xml文件中注册一个相应的Activity。如:创建的Activity的类名为:MyActivity则在文件中需添加如下代码:

Activity 的状态及状态间的转换:

    在 android 中,Activity 拥有四种基本状态:

    Active/Runing一个新 Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态。Paused当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。Stoped当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时处于Stoped状态。KilledActivity 被系统杀死回收或者没有被启动时处于Killed状态。

        当一个 Activity 实例被创建、销毁或者启动另外一个 Activity 时,它在这四种状态之间进行转换,这种转换的发生依赖于用户程序的动作。下图说明了 Activity 在不同状态间转换的时机和条件:

    图 1. Activity 的状态转换

       

        如上所示,Android 程序员可以决定一个 Activity 的“生”,但不能决定它的“死”,也就时说程序员可以启动一个 Activity,但是却不能手动的“结束”一个 Activity。当你调用Activity.finish()方法时,结果和用户按下 BACK 键一样:告诉 Activity Manager 该 Activity 实例完成了相应的工作,可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity 并重新入栈,同时原 Activity 被压入到栈的第二层,从 Active 状态转到 Paused 状态。例如:从 Activity1 中启动了 Activity2,则当前处于栈顶端的是 Activity2,第二层是 Activity1,当我们调用Activity2.finish()方法时,Activity Manager 重新激活 Activity1 并入栈,Activity2 从 Active 状态转换 Stoped 状态,Activity1. onActivityResult(int requestCode, int resultCode, Intent data)方法被执行,Activity2 返回的数据通过data参数返回给 Activity1。

    Activity 栈

        Android 是通过一种 Activity 栈的方式来管理 Activity 的,一个 Activity 的实例的状态决定它在栈中的位置。处于前台的 Activity 总是在栈的顶端,当前台的 Activity 因为异常或其它原因被销毁时,处于栈第二层的 Activity 将被激活,上浮到栈顶。当新的 Activity 启动入栈时,原 Activity 会被压入到栈的第二层。一个 Activity 在栈中的位置变化反映了它在不同状态间的转换。Activity 的状态与它在栈中的位置关系如下图所示:

    图 2. Activity 的状态与它在栈中的位置关系

        如上所示,除了最顶层即处在 Active 状态的 Activity 外,其它的 Activity 都有可能在系统内存不足时被回收,一个 Activity 的实例越是处在栈的底层,它被系统回收的可能性越大。系统负责管理栈中 Activity 的实例,它根据 Activity 所处的状态来改变其在栈中的位置。

    Activity 生命周期

    android.app.Activity类中,Android 定义了一系列与生命周期相关的方法,在我们自己的 Activity 中,只是根据需要复写需要的方法.

        Activity生命周期图:

       

        下面我们通过一个实例来说明Activity生命周期。新建工程,编写如下代码:

    public class MainActivity extends AppCompatActivity {    private String TAG = MainActivity;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i(TAG, onCreate);    }    @Override    protected void onResume() {        super.onResume();        Log.i(TAG, onResume);    }    @Override    protected void onStart() {        super.onStart();        Log.i(TAG, onStart);    }    @Override    protected void onPause() {        super.onPause();        Log.i(TAG, onPause);    }    @Override    protected void onStop() {        super.onStop();        Log.i(TAG, onStop);    }    @Override    protected void onRestart() {        super.onRestart();        Log.i(TAG, onRestart);    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG, onDestroy);    }}
    我们通过记录操作和打印日志的方式来看看Activity的生命周期过程;

        1、 运行

        看到如下打印日志:

        11-26 09:09:33.665 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onCreate

        11-26 09:09:33.665 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStart

        11-26 09:09:33.665 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onResume

        2、按下返回按键:

        11-26 09:30:20.097 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onPause

        11-26 09:30:20.637 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStop

        11-26 09:30:20.637 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onDestroy

        3、长按Home键,弹出最近打开过的应用程序,点击ActivityDemo

        11-26 09:31:07.341 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onCreate

        11-26 09:31:07.341 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStart

        11-26 09:31:07.341 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onResume

        4、按Home键

        11-26 09:31:44.649 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onPause

        11-26 09:31:45.173 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStop

        5、在AllList中点击打开

        11-26 09:32:11.793 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onRestart

        11-26 09:32:11.793 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onStart

        11-26 09:32:11.793 24933-24933/com.jcdh.jcli.activitydemo I/MainActivity: onResume

        通过日志信息,我们可以看到,

    电脑资料

    Android Activity 详述》(https://www.unjs.com)。

        Activity的启动过程:onCreate—onStart—onResume;

        下返回键时:onPause—onStop—onDestroy 正如上面说是,当按下返回键时,此Activity弹出栈,程序销毁。确实如此;

        我们再次 打开时的启动过程又回到onCreate—onStart—onResume。OK;

        启动之后按下Home键,回到Launcher,查看打印信息:onPause—onStop;

        再次打开的运行过程:onRestart—onStart—onResume;

        我们通过对Activity的各种操作,构成了Activity的生命周期,我们看到无论对Activity做如何的操作,都会接收到相关的回调方法,那么我们在开发的过程中通过这些回调方法就可以写工作,比如说释放一些重量级的对象,网络连接,数据库连接,文件读等等。

        以下是各个方法的详细说明:

        onCreate():当 activity 第一次创建时会被调用。在这个方法中你需要完成所有的正常静态设置 ,比如创建一个视图( view )、绑定列表的数据等等。如果能捕获到 activity 状态的话,这个方法传递进来的 Bundle 对象将存放了 activity 当前的状态。调用该方法后一般会调用 onStart() 方法。

        onRestart():在 activity 被停止后重新启动时会调用该方法。其后续会调用 onStart 方法。

        onStart() 当 activity 对于用户可见前即调用这个方法。如果 activity回到前台则接着调用 onResume() ,如果 activity 隐藏则调用onStop()

        onResume():在 activity 开始与用户交互前调用该方法。在这时该activity 处于 activity 栈的顶部,并且接受用户的输入。其后续会调用 onPause() 方法。

        onPause():在系统准备开始恢复其它 activity 时会调用该方法。这个方法中通常用来提交一些还没保存的更改到持久数据 中,停止一些动画或其它一些耗 CPU 的操作等等。无论在该方法里面进行任何操作,都需要较快速完成,因为如果它不返回的话,下一个 activity 将无法恢复出来。如果 activity 返回到前台将会调用 onResume() ,如果 activity 变得对用户不可见了将会调用onStop() 。

        onStop():在 activity 对用户不可见时将调用该方法。可能会因为当前 activity 正在被销毁,或另一个 activity (已经存在的activity 或新的 activity )已经恢复了正准备覆盖它,而调用该方法。如果 activity 正准备返回与用户交互时后续会调用onRestart ,如果 activity 正在被释放则会调用 onDestroy 。

        onDestroy():在 activity 被销毁前会调用该方法。这是 activity 能接收到的最后一个调用。可能会因为有人调用了 finish 方法使得当前activity 正在关闭,或系统为了保护内存临时释放这个 activity的实例,而调用该方法。你可以用 isFinishing 方法来区分这两种不同的情况。

    启动另外一个 Activity

    要启动一个新的Activity,我们可以通过调用 startActivity来启动例:

    Intent intent =new Intent(CurrentActivity.this,OtherActivity.class);  startActivity(intent);

        注意:OtherActivity同样在 AndroidManifest.xml 中定义。

    Activity 之间通信使用 Intent 通信

        在 Android 中,不同的 Activity 实例可能运行在一个进程中,也可能运行在不同的进程中。因此我们需要一种特别的机制帮助我们在 Activity 之间传递消息。Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内容。对于一个 Intent 对象,消息“目的地”是必须的,而内容则是可选项。

        在上面的实例中通过Activity. startActivity(intent)启动另外一个 Activity 的时候,我们在 Intent 类的构造器中指定了“收件人地址”。

    我们通过bundle对象来传递信息,bundle维护了一个HashMap对象,将我们的数据存贮在这个 HashMap 中来进行传递。但是像上面这样的代码稍显复杂,因为 Intent 内部为我们准备好了一个bundle,所以我们也可以使用这种更为简便的方法:

       

    Intent intent =new Intent(MainActivity.this,OtherActivity.class);  intent.putExtra(boolean_key, true);  intent.putExtra(string_key, string_value);  startActivity(intent);

        接收:

    Intent intent=getIntent();  intent.getBooleanExtra(boolean_key,false);  intent.getStringExtra(string_key);

    Activity 的 Intent Filter

    ntent Filter 描述了一个组件愿意接收什么样的 Intent 对象,Android 将其抽象为 android.content.IntentFilter 类。在 Android 的 AndroidManifest.xml 配置文件中可以通过节点为一个 Activity 指定其 Intent Filter,以便告诉系统该 Activity 可以响应什么类型的 Intent。

        当程序员使用 startActivity(intent) 来启动另外一个 Activity 时,如果直接指定 intent 了对象的 Component 属性,那么 Activity Manager 将试图启动其 Component 属性指定的 Activity。否则 Android 将通过 Intent 的其它属性从安装在系统中的所有 Activity 中查找与之最匹配的一个启动,如果没有找到合适的 Activity,应用程序会得到一个系统抛出的异常。这个匹配的过程如下:

    图 4. Activity 种 Intent Filter 的匹配过程

    Action 匹配

    Action 匹配Action 是一个用户定义的字符串,用于描述一个 Android 应用程序组件,一个 Intent Filter 可以包含多个 Action。在 AndroidManifest.xml 的 Activity 定义时可以在其节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如:

    <intent-filter>……</intent-filter>

        如果我们在启动一个 Activity 时使用这样的 Intent 对象:

    Intent intent =new Intent();  intent.setAction(com.zy.myaction);

        那么所有的 Action 列表中包含了“com.zy.myaction”的 Activity 都将会匹配成功。

        Android 预定义了一系列的 Action 分别表示特定的系统动作。这些 Action 通过常量的方式定义在android.content. Intent中,以“ACTION_”开头。我们可以在 Android 提供的文档中找到它们的详细说明。

    URI 数据匹配

        一个 Intent 可以通过 URI 携带外部数据给目标组件。在节点中,通过节点匹配外部数据。

        mimeType 属性指定携带外部数据的数据类型,scheme 指定协议,host、port、path 指定数据的位置、端口、和路径。如下:

    <data android:host="host" android:mimetype="mimeType" android:path="path/" android:port="port" android:scheme="scheme"></data>

        如果在 Intent Filter 中指定了这些属性,那么只有所有的属性都匹配成功时 URI 数据匹配才会成功。

    Category 类别匹配

        节点中可以为组件定义一个 Category 类别列表,当 Intent 中包含这个列表的所有项目时 Category 类别匹配才会成功。

    一些关于 Activity 的技巧

    锁定 Activity 运行时的屏幕方向

        Android 内置了方向感应器的支持。在 G1 中,Android 会根据 G1 所处的方向自动在竖屏和横屏间切换。但是有时我们的应用程序仅能在横屏 / 竖屏时运行,比如某些游戏,此时我们需要锁定该 Activity 运行时的屏幕方向,节点的android:screenOrientation属性可以完成该项任务,示例代码如下:

    // 竖屏 , 值为 landscape 时为横屏…………

    全屏的 Activity

        要使一个 Activity 全屏运行,可以在其onCreate()方法中添加如下代码实现:

    // 设置全屏模式 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,     WindowManager.LayoutParams.FLAG_FULLSCREEN);  // 去除标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE);

    设置Activity 的 Title

    setTitle(我的);

        实现双击返回键退出功能:

    private long exitTime = 0;@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {    if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){           if((System.currentTimeMillis()-exitTime) > 2000){              Toast.makeText(getApplicationContext(), 再按一次退出程序, Toast.LENGTH_SHORT).show();                                            exitTime = System.currentTimeMillis();           } else {            finish();            System.exit(0);        }        return true;       }    return super.onKeyDown(keyCode, event);}

       

最新文章