《Android》Chap.3 探究Activity

Posted 我还能码嘛。

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Android》Chap.3 探究Activity相关的知识,希望对你有一定的参考价值。

Activity是⼀种可以包含用户界面的组件,主要用于和用户进行交互。

Activity的基本用法

创建和加载布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 1"/>

</LinearLayout>

属性介绍

  • id:给当前元素定义的
  • layout_widthlayout_height:
    match_parent:全屏铺满
    wrap_content:自动根据内容调节大小
    20dp:数值设置 单位为dp
  • text:显示文字内容
  • textSize:设置文字大小 单位为sp

给Activity加载布局

setContentView(R.layout.first_layout)

在AndroidManifest文件中注册

  • android:label=""用于指定Activity中标题栏的内容
<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>

用于声明该Activity为主Activity

运行程序

(部分截图)

在Activity中使用Toast

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.first_layout)

    val button1: Button = findViewById(R.id.button1)
    button1.setOnClickListener
        Toast.makeText(this,"You click Button1.",Toast.LENGTH_SHORT).show()
    

补充kotlin特性:

使用Kotlin编写的Android项目在app/build.gradle文件的头部默认引入了⼀个kotlin-android-extensions插件,这个插件会根据布局文件中定义的控件id自动生成⼀个具有相同名称的变量,就可以在Activity里直接使用这个变量,而不用再调用findViewById()方法了

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.first_layout)

    button1.setOnClickListener 
        Toast.makeText(this,"You click Button1.",Toast.LENGTH_SHORT).show()
    

运行程序

在Activity中使用Menu

文件路径

main.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add"/>

    <item android:id="@+id/remove_item"
        android:title="Remove"/>
</menu>

这里创建了两个菜单项,其中<item>标签用来创建具体的某⼀个菜单项,然后通过android:id给这个菜单项指定⼀个唯⼀的标识符,通过android:title给这个菜单项指定⼀个名称。

代码效果

重写onCreateOptionsMenu()方法

override fun onCreateOptionsMenu(menu: Menu?): Boolean 
    menuInflater.inflate(R.menu.main,menu)
    return true

  1. inflate()中的两个参数:
    第⼀个参数用于指定通过哪⼀个资源文件来创建菜单,这里当然是传入R.menu.main
    第⼆个参数用于指定菜单项将添加到哪⼀个Menu对象当中,这里直接使用onCreateOptionsMenu()方法中传入的menu参数。
  2. 最后给这个方法返回true,表示允许创建的菜单显示出来。

重写onOptionsItemSelected()方法

override fun onOptionsItemSelected(item: MenuItem): Boolean 
    when (item.itemId) 
        R.id.add_item -> Toast.makeText(this,"You click Add",Toast.LENGTH_SHORT).show()
        R.id.remove_item -> Toast.makeText(this,"You click Remove",Toast.LENGTH_SHORT).show()
    
    return true

运行代码

销毁Activity

finish()

使用Intent

Intent是Android程序中各组件之间进行交互的⼀种重要⽅方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent⼀般可⽤于启动Activity、启动Service以及发送广播等场景。

显式Intent

intent常用的构造函数接收两个参数:
第一个参数Context要求提供⼀个启动Activity的上下文
第二个参数Class用于指定想要启动的目标Activity
通过这个构造函数就可以构建出Intent的“意图”。
因为它的“意图”十分明显,所以称为显式Intent

代码实现

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.first_layout)

    button1.setOnClickListener 
        val intent = Intent(this,SecondActivity::class.java)
        startActivity(intent)
    

隐式Intent

隐式Intent并不明确指出想要启动哪⼀个Activity,而是指定了⼀系列更为抽象的actioncategory等信息,然后交由系统去分析这个Intent,并找出合适的Activity去启动。
通过在<activity>标签下配置<intent-filter>的内容,可以指定当前Activity能够响应的actioncategory

代码实现

AndroidManifest文件

FirstActivity

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.first_layout)

    button1.setOnClickListener 
        val intent = Intent("com.example.activitytest.ACTION_START")
        startActivity(intent)
    

android.intent.category.DEFAULT是⼀种默认的category,在调用startActivity()方法的时候会自动将这个category添加到Intent中。

补充

每个Intent中只能指定⼀个action,但能指定多个category。目前我们的Intent中只有⼀个默认的categor,可以通过addCategory()方法添加。

intent.addCategory("com.example.activitytest.MY_CATEGORY")

其他用法1

button1.setOnClickListener 
    val intent = Intent(Intent.ACTION_VIEW)
    intent.data = Uri.parse("https://www.baidu.com")
    startActivity(intent)

⾸先指定了IntentactionIntent.ACTION_VIEW,这是⼀个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法将⼀个网址字符串解析成⼀个Uri对象,再调用IntentsetData()方法将这个Uri对象传递进去。

这样在点击按钮时就可以看到在系统浏览器上打开了百度的网站

setData()方法接收⼀个Uri对象,用于指定当前Intent正在操作的数据,这些数据通常是以字符串形式传入Uri.parse()方法中解析产生的。

补充

与此对应,还可以在<intent-filter>标签中再配置⼀个<data>标签,用于更精确地指定当前Activity能够响应的数据。
<data>标签中主要可以配置以下内容:

标签用途
android:scheme用于指定数据的协议部分,如上例中的https部分
android:host用于指定数据的主机名部分,如上例中的www.baidu.com部分
android:port用于指定数据的端口部分,⼀般紧随在主机名之后
android:path用于指定主机名和端口之后的部分,如⼀段网址中跟在域名之后的内容
android:mimeType用于指定可以处理的数据类型,允许使用通配符的方式进行指定

只有当<data>标签中指定的内容和Intent中携带的Data完全⼀致时,当前Activity才能够响应该Intent

实践


其他用法2

button1.setOnClickListener 
    val intent = Intent(Intent.ACTION_DIAL)
    intent.data = Uri.parse("tel:10086")
    startActivity(intent)

点击Button1后,自动跳转到电话并输入号码

向下一个Activity传递数据

Intent中提供了⼀系列putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent中, 在启动另⼀个Activity后,只需要把这些数据从Intent中取出就可以了。
putExtra()方法接收两个参数,第⼀个参数是键,用于之后从Intent中取值,第⼆个参数才是真正要传递的数据。

class FirstActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)

        button1.setOnClickListener 
            val data = "Hello SecondActivity"
            val intent = Intent(this,SecondActivity::class.java)
            intent.putExtra("extra_data",data)
            startActivity(intent)
        
    

class SecondActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        val extraData = intent.getStringExtra("extra_data")
        Log.d("SecondActivity","extra data is $extraData")
    

向上一个Activity返回数据

class FirstActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)

        button1.setOnClickListener 
            val intent = Intent(this,SecondActivity::class.java)
            startActivityForResult(intent,1)
        
    

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) 
            1 -> if (resultCode == RESULT_OK)
                val returnData = data?.getStringExtra("data_return")
                Log.d("FirstActivity","returned data is $returnData")
            
        
    

class SecondActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        button2.setOnClickListener 
            val intent = Intent()
            intent.putExtra("data_return","Hello FirstActivity")
            setResult(RESULT_OK,intent)
            finish()
        
    

Activity的生命周期

Android是通过任务来管理Activity,一个任务就是一组存放在栈里的Activity的集合,这个栈被称为返回栈(back stack)

Activity的4种状态

  • 运行态 Running:位于当前返回栈的顶部
  • 暂停态 Paused:不在栈顶但用户可见
  • 停止态 Stopped:不在栈顶且完全不可见
  • 销毁态 Destroyed:从返回栈中移除后销毁

Activity的7个回调方法

  1. onCreate():activity第一次启动时被调用,在该方法中初始化activity所能使用的全局资源和状态,如:绑定事件,创建线程等。
  2. onStart():当activity对用户可见时调用,即activity展现在前端,该方法一般用来初始化或启动与更新界面相关的资源
  3. onResume():当用户与activity进行交互时被调用,此时activity位于返回栈的栈顶,并处于运行状态,该方法完成一些轻量级的工作,避免用户等待
  4. onPause():启动或恢复另一个activity的时候被调用,该方法一般用来保存界面的持久信息,提交未保存的数据,并释放消耗CPU的资源。
  5. onStop():该方法在activity不可见状态时调用,如:其他activity启动或恢复并将其覆盖时调用。
  6. onDestroy():在activity销毁之前被调用。
  7. onRestart():当activity重新启动时调用。

Activity的3种生存期

  • 完整生成期:Activity 在onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期。一般情况下,一个 Activity 会在onCreate()方法中完成各种初始化操作,而在onDestroy()方法中完成释放内存的操作。
  • 可见生存期: Activity 在onStart()方法和onStop()方法之间所经历的,就是可见生存期。在可见生存期内,Activity 对于用户总是可见的,即便有可能无法和用户进行交互。可以通过这两个方法,合理地管理那些对用户可见的资源。比如在onStart()方法中对资源进行加载,而在onStop()方法中对资源进行释放,从而保证处于停止状态的 Activity 不会占用过多内存。
  • 前台生存期:Activity 在onResume()方法和onPause()方法之间所经历的,就是前台生存期。在前台生存期内,Activity 总是处于运行状态的,此时的 Activity 是可以和用户进行交互的,我们平时看到和接触最多的也就是这个状态下的 Activity。

图解传送门

onSaveInstanceState()方法

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

class FirstActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)
        if (savedInstanceState != null) 
            val tempData = savedInstanceState.getString("data_key")
            Log.d("FirstActivity", "tempData is $tempData")
        
    

    override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) 
        super.onSaveInstanceState(outState)
        val tempData = "Something you just typed"
        outState.putString("data_key", tempData)
    

Activity的启动模式

standard

standardActivity默认的启动模式。
standard模式下,每当启动⼀个新的Activity,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的Activity,系统不会在乎这个Activity是否已经在返回栈中存在,每次启动都会创建⼀个Activity的新实例。

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    Log.d("FirstActivity",this.toString())
    setContentView(R.layout.first_layout)

    button1.setOnClickListener 
        val intent = Intent(this,FirstActivity::class.java)
        startActivity(intent)
    

singleTop

Activity的启动模式指定为singleTop,在启动Activity时如果发现返回栈的栈顶已经是该Activity,则认为可以直接使用它,不会再创建新的Activity实例。
如果发现该Activity并未处于栈顶位置时,则创建一个新的Activity实例。

singleTask

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

singleInstance

指定为singleInstance模式的Activity会启用⼀个新的返回栈来管理这个Activity
其实如果 singleTask 模式指定了不同的 taskAffinity,也会启动⼀个新的返回栈。

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.first_layout)
    Log.d("FirstActivity","Task id is $taskId")
    button1.setOnClickListener 
        val intent = Intent(this,SecondActivity::class.java)
        startActivity(intent)
    

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    Log.d("SecondActivity","Task id is $taskId")
    setContentView(R.layout.activity_second)
    button2.setOnClickListener 
        val intent = Intent(this,ThirdActivity::class.java)
        startActivity(intent)
    

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    Log.d("ThirdActivity","Task id is $taskId")
    setContentView(R.layout.activity_third)

Activity的最佳实践

知道当前在哪一个Activity

open class BaseActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        Log.d("BaseActivity", javaClass.simpleName)
    

让其他的活动都继承BaseActivity
然后运行程序,依次进入其他活动界面

随时随地退出程序

新建一个单例类ActivityCollector作为Activity的集合:

object ActivityCollector 

    private val activities = ArrayList<Activity>()

    fun addActivity(activity: Activity)
        activities.add(activity)
    
    
    fun removeActivity(activity: Activity)
        activities.remove(activity)
    

    fun finishAll()
        for (activity in activities)
            if (!activity.isFinishing)
                activity.finish()
            
        
        activities.clear()
    

BaseActivity中添加:
Android:日常学习笔记———探究UI开发

Android:日常学习笔记———探究UI开发

Android:日常学习笔记———探究广播机制

Android:日常学习笔记——探究活动

Android:日常学习笔记———探究UI开发

从0系统学Android--4.1探究碎片