• Android Activity 详述


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

        <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
        </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:name=".SecondActivity"
                android:label="@string/app_name" 
                >
          </activity>

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

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

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


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

    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<String, Object>对象,将我们的数据存贮在这个 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 配置文件中可以通过<intent-filter >节点为一个 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 定义时可以在其<intent-filter >节点指定一个 Action 列表用于标示 Activity 所能接受的“动作”,例如:

     <intent-filter > 
     <action android:name="android.intent.action.MAIN" /> 
     <action android:name="com.zy.myaction" /> 
    ……
     </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 携带外部数据给目标组件。在 <intent-filter >节点中,通过 <data/>节点匹配外部数据。

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

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

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

    Category 类别匹配

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

    一些关于 Activity 的技巧

    锁定 Activity 运行时的屏幕方向

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

     <activity android:name=".EX01"
     android:label="@string/app_name" 
     android:screenOrientation="portrait">// 竖屏 , 值为 landscape 时为横屏
    …………
     </activity>

    全屏的 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;
    
    @Override
    public 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);
    }


    部分来源:

    http://www.ibm.com/developerworks/cn/opensource/os-cn-android-actvt/

    Demo 下载:

  • 相关阅读:
    FastDFS安装配置过程中出现错误提示"/home/yuqing/fastdfs" can't be accessed, error info: No such file or directory
    dubbo-monitor安装监控中心,管理控制台安装网页一直访问不到,解决bug的方式记录
    dubbo-monitor安装监控中心,管理控制台安装
    zookeeper伪分布式集群安装
    zookeeper单节点安装
    JedisCluster操作redis集群demo
    Redis Cluster集群的搭建
    redis3.0.6安装配置
    Windows注册表中修改CMD默认路径
    eclipse中使用mybatis-generator逆向代码生成工具问题解决记录
  • 原文地址:https://www.cnblogs.com/sharecenter/p/5621026.html
Copyright © 2020-2023  润新知