小言_互联网的博客

Android从入门到放弃—— 一、门(Activity 1)

391人阅读  评论(0)

门——Activity(一)

Activity是什么:

Activity作为Andorid的四大组件之一,为用户提供了一个界面,即我们能看到的界面。相当于一张画画用的纸,我们可以在上面画任何我们想要的内容。

Activity的创建:

就像我们画画需要拿一张画纸铺在画板上一样,想要看到界面我们也需要创建一个Activity。创建的方法很简单,分为2步:

  1. 继承Activity类

  2. 在AndroidManifest.xml文件中配置

这里是使用Android Studio创建项目默认创建的MainActivity代码


  
  1. class MainActivity : AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_main)
  5. }
  6. }

AndroidManifest.xml


  
  1. <?xml version= "1.0" encoding= "utf-8"?>
  2. <manifest xmlns:android= "http://schemas.android.com/apk/res/android"
  3.      package= "com.example.androidteach">
  4.     <application
  5.         android:allowBackup= "true"
  6.         android:icon= "@mipmap/ic_launcher"
  7.         android:label= "@string/app_name"
  8.         android:roundIcon= "@mipmap/ic_launcher_round"
  9.         android:supportsRtl= "true"
  10.         android:theme= "@style/AppTheme">
  11.         <activity android:name= ".MainActivity">
  12.             <intent-filter>
  13.                 <action android:name= "android.intent.action.MAIN" />
  14.                 <category android:name= "android.intent.category.LAUNCHER" />
  15.             </intent-filter>
  16.         </activity>
  17.     </application>
  18. </manifest>

代码分析:

我们上面说第一步是要新建一个类继承自Activity,但是我们的MainActivity是继承的AppCompatActivity类。大家看名字就能知道这个是Activity的子类。当然你也可以手动修改为Activity类。之后的setContentView(R.layout.activity_main)是为当前界面设置一个布局文件,布局文件中就可以放下我们需要的各种控件,这里activity_main布局文件中有一个TextView,显示的文本内容是Hello Word。

我们再看AndroidManifest的内容:

在AndroidManifest中我们只需要关注activity标签中的内容。android:name属性指定当前配置的activity名称,这里配置的是” .MainActivity”,注意,前面有一个点,是相对路径,即当java代码包的根路径下的MainActivity文件。里面的intent-filter内容:<action android:name="android.intent.action.MAIN" />表示启动当前app的默认界面。<category android:name="android.intent.category.LAUNCHER" /> 表示当前的activity会在桌面(launcher)显示一个图标。

运行程序可以在手机或者模拟器看到当前界面显示hello word字样。

启动Activity:

首先我们需要自己创建一个Activity,操作如下图:

点击Finish完成即可,这样就创建好了一个Activity,同时AS也帮我们创建好了一个布局文件activity_second。

进入布局文件,我们同样的添加一个TextView:


  
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app= "http://schemas.android.com/apk/res-auto"
  4. xmlns:tools= "http://schemas.android.com/tools"
  5. android:layout_width= "match_parent"
  6. android:layout_height= "match_parent"
  7. tools:context= ".SecondActivity">
  8. <TextView
  9. android:id= "@+id/textView"
  10. android:layout_width= "wrap_content"
  11. android:layout_height= "wrap_content"
  12. android:text= "SecondActivity"
  13. app:layout_constraintBottom_toBottomOf= "parent"
  14. app:layout_constraintEnd_toEndOf= "parent"
  15. app:layout_constraintStart_toStartOf= "parent"
  16. app:layout_constraintTop_toTopOf= "parent" />
  17. </androidx.constraintlayout.widget.ConstraintLayout>

这里完成了第二个Activity的创建。回到activity_main.xml布局中,给TextView添加一个Id,同时改变显示的文字。

记住必须要在Manifest文件中配置:


  
  1. <application
  2. android:allowBackup= "true"
  3. android:icon= "@mipmap/ic_launcher"
  4. android:label= "@string/app_name"
  5. android:roundIcon= "@mipmap/ic_launcher_round"
  6. android:supportsRtl= "true"
  7. android:theme= "@style/AppTheme">
  8. <activity android:name=".SecondActivity"> </activity>
  9. <activity android:name=".MainActivity">
  10. <intent-filter>
  11. <action android:name="android.intent.action.MAIN" />
  12. <category android:name="android.intent.category.LAUNCHER" />
  13. </intent-filter>
  14. </activity>
  15. </application>

这里添加了一个activity标签,android:name属性值为".SecondActivity",同样的前面有一个点,因为我们的SecondActivity也是在当前项目的根目录,所以这里的路径就直接写。如果还有子包,则这里的路径需要加上。

在MainActivity的代码中添加如下代码:


  
  1. override fun onCreate(savedInstanceState: Bundle?) {
  2. super.onCreate(savedInstanceState)
  3. setContentView(R.layout.activity_main)
  4. acMainTvJump.setOnClickListener {
  5. val intent = Intent( this, SecondActivity:: class.java)
  6. startActivity(intent)
  7. }
  8. }

运行程序,然后点击MainActivity文本,界面就会跳转到我们刚刚建立的SecondActivity中。

代码分析:

创建SecondActivity的代码比较简单就不做介绍了,主要的代码就在MainActivity中添加的4行代码。

acMainTvJump为textView的ID,这里使用了kotlin语言,kotlin相关的内容这里就不做介绍了。通过设置textview的点击事件,我们在点击时进行activity的跳转。其中关键的一个类:Intent。Intent可以理解为我们想要完成某一件事情的意图,这里我们的意图是跳转到SecondActivity,其构造方法接受2个参数(Intent的构造方法有很多):

可以看到这里第一个参数为packageContext,这里可以直接传入this。第二参数为class,即我们需要跳转的activity。

Activity的生死历程:

要了解Activity的生命周期,这里就不得不祭出官方的祖传图了:

Activity 类提供六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop() 和 onDestroy()

onCreate:这个方法是我们必须要重写的,activity刚刚创建的是系统会调用这个方法,我们通过setContentView来为Activity设置布局,可以是布局ID,也可以是直接用代码写的一个View。这个时候Activity还是不可见的。

onStart:这个时候Activity已经可见了,相当于我们的界面经过onCreate已经准备好了。但是Activity并不是一直处于这个状态,系统调用完这个方法后会进入下一阶段。

onResume:这个状态Google定义为“已恢复”状态,这个时候Activity进入前台,将长期处于当前状态,并且能和用户进行交互。

onPause:当发生中断事件时,Activity 进入已暂停状态,系统调用 onPause() 回调。这里的中端事件有点模糊,待会我们可以用代码来模拟。如果 Activity 从onPause状态返回“已恢复”状态,系统将再次调用 onResume() 方法。此方法表示 Activity 不再位于前台(尽管如果用户处于多窗口模式,Activity 仍然可见)

onStop:这个时候Activity已经不可见,比如我们新启动了一个Activity覆盖了当前的Activity。

onDestroy:调用此方法时Activity被销毁。如用户按下返回键、代码中调用finish。

通过图片我们看到还有一个方法:onRestart,这个回调发生在重新进入Activity的时候。下面我们通过代码来实际看看各个回调的调用顺序。

在MainActivity和SecondActivity中都重写这几个回调方法并且打印log


  
  1. class MainActivity : AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. Log.d( "MainActivity", "ZLog onCreate :")
  5. setContentView(R.layout.activity_main)
  6. acMainTvJump.setOnClickListener {
  7. val intent = Intent( this, SecondActivity:: class.java)
  8. startActivity(intent)
  9. }
  10. }
  11. override fun onStart() {
  12. super.onStart()
  13. Log.d( "MainActivity", "ZLog onStart :")
  14. }
  15. override fun onResume() {
  16. super.onResume()
  17. Log.d( "MainActivity", "ZLog onResume :")
  18. }
  19. override fun onRestart() {
  20. super.onRestart()
  21. Log.d( "MainActivity", "ZLog onRestart :")
  22. }
  23. override fun onPause() {
  24. super.onPause()
  25. Log.d( "MainActivity", "ZLog onPause :")
  26. }
  27. override fun onStop() {
  28. super.onStop()
  29. Log.d( "MainActivity", "ZLog onStop :")
  30. }
  31. override fun onDestroy() {
  32. super.onDestroy()
  33. Log.d( "MainActivity", "ZLog onDestroy :")
  34. }
  35. }

SecondActivity类似,就不贴代码了。同样我们运行程序查看log

看到如图的log,我们启动MainActivity后对应的3个回调被调用,最后停留在onResume这里。这个时候我们点击文本跳转到SecondActivity

我们看到首先被调用的是MainActivity的onPause,为什么?因为这个时候系统是先将当前的Activity设置为暂停状态,放到后台,而后开始准备要显示在前台的SecondActivity,于是SecondActivity开始创建和显示到前台。这个时候MainActivity完全不可见,设置为stop状态。

这个时候我们再点击返回按钮

点击返回按钮发生的事件流程:SecondActivity首先退出前台进入后台(调用onPause),MainActivity准备再次显示进入前台,所以调用了onRestart-onstart-onResume进入前台可见。这个时候SecondActivity不可见(onStop),并且进行销毁(onDestroy)。

Activity启动模式

之前说Activity就像画画的画布,这里的画布我们理解为透明的,我们是可以一层一层的叠加的,类似Photoshop的图层。这个时候添加就有讲究了。Android提供了4种模式:standard、singleTop、singleTask、singleInstance。4种模式的设置同样在Manifest种activity标签配置,android:launchMode="standard"。

standard:这个是默认的模式,也是最简单的模式。即每次启动任何activity都直接在之前的activity上添加。

我们正常启动A,在A种启动B,再在B中启动A。按照图中所示,这个时候栈中应该有3个Activity,我们需要按下3次返回键才能推出APP。上代码看看:

我们在SecondActivity中添加了点击事件,启动MainActivity。注意,2个Activity的onCreate方法中打印了当前的对象的地址

通过打印信息我们可以发现MainActivity出现2次,并且不是同一个实例。我们按下返回键查看,需要按下3次才能退出:

singleTop:这种模式主要是为了应对另一种情况,如果刚刚在SecondActivity中再次启动SecondActivity会怎么样?如果是standard则直接新加一个。但如果我们把SecondActivity的模式设置为singleTop呢?

再来查看log信息

可以看到我们点击事件触发后并没有新的SecondActivity被创建。

当我们设置Activity为singleTop时,会启动一个栈顶复用机制。即如果Activity栈顶的Activity跟我们要启动的Activity是同一个,系统并不会重新创建新的,而是直接使用当前的Activity。可以理解为不做任何操作。

singleTask:有没有感觉singleTop模式并不是那么的完美?只能实现栈顶的复用,那要是返回栈中有,但是不是在栈顶的想要复用呢?对,那就设置singleTask模式吧。为什么验证,我们代码需要再改改。

首先我们把MainActivity设置为singleTask,目的就是重复的启动MainActivity。

在SecondActivity中的点击事件我们就启动MainActivity。即 A——B——A这样的顺序,下面我们看log

可以看到SecondActivity中点击事件触发之后MainActivity并没有重新初始化。那是怎么复用的呢?

我们按下返回键看看

what? 为什么只按了一下返回就退出了?因为它很聪明,直接把MainActivity之上的所有Activity都移除了,直接让自己处于栈顶。

来看一下完整的log

重点是在SecondActivity中点击之后,SecondActivity被销毁了。

singleInstance:这个模式是最复杂的一种。之前的3种模式我们所说的返回栈都是同一个返回栈,而这个会启用新的返回栈。

这里我们先把文件改一下

BActivity设置为singleInstance,A、C为默认,按照A——B——C的顺序启动。

我们在onCreate中打印当前taskId

通过log我们可以看到BActivity的taskId跟其他2个不同,说明B是处在一个新的返回栈中。我们在B中启动了C,可能有的朋友会想,C应该跟B在同一个栈中才对。事实是C还是和A在同一个栈中。这里要特别注意,因为singleInstance是独占栈的模式,这个栈里面只能有B。

这个时候我们再来按下返回键看看

我们看到在C界面按下返回,显示的MainActivity(A),刚刚我们说了 C和A是在一个返回栈,所以C返回之后A就显示出来了,A再返回,当前返回栈就全部退出了,这个时候才会再显示B所在的返回栈,因为B里面只有它一个,所以显示了B,再返回所有的就都返回了,退出APP。

好了,先暂时写到这里,后续还将继续介绍Activity相关的其他内容。

欢迎大家指出错误的地方,我们共同学习。


转载:https://blog.csdn.net/zgy441008825/article/details/105961701
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场