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文件,其内容为:

package com.example.activitytest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }
}

项目中的任何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文件内容为:

<?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">

</LinearLayout>

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

<?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>

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

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

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

package com.example.activitytest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

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

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

在AndroidManifest文件中注册

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ActivityTest">
        <activity
            android:name=".FirstActivity"
            android:exported="true" />
    </application>

</manifest>

 从上面文件内容可以看出,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标签内部添加以下内容:

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

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

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ActivityTest">
        <activity
            android:name=".FirstActivity"
            android:label="This is FirstActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            </activity>
    </application>

</manifest>

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

此时运行程序的结果为:

在Activity中使用Toast

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

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

package com.example.activitytest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)
        val button1: Button = findViewById<Button>(R.id.button1)
        button1.setOnClickListener {
            Toast.makeText(this, "You clicked Button 1.", Toast.LENGTH_SHORT).show()
        }
    }
}

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

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

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

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

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

同时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文件中添加该插件:

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
}

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

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

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

package com.example.activitytest

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import kotlinx.android.synthetic.main.first_layout.*

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)
//        val button1: Button = findViewById<Button>(R.id.button1)
        button1.setOnClickListener {
            Toast.makeText(this, "You clicked Button 1.", Toast.LENGTH_SHORT).show()
        }
    }
}

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

在Activity中使用Menu

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

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

<?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:用于给菜单指定一个名称

然后在FirstActivity中重写onCreateOptionsMenu方法:

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

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

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


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

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

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        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
    }

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

上述代码运行的结果为:

 销毁一个Activity

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

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

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

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

猜你喜欢

转载自blog.csdn.net/SAKURASANN/article/details/126806992