第一行代码Android----阅读笔记(探究活动_2)

第2章 探究活动_2

2.4 活动的生命周期

        Android使用任务(Task)来管理活动的,一个任务就是一组存放在栈里活动的集合,这个栈也称作返回栈(Back Stack)。栈是先进后出的数据结构。

2.4.2 活动状态

        每个活动在其生命周期中最多会有4种状态。

  • 运行状态----当活动位于返回栈的栈顶时,活动处于运行状态。
  • 暂停状态----当活动不再处于栈顶位置,但仍然可见时,活动进入暂停状态。
  • 停止状态----当活动不再处于栈顶位置,并且完全不可见时,就进入停止状态(系统仍会为活动保存相应的状态和成员变量)。
  • 销毁状态----当活动从返回栈中移除后就变成销毁状态。

2.4.3 活动的生存期

        Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节。

  • onCreate()----在活动第一次被创建的时候调用,在这个方法中完成活动的初始化操作,比如加载布局、绑定事件等。
  • onStart() ---- 这个方法在活动由不可见变为可见的时候调用。
  • onResume() ---- 在活动准备好和用户进行交互的时候调用。此时活动一定位于返回栈的栈顶,并处于运行状态。
  • onPause() ---- 在系统准备去启动或恢复另一个活动的时候调用。
  • onStop() ---- 在活动完全不可见的时候调用。和onPause()方法的主要区别在于:如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()并不会执行。
  • onDestroy() ---- 在活动被销毁之前调用,之后活动的状态将变为销毁状态,释放内存操作。
  • onRestart() ---- 在活动由停止状态变为运行状态之前调用,活动被重新启动。

        以上7个方法中除了onRestart()方法,其他都是两两相对的,从而将活动分为3种生存期。

  • 完整生存期 ---- 活动在onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期。
  • 可见生存期 ---- 活动在onStart()方法和onStop()方法之间所经历的,就是可见生存期。可以通过这两个方法,合理管理对用户可见的资源。比如在onStart()方法中对资源进行加载,在onStop()方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。
  • 前台生存期 ---- 活动在onResume()方法和onPause()方法之间所经历的,就是前台生存期在前台生存期内,活动总是处于运行状态的,此时的活动时可以和用户进行交互的

2.4.4 体验活动的生命周期

        新建一个ActivityLifeCycleTest项目,系统自动创建主活动和布局,再分别创建两个子活动-----NormalActivity和DialogActivity。编辑normal_layout.xml文件,代码替换如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This is a normal activity"/>

</LinearLayout>

        这个布局中使用了一个TextView用于显示一行文字。同理,替换dialog_layout.xml代码。

        下面,将DialogActivity活动设置成对话框模式。修改AndroidManifest.xml的<activity>标签的配置,如下所示:

        <activity
            android:name=".DialogActivity"
            android:exported="false"
            android:theme="@style/Theme.AppCompat.Dialog">
        </activity>
        <activity
            android:name=".NormalActivity"
            android:exported="false" />

        这里是两个活动的注册代码,对DialogActivity的注册代码使用了一个android:theme属性,用于给当前Activity指定主题,Android系统内置有很多主题可以选择,当然也可以定制自己的主题,这里是对话框式的主题。

        接下来修改activity_main.xml,加入两个按钮,一个用于启动NormalActivity,一个用于启动DialogActivity。最后修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {

    public static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        setContentView(R.layout.activity_main);
        Button startNormalActivity = (Button) findViewById(R.id.startNormalActivity);
        Button startDialogActivity = (Button) findViewById(R.id.startDialogActivity);
        startNormalActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, NormalActivity.class);
                startActivity(intent);
            }
        });
        startDialogActivity.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, DialogActivity.class);
                startActivity(intent);
            }
        });
    }

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

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

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

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

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

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

        运行程序,当MainActivity第一次被创建时会依次执行onCreate()、onStart()和onResume()方法(通过Logcat中打印日志可以看到)。然后点击第一个按钮,启动NormalActivity。由于Normal-Activity已经把MainActivity完全遮住,因此onPause()和onStop()方法都会得到执行。然后按下Bac-k键返回MainActivity。由于之前MainActivity已经进入了停止状态,所以onRestart()方法会得到执行,之后会依次执行onStart()和onResume()方法。注意,此时onCreate()方法不会执行,因为MainActivity并没有重新创建

        然后点击第二个按钮,启动DialogActivity。可以看到,只有onPause()方法得到了执行,onStop()方法并没有执行,这是因为DialogActivity并没有完全遮挡住MainActivity,此时Main-Activity只是进入了暂停状态,并没有进入停止状态。相应地,按下Back键返回MainActivity也应该只有onResume()方法会得到执行。最后在MainActivity按下Back键退出程序,依次会执行onPause()、onStop()和onDestory()方法,最终销毁MainActivity。

2.4.5 活动被回收了

        背景:用户在Activity A的基础上启动了Activity B,这时Activity A就进入了停止状态,这时由于系统内存不足,将Activity A回收掉了然后用户按下Back键返回Activity A,会正常显示Activ-ity A的,只不过这时并不会执行onRestart()方法,而是会执行Activity A的onCreate()方法,因为Activity A在这种情况下会被重新创建一次。        

        问题:若Activity A中存在临时数据和状态,被重新创建后,数据会丢失。

        Activity中提供了一个onSaveInstanceState()回调方法,这个方法可以保证在Activity被回收之前一定会被调用。onSavaInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle中取值,第二个参数是真正要保存的内容。

        在MainAcitivity中添加如下代码就可以将临时数据进行保存:

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        String tempData = "Something you just typed";
        outState.putString("data_key", tempData);
    }

       保存数据的恢复:onCreate()方法也有一个Bundle类型的参数,这个参数在一般情况下都是null,但是如果在活动被系统回收之前有通过onSaveInstance()方法来保存数据的话,这个参数就会带有之前所保存的全部数据,只需再通过相应的取值方法将数据取出即可。 修改MainActivity的onCreate()方法,如下:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(savedInstanceState != null){
            String tempData = savedInstanceState.getString("data_key");
            Log.d(TAG, tempData);
        }
       ...
    }

        取出值后再做相应的恢复操作就可以了,这里只是简单打印。使用Bundle来保存和取出数据与使用Intent传递数据方法类似。Intent还可以结合Bundle一起用于传递数据,首先可以把需要传递的数据都保存在Bundle对象中,然后再将Bundle对象存放在Intent里。到了目标活动之后先从Intent中取出Bundle,再从Bundle中一一取出数据。

2.5 活动的启动模式

        启动模式一共有4种,分别是standard、singleTop、singleTask和singleInstance,可以在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。

2.5.1 standard

        standard是Activity默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。在standard模式下,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。问题:重复创建栈顶活动。standard模式原理示意图如下:

2.5.2 singleTop

        当活动模式指定为singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。指定模式代码示例如下:

        <activity
            android:name=".FirstActivity"
            android:launchMode="singleTop"
            android:exported="true"
            android:label="This is FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        不过当FirstActivity并未处于栈顶位置时,这时再启动FirstActivity,还是会创建新的实例。singleTop模式原理示意图如下:

2.5.3 singleTask

        当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。singleTask模式原理示意图如下:

2.5.4 singleInstance

        不同于以上3种启动模式,指定为singleInstance模式的活动会启动一个新的返回栈来管理这个活动(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。

        问题背景:想实现其他程序和当前程序可以共享这个活动的实例。

        使用singleInstance模式可以解决,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用同一个返回栈,也就解决了共享活动实例的问题。singleInstance模式的原理示意图如下:

2.6 活动的最佳实践

2.6.1 知晓当前是在哪一个活动

        根据程序当前界面判断出这是哪一个活动。在ActivityTest项目的基础上修改,首先需新建一个BaseActivity类。右击com.example.activitytest包----New----Java Class,在弹出的窗口输入类名。注意:这里BaseActivity和普通活动的创建方式不一样,因为不需要让BaseActivity在Android-Manifest.xml中注册,所以选择创建一个普通的Java类就可以了。然后让BaseActivity继承自AppCompatActivity,并重写onCreate()方法,如下所示:

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
    }
}

        在onCreate()方法中获取当前实例的类名,并通过Log打印出来。接下来让BaseActivity成为ActivityTest项目中所有活动的父类。重新运行程序,通过点击按钮进入不同活动界面,观察打印信息。每当进入一个活动界面,该活动的类名就会被打印出来,这样就可以时时刻刻知晓当前界面对应的是哪一个活动了。

2.6.2 随时随地退出程序

        问题背景:若手机界面停留在ThirdActivity,想退出活动需连按3次Back键,按Home键只是把程序挂起,并没有退出程序。

        解决思路:需要用一个专门的集合类对所有的活动进行管理

        新建一个ActivityCollector类作为活动管理器,代码如下:

public class ActivityCollector {

    public static List<Activity> activities = new ArrayList<>();

    public static void addActivity(Activity activity){
        activities.add(activity);
    }

    public static void removeActivity(Activity activity){
        activities.remove(activity);
    }

    public static void finishAll(){
        for (Activity activity : activities){
            if (!activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

        在活动管理器中,通过一个List来暂存活动,然后提供一个addActivity()方法用于向List中添加一个活动,提供了一个removeActivity()方法用于从List中移除活动,最后提供了一个finishAll()方法用于将List中存储的活动全部销毁掉。

        接下来修改BaseAcitivity中的代码,如下:

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

        在BaseActivity的onCreate()方法中调用了ActivityCollector的addActivity()方法,表明将当前正在创建的活动添加到活动管理器里。然后再BaseActivity中重写onDestroy()方法,并调用了ActivityCollector的removeActivity()方法,表明将一个马上要销毁的活动从活动管理器里移除。

        从此,不管想在什么地方退出程序,只需调用ActivityCollector.finishAll()方法就可以了。例如在ThirdActivity界面想通过点击按钮直接退出程序,只需将代码改成如下:

public class ThirdActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.third_layout);
        Button button3 = (Button) findViewById(R.id.button_3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityCollector.finishAll();
            }
        });
    }
}

        还可以在销毁所有活动的代码后面再加上杀掉当前进程的代码,以保证程序完全退出,杀掉进程的代码如下:

                android.os.Process.killProcess(android.os.Process.myPid());

        其中,killProcess()方法用于杀掉一个进程,它接收一个进程id参数,可以通过myPid()方法来获取当前程序的进程id。需要注意的是,killProcess()方法只能用于杀掉当前程序的进程,不能使用这个方法去杀掉其他的程序。

2.6.3 启动活动的最佳写法

        启动活动的方法回顾:首先通过Intent构建当前的“意图”,然后调用startActivity()start-ActivityForResult()方法将活动启动起来,如果在活动之间传递数据,也可借助Intent完成。

        问题背景:传递多个参数时,传递方可能不清楚对方需要哪些数据。

        解决办法:修改传参启动活动写法。修改SecondActivity中的代码,如下:

public class SecondActivity extends BaseActivity {

    public static void actionStart(Context context, String data1, String data2){
        Intent intent = new Intent(context, SecondActivity.class);
        intent.putExtra("param1", data1);
        intent.putExtra("param2", data2);
        context.startActivity(intent);
    }
...
}

        在SecondActivity中添加了一个actionStart()方法,在这个方法中完成了Intent的构建,另外所有SecondActivity中需要的数据都是通过actionStart()方法的参数传递过来的,然后存储到Intent中,最后调用startActivity()方法启动SecondActivity

        这样写一目了然,SecondActivity所需要的数据在方法参数中全部体现出来,非常清晰地知道启动SecondActivity需要传递哪些数据。另外,这样写简化了启动活动的代码,现在只需一行代码就可以启动SecondActivity,如下

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SecondActivity.actionStart(FirstActivity.this, "data1","data2");
            }
        });
  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: android-x86_64-9.0-r2-k49.iso是一个Android操作系统的镜像文件,专为64位PC和笔记本电脑而设计。该操作系统基于谷歌的Android Open Source Project(AOSP)构建,并且可以在x86、AMD和Intel设备上运,支持UEFI USB和Legacy-BIOS引导方式。 这个镜像文件是第9版Android操作系统的第2个修订版本,其中包含了最新的安全补丁程序和功能更新。该版本的Android系统最初于2019年10月发布,旨在改善性能、增强隐私保护和加强系统稳定性,同时提供更多的自定义选项和新功能。 这个镜像文件具有实用性,可作为装备在个人计算机和笔记本电脑上的操作系统。用户可以通过下载这个镜像文件并将其安装在电脑上,轻松地运Android应用程序,并在个人电脑上获得更好的使用体验。同时,该操作系统还可以用于应用程序开发和测试,以确保Android应用程序在不同设备上的兼容性和性能。 总之,android-x86_64-9.0-r2-k49.iso是一个可靠和实用的Android操作系统的扩展,具有更好的性能、安全和用户体验,是适用于PC和笔记本电脑的优秀操作系统。 ### 回答2: android-x86_64-9.0-r2-k49.iso 是一个 Android 操作系统的 64 位版本,主要针对 x86 架构的计算机或虚拟机而设计。其中的 9.0-r2 表示这是基于 Android 9.0 版本的第二个版本,而 k49 则是表明该版本为基于 Linux Kernel 4.9 的版本。 Android-x86_64-9.0-r2-k49.iso 的最大特点是可以在个人电脑上或者虚拟机上直接安装运,让普通计算机用户也可以享受到 Android 系统的特性。用户可以在其上安装和运普通的 Android 应用程序,通过模拟 Android 手机的界面让用户体验更加舒适自然。同时,这个版本还具备较高的兼容性和适应性,兼容广泛的硬件设备,同时支持多种存储方式,例如 U 盘、SSD 硬盘等。 与 Android 手机不同,Android-x86_64-9.0-r2-k49.iso 也启动了类似于 Grub 的引导程序,用户可以通过键盘选择和启动其它操作系统或者直接运安装的 Android 操作系统。同时,安装过程也需要用户进操作,用户需要选择安装到哪个磁盘,是否格式化磁盘等。在使用上,用户也需要注意一些特殊的设置,例如键位设置等,以便更好地适应 Android 系统的操作方式。 总之,Android-x86_64-9.0-r2-k49.iso 版本是一个非常有趣和实用的 Android 操作系统,它可以让 PC 用户更好的体验 Android 操作系统,同时也带来更多的选择和便利性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值