点击上方“罗晓胜”,马上关注,您的支持对我帮助很大

上期文章

  • 从0到1学android:认识Android

  • 逻辑题——特尔斐城的少女

/   前言   /

活动(Activity)是一种可以包含用户界面的组件, 相当于一个页面,可以在Activity中添加Button、CheckBox 等控件, 主要用于和用户进行交互, 一个应用程序中可以包含零个或多个活动。

/   正文   /

活动Activity

2.2 Activity的基本用法

到现在为止,你还没有手动创建过活动呢,因为上一章中的 HelloWorldActivity 是 ADT 帮我们自动创建的。手动创建活动可以加深我们的理解,因此现在是时候应该自己动手了。

首先,你需要再新建一个 Android 项目,项目名可以叫做 ActivityTest,包名我们就使用 默认值 com.example.activitytest。新建项目的步骤你已经在上一章学习过了,不过图 1.12 中 的那一步需要稍做修改,我们不再勾选 Empty Activity 这个选项,而是选择Add No Activity,因为这次准备手动创建活动 点击 Finish, 等待Gradle构建完成,项目就创建完成了。

手动创建Activity

右键包名:com.example.activitytest,选择New→Activity→Empty Activity,对话框中命名FirstActivity即可 代码如下:

package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {//任何Activity需要重写父类的onCreate方法override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)}
}

创建和加载布局

Android程序的设计讲究逻辑和程序分离 创建布局操作步骤:Res目录->New->Directory->创建Layout目录->New->Layout Resourcce file->将布局文件命名为first_layout。点击右上角按钮切换为Design可视化布局或XML编辑布局。代码示例如下:(这里用按钮button举例)

<?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"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/button1"android:text="Button 1"></Button>
</LinearLayout>

android: id 是唯一标识符,不允许重复 android:layout_width 指定了当前元素 的宽度,这里使用 match_parent 表示让当前元素和父元素一样宽。android:layout_height 指定 了当前元素的高度,这里使用 wrap_content,表示当前元素的高度只要能刚好包含里面的内 容就行。android:text 指定了元素中显示的文字内容。

随后在Activity中加载这个布局,使用setcontentView给当前加载一个布局,一般方法是传入布局文件的id。项目添加的任何资源都会在R文件中生成一个布局文件的id,因此上述xml文件的id已经添加进入了,只需要引用即可。

package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {//任何Activity需要重写父类的onCreate方法override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.first_layout)}
}

在AndroidManifest.xml中注册

注:所有的活动都要在 AndroidManifest.xml 中进行注册才能生效, Actvity的注册声明要放在application标签内,通过对Activity进行注册, android:name用于指定哪一个Activity,这里采用了缩写,目前没有配置主程序Activity,因此仍然无法运行。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapplication"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"></activity></application></manifest>

android中配置主Activity的方案是内部加入标签,然后在此标签中加入两句必要的声明,android:label指定了标题内容。修改后的代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapplication"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activityandroid:name=".MainActivity"android:label="This is Activity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest>

这个我在前面也已经解释过了,如果你想让 FirstActivity 作为我们这个程序的 主活动,即点击桌面应用程序图标时首先打开的就是这个活动,那就一定要加入这两句声明。另外需要注意,如果你的应用程序中没有声明任何一个活动作为主活动,这个程序仍然是可 以正常安装的,只是你无法在启动器中看到或者打开这个程序。

在Activity中使用Toast

Toast是一种非常好的提醒方式,实现如下:

package com.example.myapplicationimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import kotlinx.android.synthetic.main.first_layout.*class MainActivity : AppCompatActivity() {//任何Activity需要重写父类的onCreate方法override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.first_layout)//findViewById获取布局文件中定义的元素,R.id.button1得到按键实例,返回一个继承自View的泛型变量//因为无法自动推导,所以显式声明为Button类型。val button1: Button = findViewById(R.id.button1)//得到按键实例后,我们调用setOnClickListener注册监听器,点击按钮会执行onclick方法button1.setOnClickListener {//静态方法makeText创建一个Toast对象,共三个参数,一个是上下文,Activity本身就是context对象;第二个是文本内容;第三个是Toast显示时长Toast.makeText(this, "you clicked button 1", Toast.LENGTH_SHORT).show()}}
}

如果十个控件,Java需要十个findViewById才行,需要借助ButterKnife才能解决;在Kotlin中Android项目的gradle文件中默认引入Kotlin-android-extensions插件,会根据布局文件定义的控件id自动生成一个具有相同名称的变量,直接使用这一变量,删除findViewById这一行。推荐使用后者。

在Activity中引入Menu

   Menu是目录,不占用任何屏幕控件,创建如下:res目录->右击选New->Directory->输入文件名menu->右击选New->Menu resource file->输入文件名main。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- item用于创建某一个菜单项,指明唯一标识符和名称--><itemandroid:id="@+id/add_item"android:title="Add" /><itemandroid:id="@+id/remove_item"android:title="remove" />
</menu>

再回到mainActivity,重写onCreateOptionsMenu方法,编写如下方法:

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {//menuInflater调用了父类的getmenuInflater方法,在调用它的inflate方法就可以创建菜单了,// 两个参数:一个是哪一个资源文件的id;另一个是添加到哪一个Menu对象。menuInflater.inflate(R.menu.main, menu)//返回true显示出来,返回false则不显示return true
}

插一点语法糖概念,自动将下面的代码转换为setPages方法和getPages方法。非常简单的Java类和调用的语法糖。

package com.example.myapplication;public class Book {private int pages;public int getPages() {return pages;}public void setPages(int pages) {this.pages = pages;}
}val book = Book()
book.pages = 500
val bookPages = book.pages

另外,仅显示还不够,必须要有相应的点击事件。复写onOptionsItemSelected即可。

    override fun onOptionsItemSelected(item: MenuItem?): Boolean {//语法糖的小应用,调用了item的getItemId方法when (item?.itemId) {//语法逻辑:匹配值->{执行逻辑}R.id.add_item -> Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show()R.id.remove_item -> Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show()}return true
}

销毁一个Activity

    Back键或者使用finish()方法。

2.3 使用Intent在Activity之间穿梭

显式Intent

   创建第二个Activity,并在其中加入一个按钮。Intent是Android各组件进行交互的一种重要方式,可以不同组件传递数据、指明要执行动作。譬如:启动Activity、启动Service、发送广播等。Intent有两种,一种是显式,一种是隐式。下面介绍前者。
 button1.setOnClickListener {//Intent接受两个参数:第一个参数context提供了启动Activity的上下文;第二个参数是要启动的目标Activity//this是当前上下文,第二个SecondActivity::class.java相当于Java的SecondActivity.classval intent = Intent(this, SecondActivity::class.java)//启动Activity,接受一个Intent参数startActivity(intent)}

隐式Intent

隐式Intent通过指定一系列更为抽象的action和category等信息去决定启动哪一个Activity。首先在AndroidManifest.xml中的intent-filter中声明action和category。如下所示:

   <activity android:name=".SecondActivity"><intent-filter><action android:name="com.example.myapp.ACTION_START"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity>

action标明做啥动作,category是附加信息。只有两者内容同时匹配Intent的指定时,才能响应Intent。响应代码如下所示:

  button1.setOnClickListener {val intent = Intent("com.example.myapp.ACTION_START")startActivity(intent)}

刚不是说两个同时匹配么?这是因为android.intent.category.DEFAULT是默认的category,会将其自动添加进去。每个Intent有一个action和多个category。

     button1.setOnClickListener {val intent = Intent("com.example.myapp.ACTION_START")intent.addCategory("com.example.myapp.my_category")startActivity(intent)}

Intent中添加了category,但xml中的没有,需要再添加一个category的声明。在xml中声明。

        <activity android:name=".SecondActivity"><intent-filter><action android:name="com.example.myapp.ACTION_START" /><category android:name="android.intent.category.DEFAULT" /><category android:name="com.example.myapp.my_category" /></intent-filter></activity>

更多隐式Intent的用法

   隐式Intent不仅启动程序内的Activity,还可以启动其他程序的Activity。举例来讲,应用程序内展示一个网页百度。
        button1.setOnClickListener {//action是Intent.ACTION_VIEW,安卓内置动作android.intent.action.VIEWval intent = Intent(Intent.ACTION_VIEW)//Uri.parse将字符串解析成Uri对象,然后再使用setData传入,这里使用了语法糖,使得看起来是给Intent的data赋值intent.data = Uri.parse("https://www.baidu.com")startActivity(intent)}
   另外,<data>标签用于指定数据协议之类的,书中讲的比较粗略,除了https协议,仍有geo地理位置、tel打电话等。譬如,打电话给10086。
        button1.setOnClickListener {//内置动作,拨号val intent = Intent(Intent.ACTION_DIAL)//data部分指定了协议是tel,号码是10086intent.data = Uri.parse("tel:10086")startActivity(intent)}

向下一个Activity传递数据

   Intent在启动Activity过程中可以传递数据。Intent中提供了putExtra方法进行重载,举例来讲:将字符串从一个Activity中传递至第二个Activity中。
        button1.setOnClickListener {val data = "Hello SecondActivity"val intent = Intent(this, SecondActivity::class.java)//putExtra接受的是键值对,第一个参数是键,用于后面取值;第二个是真正要传递的数据intent.putExtra("extra_data", data)startActivity(intent)}
  在第二个Activity中将传递的数据拿出,并将其打印出来。
class SecondActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.layout_second)//intent调用的是getIntent方法,会获取用于启动SecondActivity的Intent,getStringExtra获取到传递的数据//getIntExtra拿到的是整形;getBooleanExtra拿到的是布尔类型val extradata = intent.getStringExtra("extra_data")Log.d("SecondActivity", "extra data is $extradata")}
}

返回数据给上一个Activity

   既可以传递数据给下一个Activity,那么将数据返回给一个Activity也是可行的。
        button1.setOnClickListener {val intent = Intent(this, SecondActivity::class.java)startActivityForResult(intent, 1)}
   startActivityForResult方法接受两个参数:第一个参数是Intent,第二个参数是请求码。用于在之后的回调中判断数据来源。
class SecondActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.layout_second)button2.setOnClickListener {//Intent传递数据,没有任何意图,只需要将数据存放进去val intent = Intent()intent.putExtra("data_return", "Hello FirstActivity")//setResult接受两个参数:第一个是用于向上一个Activity返回处理结果,一般是RESULT_OK或者RESULT_CANCELED//第二个是带有数据的intent传递过去。最后调用finish销毁。setResult(Activity.RESULT_OK, intent)finish()}}
}
   最后需要在第一个Activity重写方法得到返回的数据。
  //第一个参数requestCode是启动Activity时传入的请求码;第二个参数resultcode是返回数据传入的处理结果//第三个参数是data数据,携带intent。override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)//requestcode是判断数据来源when (requestCode) {//resultcode是判断处理结果是否成功与否。1 -> if (resultCode == Activity.RESULT_OK) {val returnedData = data?.getStringExtra("data_return")//将data值打印出来Log.d("MainActivity", "returned data is $returnedData")}}
}
   那么如果用户不是通过点击事件返回,而是点击Back键回到第一个Activity,如何处理?通过在第二个Activity中重写onBackPressed方法来解决这个问题。
    override fun onBackPressed() {val intent = Intent()intent.putExtra("data_return", "Hello FirstActivity")setResult(Activity.RESULT_OK, intent)finish()
}

2.4 活动生命周期:

返回栈

    栈后进先出,这个栈在Android中被称为返回栈。默认情况,启动Activity入栈并处于栈顶位置,back键或者finish方法时,栈顶将会被移除。

Activity状态

    Activity有四种状态:1.运行状态:当Activity处于栈顶时;2.暂停状态:不再处于栈顶但可见,并不是每一个Activity都会占满屏幕。eg:对话框形式的Activity占用屏幕中间部分区域,下面的Activity是暂停的,一般不会回收;3.停止状态:不再处于栈顶且完全不可见。当其他地方需要内存时,该状态的Activity可能会被回收;4.销毁状态:从返回栈中移除,系统会回收该部分。

Activity生存期——七个回调方法

(1)onCreate:create表示创建,这是Activity生命周期的第一个方法,也是我们在android开发中接触的最多的生命周期方法。它本身的作用是进行Activity的一些初始化工作,比如使用setContentView加载布局,对一些控件和变量进行初始化等。但也有很多人将很多与初始化无关的代码放在这,其实这是不规范的。此时Activity还在后台,不可见。所以动画不应该在这里初始化,因为看不到……

(2)onStart:start表示启动,这是Activity生命周期的第二个方法。此时Activity已经可见了,但是还没出现在前台,我们还看不到,无法与Activity交互。其实将Activity的初始化工作放在这也没有什么问题,放在onCreate中是由于官方推荐的以及我们开发的习惯。

(3)onResume:resume表示继续、重新开始,这名字和它的职责也相同。此时Activity经过前两个阶段的初始化已经蓄势待发。Activity在这个阶段已经出现在前台并且可见了。这个阶段可以打开独占设备

(4)onPause:pause表示暂停,当Activity要跳到另一个Activity或应用正常退出时都会执行这个方法。此时Activity在前台并可见,我们可以进行一些轻量级的存储数据和去初始化的工作,不能太耗时,因为在跳转Activity时只有当一个Activity执行完了onPause方法后另一个Activity才会启动,而且android中指定如果onPause在500ms即0.5秒内没有执行完毕的话就会强制关闭Activity。从生命周期图中发现可以在这快速重启,但这种情况其实很罕见,比如用户切到下一个Activity的途中按back键快速得切回来。

(5)onStop:stop表示停止,此时Activity已经不可见了,但是Activity对象还在内存中,没有被销毁。这个阶段的主要工作也是做一些资源的回收工作。

(6)onDestroy:destroy表示毁灭,这个阶段Activity被销毁,不可见,我们可以将还没释放的资源释放,以及进行一些回收工作。

(7)onRestart:restart表示重新开始,Activity在这时可见,当用户按Home键切换到桌面后又切回来或者从后一个Activity切回前一个Activity就会触发这个方法。这里一般不做什么操作。

Activity被回收了怎么办?

    考虑一个问题,Activity进入停止状态是有可能被回收的,假设可能被回收的Activity有用户输入的文字之类的,系统回收之后没了,很影响用户体验,在这里我们使用onSavedInstance方法来保证Activity被回收之前一定会被调用。onSavedInstance方法携带一个Bundle类型的数据,Bundle提供了保存数据的一系列方法,putString保存字符串,putInt保存整数,这方法有两个参数:键和内容。
    override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {super.onSaveInstanceState(outState, outPersistentState)val tempData = "Something u just typed"outState?.putString("data_key", tempData)
}
    onCreate方法中调用、恢复:
        if (savedInstanceState != null) {val tempData = savedInstanceState.getString("data_key")Log.d(tag, tempData)}
   举一反三:(1)Intent也可以结合Bundle一起传递数据。Bundle对象置于intent当中进行传递;(2)横竖屏旋转也使得Activity经历重建过程,可以通过onSavedInstance保存数据,当然也有更优的方法。

2.5 活动的启动模式

Standard 模式 : standard 模式是android 的默认启动模式,在这种模式下,activity可以有多个实例,每次启动Activity,无论任务栈中是否已经存在这个activity的实例,系统都会创建一个新的activity实例。

SingleTop 模式:栈顶模式,当一个singleTop模式的activity 已经位于栈顶时,再去启动它时,不在创建实例,如果不在栈顶,就会创建实例。

SingleTask 模式 :单任务模式,如果启动的activity 已经存在于 任务栈中,则会将activity移动到栈顶,并将上面的activity出栈,否则创建新的实例

SingleInstance 模式 :单实例模式,一个activity 一个栈。

/   总结   /

本文主要讲了android四大组件中活动的使用方法,它将在今后的app开发中经常被使用到,后面还会介绍另外三个组件,敬请期待。

往期推荐:

如何入门做软件开发

为什么我不推荐入行程序员

做全栈开发很难吗

关注我的公众号,学习技术或投稿

长按上图,识别图中二维码即可关注

从0到1学android:四大组件—活动Activity相关推荐

  1. Android四大组件之——Activity的生命周期(图文详解)

        转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:JohnTsai.Work@gmail.com       [Andro ...

  2. Android四大组件之Activity(第一篇-简单使用)

    Android四大组件之Activity(第一篇-简单使用) 前言 一.Activity是什么? 二.如何使用 1.继承 2.重写onCreate() 总结 文章目录 前言 一.Activity是什么 ...

  3. 重温Android四大组件(一)—Activity的生命周期

    前言 四大组件对于Android开发者是老生常谈的知识了,相信每个Android开发者对四大组件都已经很熟悉了.但是四大组件作为Android应用的基础,作为开发者不仅要熟悉而且要烂熟于心. 这里以& ...

  4. 第六课-Android四大组件之Activity

    Activity是Android四大组件之一,它是个控制类,主要控制界面的加载显示,用户交互处理,数据的获取,数据的传送等.在它的onCreate方法中的setContentView方法就是来加载一个 ...

  5. Android四大组件之——Activity(一)定义、状态和后退栈(图文详解)

    什么是Activity 关键字:应用组件.四大组件.用户界面,交互. An Activity is an application component that provides a screen wi ...

  6. 【Android 四大组件之Activity】一文吃透Activity 生命周期

    作者:半身风雪 简介:在Android组件中最基本也是最为常见的四大组件: Activity Service服务 Content Provider内容提供者 BroadcastReceiver广播接收 ...

  7. Android 四大组件之 Activity

    什么是 Activity? Activity 是 Android 的四大组件之一,是用户操作的可视化界面,它为用户提供了一个完成操作指令的窗口. 当我们创建完 Activity 之后,需要调用 set ...

  8. android四大组件之Activity(三)

    这是一篇关于android开发四大组件Activity部分的笔记之一,其中主要介绍Activity的生命周期以及一些实例等内容.这里所用到的开发工具是Android4.1. 目录 14.Activit ...

  9. android 4大组件相互启动,Android四大组件之Activity

    1.感性的认知Activity Activity是安卓的四大组件之一,它就像是一个容器,容器当中装了很多的Android布局,这些布局可以直接写在Activity所引用的xml布局文件当中,也可以通过 ...

最新文章

  1. 学习编程能够从事哪些行业?
  2. 一文了解动态场景中的SLAM的研究现状
  3. EasyUI datagrid动态加载json数据
  4. 常用的正则表达式(持续更新。。)
  5. RabbitMQ之比较好的资料
  6. Thinkpad上安装Ubuntu相关事项
  7. Java:关于main方法的10道面试题
  8. struts2 mysql配置文件路径_Struts2(四)Struts2配置文件的配置
  9. Python验证码识别初探(tesserocr库)
  10. linux 常用到的命令(centos 6.5)
  11. 恢复删除了数据文件的表MyISAM
  12. 【PDF下载】大数据峰会之地产大数据趋势与应用实践
  13. 设计师们必须要知道的素材网站
  14. DUTOJ-1205: 对圣杯宝具的威力值
  15. Chrome浏览器各版本对应的驱动
  16. 基于微信小程序房屋出租民宿预定app设计
  17. 云计算实验4 面向行业背景的大数据分析与处理综合实验
  18. .net基础学java系列(五)慢性自杀 之 沉沦在IDE中
  19. 【微信小程序源码】独立版云贝餐饮连锁V2_2.3.9源码线传小程序,新增堂食订单,支付打印新增下单时间显示
  20. matlab画一个正弦函数y=sin(x)(全网最简便,没有之一)

热门文章

  1. 私有网盘部署-Cloudreve网盘
  2. 什么是配置iptv服务器信息,请配置iptv服务器信息
  3. Web阶段八:Ajax
  4. Kubelet组件解析
  5. webm视频怎么转换成mp4格式?
  6. 海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子平均分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分为五份,又多了一个,它同样把多的一个扔入海......
  7. 2021-06-24Leetcode240.二维数组中的查找
  8. 《精力管理》与《意念力》
  9. 关于Pandas replace 函数的使用
  10. 四川计算机专业三本大学排名,四川三本大学排名及分数线2021【文科 理科】