• Android开发基础——Activity基本用法


    什么是Activity

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

    一个应用程序中可以包含零个或多个Activity,但不包含任何Activity的应用程序则很少。

    Activity的基本用法

    手动创建Activity

    这里选择No Activity创建一个新的项目,并将项目命名为ActivityTest,此时会发现app\src\main\java\com\example\activitytest目录是空的,然后在该包下新建Empty Activity,并将之命名为FirstActivity,并不勾选Generate Layout File和Launcher Activity两个选项,即:

     上面两个选项的作用为:

    • Generate Layout File:勾选表示会自动为FirstActivity创建一个对应的布局文件
    • Launcher Activity:勾选表示会自动将FirstActivity设置为当前项目的主Activity

    此时Android Studio会自动生成FirstActivity.kt文件,其内容为:

    1. package com.example.activitytest
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. class FirstActivity : AppCompatActivity() {
    5. override fun onCreate(savedInstanceState: Bundle?) {
    6. super.onCreate(savedInstanceState)
    7. }
    8. }

    项目中的任何Activity都应该重写onCreate方法,不过上面的onCreate是自动生成的,可以看到上面自动生成的onCreate方法很简单,就是调用父类的onCreate方法。

    创建和加载布局

    之前提到,Android程序设计讲究逻辑和视图分离,最好每一个Activity都能够对应一个布局。

    而布局则是用来显示界面内容的,这里手动创建一个布局文件。

    在app\src\main\res下新建一个目录,命名为layout,然后在layout下新建一个Layout resource file,命名为first_layout,根元素默认选择LinearLayout

     然后便会出现下面的界面:

     上图的右上角有Design,Code和Split的选项卡:

    • Design:表示当前的可视化布局编辑器,此时不仅可以预览当前的布局,还可以通过拖放的方式编辑布局
    • Code:则可以通过XML文件方式编辑布局
    • Split:则可以同时显示两者

    其XML文件内容为:

    1. "1.0" encoding="utf-8"?>
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. android:orientation="vertical"
    4. android:layout_width="match_parent"
    5. android:layout_height="match_parent">
    6. LinearLayout>

    之前在创建布局文件时选择了LinearLayout 作为根元素,因此现在布局文件中便存在一个LinearLayout元素。此时添加一个按钮:

    1. "1.0" encoding="utf-8"?>
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. android:orientation="vertical"
    4. android:layout_width="match_parent"
    5. android:layout_height="match_parent">
    6. <Button
    7. android:id="@+id/button1"
    8. android:layout_width="match_parent"
    9. android:layout_height="wrap_content"
    10. android:text="Button 1"
    11. />
    12. LinearLayout>

    上面添加了一个Button元素,并在Button元素内部增加了几个属性:

    • android:id:是给当前元素定义一个唯一的标识符,之后可以在代码中对该元素进行操作,这正是之前提到的XML文件引用资源的用法,不过多一个+表示定义一个id
    • android:layout_width:指定了当前元素的宽度,match_parent表示和父元素一样宽
    • android:layout_height:指定了当前元素的高度,wrap_content表示当前元素的高度只要能刚好包含里面的内容就可以
    • android:text:指定了元素中显示的文字内容

    从预览中可以看出,该按钮已经添加成功,然后在Activity中加载该布局:

    1. package com.example.activitytest
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. class FirstActivity : AppCompatActivity() {
    5. override fun onCreate(savedInstanceState: Bundle?) {
    6. super.onCreate(savedInstanceState)
    7. setContentView(R.layout.first_layout)
    8. }
    9. }

     可以看到,这里调用了setContentView方法来给当前的Activity加载一个布局,而在该方法中一般需要传入一个id。之前提到,项目中添加的任何资源都会在R文件中生成一个相应的资源id,这里传入的就是first_layout的id。

    在AndroidManifest文件中注册

    之前提到,所有的Activity都要在AndroidManifest.xml中注册才能够生效。实际上FirstActivity已经在AndroidManifest中注册过了:

    1. "1.0" encoding="utf-8"?>
    2. "http://schemas.android.com/apk/res/android"
    3. package="com.example.activitytest">
    4. android:allowBackup="true"
    5. android:icon="@mipmap/ic_launcher"
    6. android:label="@string/app_name"
    7. android:roundIcon="@mipmap/ic_launcher_round"
    8. android:supportsRtl="true"
    9. android:theme="@style/Theme.ActivityTest">
    10. android:name=".FirstActivity"
    11. android:exported="true" />

     从上面文件内容可以看出,Activity的注册声明位于application标签内,这里是通过activity标签来对Activity进行注册的,不过注册过程是Android Studio自动完成的。

    而在activity标签中:

    • android:name:指定了具体注册哪一个Activity,这里的.FirstActivity是com.example.activitytest.FirstActivity的缩写,由于在最外层的manifest标签中已经通过package属性指定了程序的包名com.example.activitytest,因此在注册Acitvity时,这一部分可以省略,直接使用.FirstActivity

    不过上面只是注册了Activity,程序仍然不能运行,因为还没有为程序配置主Activity,即程序运行起来的时候,不知道要先启动哪个Activity。而配置主Activity的方法就是在activity标签内部添加以下内容:

    1. <intent-filter>
    2. <action android:name="android.intent.action.MAIN" />
    3. <category android:name="android.intent.category.LAUNCHER" />
    4. intent-filter>

    此外,还可以使用android:label指定Activity中标题栏的内容,标题栏是显示在Activity最顶部的。同时给主Activity指定的label不仅会生成标题栏中的内容,还会称为启动器(Launcher)中应用程序显示的名称。

    1. "1.0" encoding="utf-8"?>
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    3. package="com.example.activitytest">
    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/Theme.ActivityTest">
    11. <activity
    12. android:name=".FirstActivity"
    13. android:label="This is FirstActivity"
    14. android:exported="true">
    15. <intent-filter>
    16. <action android:name="android.intent.action.MAIN" />
    17. <category android:name="android.intent.category.LAUNCHER" />
    18. intent-filter>
    19. activity>
    20. application>
    21. manifest>

    此时,FirstActivity就称为该程序的主Activity了,点击桌面应用程序图标时首先打开的就是该Activity。不过,如果应用程序中没有声明任何一个Activity作为主Activity,该程序仍然是可以正常安装的,只是无法在启动器中看到或者打开该程序,此类程序一般是作为第三方服务供其它应用在内部进行调用的。

    此时运行程序的结果为:

    在Activity中使用Toast

    Toast是Android系统提供的一种很好的提醒方式,在程序中可以使用Toast将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间。

    首先需要定义一个弹出Toast的触发点,之前定义了一个按钮,这里可以使用该按钮的点击事件作为弹出Toast的触发点。此时需要在onCreate方法中添加代码:

    1. package com.example.activitytest
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. import android.widget.Button
    5. import android.widget.Toast
    6. class FirstActivity : AppCompatActivity() {
    7. override fun onCreate(savedInstanceState: Bundle?) {
    8. super.onCreate(savedInstanceState)
    9. setContentView(R.layout.first_layout)
    10. val button1: Button = findViewById
    11. button1.setOnClickListener {
    12. Toast.makeText(this, "You clicked Button 1.", Toast.LENGTH_SHORT).show()
    13. }
    14. }
    15. }

     此时运行程序,并点击BUTTON 1的结果为:

     在Activity中,通过findViewById方法获取在布局文件中定义的元素,这里传入R.id.button1获取之前定义的按钮的实例。而findViewById方法返回的是一个继承自View的泛型对象,因此Kotlin无法自动推导出其是Button还是其它控件,因此需要将button1变量显式地声明为Button类型。

    得到按钮的实例之后,通过setOnClickListener方法为按钮注册一个监听器,点击按钮时就会指定监听器中的onClick方法,因此弹出Toast的功能是在onClick方法中编写的。

    Toast通过静态方法makeText创建出了一个Toast对象,然后调用show方法将Toast显示出来。

    1. public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
    2. return makeText(context, null, text, duration);
    3. }

    同时makeText方法需要三个参数,第一个参数是Context,是Toast要求的上下文,由于Activity本身就是一个Context对象,因此可以传入this,第二个参数是Toast显示的文本内容,第三个参数是Toast显示的时长,有两个内置常量可以选择:Toast.LENGTH_SHORT和Toast.LENGTH_LONG。

    而关于findViewById,该方法可以获取布局文件中控件的实例,在之前的例子中,只有一个按钮,而如果布局文件中存在多个控件,就需要多次调用findViewById方法,这种写法会很繁琐。

    不过Kotlin中的kotlin-android-extensions插件可以根据布局文件中定义的控件id自动生成一个具有相同名称的变量,而用户可以直接在Activity中使用该变量,而不用调用findViewById方法。只是需要在app下的build.gradle文件中添加该插件:

    1. plugins {
    2. id 'com.android.application'
    3. id 'kotlin-android'
    4. id 'kotlin-android-extensions'
    5. }

     然后在Activity中导入该布局文件:

    import kotlinx.android.synthetic.main.first_layout.*
    

     此时便可以省略掉Button变量的创建,而直接使用该Button的id作为变量名:

    1. package com.example.activitytest
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. import android.widget.Button
    5. import android.widget.Toast
    6. import kotlinx.android.synthetic.main.first_layout.*
    7. class FirstActivity : AppCompatActivity() {
    8. override fun onCreate(savedInstanceState: Bundle?) {
    9. super.onCreate(savedInstanceState)
    10. setContentView(R.layout.first_layout)
    11. // val button1: Button = findViewById
    12. button1.setOnClickListener {
    13. Toast.makeText(this, "You clicked Button 1.", Toast.LENGTH_SHORT).show()
    14. }
    15. }
    16. }

    同时这也是Kotlin中推荐的写法。

    在Activity中使用Menu

    手机的屏幕空间有限,因此需要充分利用屏幕空间进行显示,而如果有大量的菜单需要显示,界面设计就会比较麻烦,而Android则提供了一种方式,可以让菜单都能够得到展示,还不占用屏幕空间。

    在res目录下新建文件夹,并命名为menu,然后在该目录下创建Menu resource file,并命名为main,添加如下代码:

    1. "1.0" encoding="utf-8"?>
    2. <menu xmlns:android="http://schemas.android.com/apk/res/android">
    3. <item
    4. android:id="@+id/add_item"
    5. android:title="Add"/>
    6. <item
    7. android:id="@+id/remove_item"
    8. android:title="Remove"/>
    9. menu>

    上面的代码创建了两个菜单项:

    • item:该标签用来创建具体的某一菜单项
    • android:id:用于给菜单项指定一个唯一的标识符
    • android:title:用于给菜单指定一个名称

    然后在FirstActivity中重写onCreateOptionsMenu方法:

    1. override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    2. menuInflater.inflate(R.menu.main, menu)
    3. return true
    4. }

    这段代码中,menuInflater实际上调用的是父类的getMenuInflater方法,该方法能够得到一个MenuInflater对象,再调用它的inflate方法,就可以给当前Activity创建菜单了。

    而inflate方法接收两个参数,第一个参数用于指定通过哪一个资源文件来创建菜单,这里传入R.menu.main,第二个参数用于指定菜单项要添加到的Menu对象,这里直接使用onCreateOptionsMenu方法中传入的menu参数。最后返回true,表示允许创建的菜单显示,如果返回了false,创建的菜单将无法显示。

    1. /**
    2. * Inflate a menu hierarchy from the specified XML resource. Throws
    3. * {@link InflateException} if there is an error.
    4. *
    5. * @param menuRes Resource ID for an XML layout resource to load (e.g.,
    6. * R.menu.main_activity)
    7. * @param menu The Menu to inflate into. The items and submenus will be
    8. * added to this Menu.
    9. */
    10. public void inflate(@MenuRes int menuRes, Menu menu)

    菜单能够显示后,还要定义菜单响应事件。在FirstActivity中重写onOptionsItemSelected方法:

    1. override fun onOptionsItemSelected(item: MenuItem): Boolean {
    2. when (item.itemId) {
    3. R.id.add_item -> Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show()
    4. R.id.remove_item -> Toast.makeText(this, "You clicked Remove", Toast.LENGTH_SHORT).show()
    5. }
    6. return true
    7. }

     在onOptionsItemSelected方法中,通过调用item.itemId来判断点击的是哪一个菜单项,实际上这里调用的item的getItemId方法,这种简洁写法其实也是Kotlin的语法糖。然后使用when条件语句进行逻辑处理。

    上述代码运行的结果为:

     销毁一个Activity

    之前提到的都是创建Activity,并在Activity中添加内容的操作,而如何销毁Acivity呢?

    其实简单通过back键就可以销毁当前的Activity,而如果不想通过按键的方式,也可以通过代码销毁,即调用finish方法。比如修改一下按钮的触发代码:

    1. button1.setOnClickListener {
    2. // Toast.makeText(this, "You clicked Button 1.", Toast.LENGTH_SHORT).show()
    3. finish()
    4. }

    此时点击按钮,就会退出当前Activity,效果和back键是一样的。

  • 相关阅读:
    Slf4j打印异常的堆栈信息
    【Nginx41】Nginx学习:Stream四层负载均衡浅尝及总结
    git创建本地分支并提交到远程
    打开英雄联盟缺少d3dcompiler_43.dll有哪些处理方法
    使用open as方法对文件进行操作
    SpringBoot —— 整合RabbitMQ常见问题及解决方案
    魔众题库系统 v8.8.0 公式编辑升级,注册站内信和邮件,手机Banner支持视频背景
    VUE综合数据库编程
    uml学习笔记
    用 Jmeter 工具做个小型压力测试
  • 原文地址:https://blog.csdn.net/SAKURASANN/article/details/126806992