• Activity的生命周期与加载模式——Activity的4种加载模式


           配置Activity时可指定android:launchMode属性,该属性用于配置该Activity的加载模式,该属性支持如下4个属性值。

    • standard:标准模式,这是默认的加载模式。
    • singleTop:Task顶单例模式。
    • singleTask:Task内单例模式。
    • singleInstance:全局单例模式。

         Android采用Task来管理多个Activity,当我们启动一个应用时,Android就会为之创建一个Task,然后启动这个应用的入口Activity(即<intent-filter.../>中配置为MAIN和LAUNCHER的Activity)。

        Adroid的Task是一个有点麻烦的概念——因为Android并没有为Task提供API,因此开发者无法真正去访问Task,只能调用Activity的getTaskId()方法来获取它所在的Task的ID。事实上,我们可以把Task理解成Activity栈,Task以栈的形式来管理Activiy:先启动的Activity被放在Task栈底,后启动的Activity被放在Task栈顶。

        那么Activity的加载模式,就负责管理实例化、加载Activity的方式、并可以控制Activity与Task之间的加载关系。

        下面详细介绍这4种加载模式。

          1、standard加载模式

         每次通过这种模式来启动目标Activity时,Android总会为目标Activity创建一个新的实例,并将该Activity添加到当前Task栈中——这种模式不会启动新的Task,新Activity将被添加到原有的Task中。

         下面的示例使用了standard模式来不断启动自身。

         

    package com.example.studyactivity;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Intent;
    import android.view.Menu;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    public class StandardTest extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            LinearLayout layout=new LinearLayout(this);
            layout.setOrientation(LinearLayout.VERTICAL);
            this.setContentView(layout);
            //创建一个TextView来显示该Activity和它所在的Task ID
            TextView tv=new TextView(this);
            tv.setText("Activity为"+this.toString()+"
    "+",Task ID为:"+this.getTaskId());
            Button button=new Button(this);
            button.setText("启动StardardTest");
            //添加TextView和Button
            layout.addView(tv);
            layout.addView(button);
            //为button添加事件监听器,当单击该按钮时启动StandardTest
            button.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    //创建启动StardardTest的Intent
                    Intent intent=new Intent(StandardTest.this,StandardTest.class);
                    startActivity(intent);
                }});
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.standard_test, menu);
            return true;
        }
    
    }

          正如上面的粗体字代码所示,每次单击按钮,程序将会再次启动StandardTest   Activity,程序配置该Activity时无须指定launchMode属性,该Activty默认采用standard加载模式。

          运行该程序,多次单击程序界面上的“启动StandardTest”按钮,程序将会不断启动新的StandardTest实例(不同Activity实例的hashCode值有差异),但它们所在的Task ID总是相同的——这表明这种加载模式不会使用全新的Task。

          standard加载模式的示意图如图4.22所示。

    正如图4.22所示,当用户低年级手机的“返回”键时,系统将会“逐一”从Activity栈顶删除Activity实例。

         2、singleTop模式

         这种模式与standard模式基本相似,但有一点不同:当将要被启动的目标Activity已经位于Task栈顶时,系统不会重新创建目标Activity的实例,而是直接复用已有的Activity实例。

        如果将上面实例中StandardTest Activity的加载模式改为standard加载模式,无论用户点击多少次按钮,界面上的程序将不会有任何变化。

        如果将要比启动的目标Activity没有位于Task栈顶,此时系统会重新创建目标Activity的实例,并将它加载到Task的栈顶——此时与standard模式完全相同。

        3、singleTask模式

         采用这种加载模式的Activity在同一个Task内只有一个实例,当系统采用singleTask模式启动Activity时,可分为如下三种情况:

    •  如果将要启动的目标Activity不存在,系统将会创建目标Activity的实例,并将它加入Task栈顶。
    • 如果将要启动的目标Activity已经位于栈顶,此时与singleTop模式的行为相同。
    • 如果将要启动的目标Activity已经存在、但没有位于Task栈顶,系统将会把位于该Activity上面的所有Activity移出Task栈,从而使目标Activity转入栈顶。

       4、singleInstance模式

        这种加载模式下,系统保证无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会启动一个全新的Task栈来装载该Activity实例。

        当系统采用singelInstance模式启动目标Activity时,可分为如下两种情况。

    • 如果将要启动的目标Activity不存在,系统会先创建一个全新的Task、再创建目标Activity的实例,并将它加入新的Task的栈顶。
    • 如果将要启动的目标Activity已经存在,无论它位于哪个应用程序中,无论它位于哪个Task中,系统将会把该Activity所在的Task转到前台,从而使该Activity显示出来。

         需要指出的是,采用singleInstance模式加载Activity总是位于Task栈顶,采用singleInstance模式加载Activity所在Task只包含该Activity。

          下面示例中的SingleInstanceTest中包含一个按钮,当用户单击该按钮时,系统启动SingleInstanceSecondTest,程序清单如下。

    package com.example.studyactivity;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Intent;
    import android.view.Menu;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    public class SingleInstanceTest extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            LinearLayout layout=new LinearLayout(this);
            layout.setOrientation(LinearLayout.VERTICAL);
            this.setContentView(layout);
            //创建一个TextView来显示该Activity和它所在Task ID
            TextView tv=new TextView(this);
            tv.setText("Activity为:"+this.toString()+"
    "+",Task ID为:"+this.getTaskId());
            Button button=new Button(this);
            button.setText("启动SingleInstanceSecondTest");
            layout.addView(tv);
            layout.addView(button);
            //为button添加事件监听器,当单击该按钮时启动SingleInstanceSecondTest
            button.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    Intent intent=new Intent(SingleInstanceTest.this,SingleInstanceSecondTest.class);
                    startActivity(intent);
                }});
        }
        
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.single_instance_test, menu);
            return true;
        }
    
    }

     上面的粗体字代码指定单击按钮时将会启动SingleInstanceSecondTest,将该SingleInstanceSecondTest配置成singleInstance加载模式,并且将该Activity的exported属性配置成true——表明该Activity可被其他应用启动。

        配置该Activity的配置片段如下:

     <activity
                android:name="com.example.studyactivity.SingleInstanceSecondTest"
                android:label="@string/title_activity_single_instance_second_test"
                android:exported="true"
                android:launchMode="singleInstance" >
                <intent-filter>
    
                    <!-- 指定该Activity能响应Action为指定字符串的Intent -->
                   <action android:name="com.example.intent.action.CRAZY_T_ACTION" /> 
    
    
                  <category android:name="android.intent.category.DEFAULT" /> 
                </intent-filter>
            </activity>

    配置该Activity时,将它的exported属性设为true,表明允许通过其他程序来启动该Activity,配置该Activity时还配置了<intent-filter.../>子元素,这表明该Activity可通过隐式Intent启动。

        运行该示例,系统默认显示SingleInstanceTest,当用户单击该Activity界面上的按钮时,系统将会采用singleInstance模式加载SingleInstanceSecondTest:系统启动新的TaskTask、并用新的Task加载新创建的SingleInstanceSecondTest实例,SingleInstanceSecondTest总是位于该新Task的栈顶。

         另一个示例将采用隐式Intent再次启动该SingleInstanceSecondTest,下面是采用隐式Intent启动SingleInstanceSecondTest的示例的代码。

        

    package com.example.studyactivity;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Intent;
    import android.view.Menu;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    public class SingleInstanceOtherTest extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            LinearLayout layout=new LinearLayout(this);
            layout.setOrientation(LinearLayout.VERTICAL);
            setContentView(layout);
            //创建一个TextView来显示该Activity和它所在的Task ID
            TextView tv=new TextView(this);
            tv.setText("Activity为:"+this.toString()+"
    "+",Task ID为:"+this.getTaskId());
            Button button=new Button(this);
            button.setText("启动SingleInstanceSecondTest");
            //添加TextView和Button
            layout.addView(tv);
            layout.addView(button);
            //为button添加事件监听器,使用隐式Intent启动目标Activity
            button.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    //使用隐式Intent启动SingleInstanceSecondTest
                    Intent intent=new Intent();
                    intent.setAction("com.example.intent.action.CRAZY_T_ACTION");
                    startActivity(intent);
                }});
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.single_instance_other_test, menu);
            return true;
        }
    
    }

     运行该示例,系统默认显示SingleInstanceOtherTest,当用户单击该Activity界面上的按钮时,系统将采用隐式Intent来启动SingleInstanceSecondTest,注意SingleInstanceSecondTest的加载模式是singleInstance,如果前一个示例还未退出,无论SingleInstanceSecondTest所在的Task是否位于前台,系统将再次把SingleInstanceSecondTest所在的Task转入前台,从而将SingleInstanceSecondTest显示出来。

          

  • 相关阅读:
    docker基础总结
    python基础学习总结
    静默(命令行)安装oracle 11g
    java中如果函数return可能抛出异常怎么办
    Android 开发先驱的博客列表
    栈与队列
    线性表
    算法
    数据结构概论
    iOS开发中实现手势解锁
  • 原文地址:https://www.cnblogs.com/wolipengbo/p/3420664.html
Copyright © 2020-2023  润新知