安卓开发(3)—1— Activity

安卓开发(3)—1— Activity

3.1 Activity是什么:

在前面安卓概述中有提到,Activity是Android开发中的四大组件,所有在app里可以看到的东西都是Activity里面的,Activity主要是用来和用户直接进行交互的。

3.2 Activity的基本用法

最开始创建的HelloAndroid采用的是IDE自带的MainActivy,这次直接创建一个什么都没有的Android项目来方便学习:

安卓开发(3)—1— Activity

 

 

其它的配置参考:https://www.cnblogs.com/Sna1lGo/p/14823681.html 该博客。

3.2.1 手动创建Activity

采用了Empty Activity创建项目后,app/src/main/java/包名/ 文件夹是空的目录:

安卓开发(3)—1— Activity

 

 

所有就需要我们手动来添加Activity组件,右键包名,新建一个Empty Activity:

安卓开发(3)—1— Activity

 

 

勾选Generate Layout File会自动为该Activity创建一个对应的布局文件。勾选Launcher Activity表示会为项目开启向下兼容旧版系统的模式,这个需要勾上不然兼容不了。这里为了学习,所以就不勾选Generate a Layout File ,自己手动创建布局文件。

安卓开发(3)—1— Activity

 

 

在Android的项目中任何一个Activity文件都应该重写 onCreate函数,默认创建生成的onCreate函数很简单,就是调用了父类的onCreate函数而已。

 

3.2.2 创建和加载布局文件

Android程序讲究的是逻辑和视图分离,最好每一个Activity都有一个布局文件对应,布局文件就是资源文件里面用来显示内容的文件。

手动创建一个布局文件:右键app/src/main/res目录 选择New然后选择目录,先创建一个名叫layout的目录,然后再右键layout目录,创建一个layout xml File文件,将其按下图配置:

安卓开发(3)—1— Activity

 

 

该layout文件可以查看多种格式,Code就是XML源代码模式,Split就是xml和可视化模式一样一半,Design就是可视化设计模式。

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

现在通过XML代码模式添加一个Button控件给布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  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>

安卓开发(3)—1— Activity

 

 

可以通过旁边的desigh看到预览视角,添加了一个名为Button 1的按钮,接下来讲一下这段xml代码:

    <Button
      android:id="@+id/button1"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Button 1"
      />
     
第一个:android:id="@+id/button1"
  @+id 这种用法比较少见,但是先不看加号 @id/button1不就是xml中引用资源的用法吗,只不过把string换成了id而已。
  这里的@+id就是定义一个id资源的用法,如果要定义一个id资源就需要采用 @+id/id_name这种用法。
 
第二个:android:layout_width="match_parent"
这里指定了布局文件的宽度,match_parent表示和父类的宽度一样。(宽度也就是横着的长度)

第三个:android:layout_height="wrap_content"
指定了布局文件的高度,wrap_content表明和父类的高度一样。(高度也就是竖着的长度)
?
第四个:android:text="Button 1"
指定了布局文件的文字内容。

Activity文件创建了,layout资源布局文件也创建了,接下来要做的就是把Activity和layout布局文件结合在一起:

安卓开发(3)—1— Activity

 

 

        setContentView(R.layout.first_layout)
      这里调用了一个setContentView函数,来给该Activity加载一个布局文件,而setContentView一般的调用是给它传一个布局文件的id。
      其中安卓(1)里面讲了在Android项目中调用资源的方式:
      可以看到这里定义了一个应用程序名字的字符串,有两种方式可以拿来引用它:
?
1:在代码里面通过R.string.app_name可以获得该字符串的引用
?
2:在X M L中通过 @string/app_name可以获得该字符串的引用
?
其中的string部分是可以替换的,如果用的是图片资源就可以替换成drawable,如果是应用图标就可以替换成mipmap,布局文件就可以替换成layout
这里因为我们在res资源文件中有定义layout下的first_layout文件,所以就可以直接调用了。

3.2.3 在AndroidManifest文件中注册

所有的Activity组件都需要在AndroidMainifest文件中注册才能生效,实际上这里通过前面的流程,FirstActivity已经被注册了:

安卓开发(3)—1— Activity

 

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.helloworld3">
?
  <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.HelloWorld3">
      <activity android:name=".FirstActivity"></activity>
  </application>
?
</manifest>

当自动创建组件的时候Android Studio就会自动添加AndroidManifest.xml文件,来防止程序允许崩溃,也是AS的一种人性化。

<activity>标签中,使用了android:name来指定具体注册哪一个Activity,那么这里的.FirstActivity是什么呢,其实就是com.example.helloworld3.FirstActivity的缩写,就是com.example.hellworld3这个项目下的包名的Activity组件的名字:

安卓开发(3)—1— Activity

 

 

其实这也是因为在该AndroidManifest.xml文件中前面的包(package)指定了是com.example.helloworld3,所以后面才可以这样写。

这样注册了Activity后还不行,因为还需要指定主Activity,就好比在C语言中指定main函数一样。要指定主Activity直接在AndroidMainifest中的<activity>标签中添加<intent-filter>标签就好了,并在该intent-filter标签中添加两行代码:<action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER" /> 就好了。还可以添加android:label来指定Activity标题栏中的内容。需要注意的是,给主Activity指定label不仅会成为标题栏中的内容,还会成为启动器(launcher)中应用程序显示的内容。

修改后的AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.helloworld3">
?
  <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.HelloWorld3">
      <activity android:name=".FirstActivity"
          android:label="This is FirstActivity">
          <intent-filter>
              <action android:name="android.intent.action.MAIN"/>
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
?
?
      </activity>
  </application>
?
</manifest>

这样该Activity就是这个程序的主Activity,点击打开APP时就是首先打开该Activity就和main函数一样,启动C程序首先启动main函数。

这样就实现了一个简单的Activity了:

安卓开发(3)—1— Activity

 

 

 

总结如何创建Activity

Android项目讲究的是将逻辑和视图分离,所以要创建一个Activity不仅需要添加代码逻辑,还需要添加布局资源文,在 app/src/main/java/包名 目录下新建Activity代码逻辑,然后再在layout中添加Activity布局资源,最后再再AndroidManifest中检查是否有注册该Activity(一般都会自动注册)。要使用布局文件的什么内容就在在 app/src/main/java/包名 目录下新建Activity代码逻辑中使用,要让Activity展示什么内容就在Activity的资源布局文件的XML中修改。

3.2.4 在Activity中使用Toast

 

Toast是Android提供的一种提醒方式,用来在程序中给用户通知,在一段时间后会自动消失,且不会占用屏幕任何资源。

要创建Toast,首先需要定义一个弹出Toast的触发点,正好我们刚刚设计的Activity有一个button按钮,就让这个按钮的点击事件作为弹出Toast的出发点。在该Activity的onCreate中添加以下代码:

var button1: Button = findViewById(R.id.button1)
button1.setOnClickListener {
Toast.makeText(this,"You clicked Button 1",Toast.LENGTH_SHORT).show()
  }
安卓开发(3)—1— Activity

 

 

var button1: Button = findViewById(R.id.button1)
//通过findViewById该API函数来获取在布局文件中定义的元素
//这里通过前面在定义布局文件中定义的ID来引入获取得布局文件中的按钮的实例 button1就是对应的button实例
//findViewById函数返回的是一个继承自View的泛型对象,所以kotlin没有办法自动推导它是Button还是其它控件
//所以需要显示地将button1这个变量声明称Button类型。
    button1.setOnClickListener {
Toast.makeText(this,"You clicked Button 1",Toast.LENGTH_SHORT).show()
  }
//调用setOnClickListener()方法给这个button按钮注册一个监听器,当被OnClick(被点击)的时候就会启动
//该监听器中使用了Toast.makeText()函数,Toast刚刚介绍过了,就是在APP中弹出内容的一个类
//然后该makeText()函数就是给该Toast修改内容,然后.show()函数,就是展示该Toast
//makeText()中有三个参数,第一个参数要传的内容是一个context,由于Activity本身也是一个Context对象
//这里可以直接将该Activity传进去,第二个参数是Toast显示的文本内容,第三个参数是Toast显示的时长
//第三个参数有两个宏定义可以选:Toast.LENGTH_SHORT和Toast.LENGTH_LONG

3.2.5 在Activity中使用Menu

菜单这个内容也是一个很常见的内容。

首先在res目录下新建一个menu文件夹,来存放菜单资源。接着创建一个名为main的Menu源代码文件:

安卓开发(3)—1— Activity

 

 

然后在该新建的main.xml菜单源文件中添加以下代码:

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

安卓开发(3)—1— Activity

 

 

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

然后,还需要在Activity中重写onCreateOptionsMenu()该函数,因为该函数涉及菜单和Activity的联系:

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

安卓开发(3)—1— Activity

 

 

在讲解这段代码的时候,需要先讲解一个关于Kotlin语法糖的知识。Java Bean是一个很简单的类:

public class Book
{
private int pages;

public int getPages()
{
return pages;
}
public void setPages(int pages)
{
this.pages = pages
}
}

在Kotlin中调用该语法结构的Java代码时有一种非常简便的办法:

val book = Book()
book.pages = 500
val bookpage = book.pages

看起来是在瞎JB写,但是其实它是在后面自动调用了Book类的getPages和setPages函数。

这样类比到刚刚的Menu代码里面:

 menuInflater.inflate(R.menu.main,menu)
//这里实际上就是调用了getMenuInflater()方法得到了menuInflater对象,再调用它的inflate方法
//inflate方法有两个参数:第一个参数表明通过哪一个Menu资源文件来创建菜单
//第二个参数用来指定菜单项添加到哪一个Menu对象中,这里使用该Activity中重写的onCreateOptionsMenu
//传入的menu参数,表示添加到该Activity默认的菜单中
//如果该函数返回的是true表明会将新建的菜单显示出来
//如果返回的是false表明不会将新建的菜单显示出来

当然光显示出来是不够的,还需要给菜单添加响应,这样才可以完美配合。在Activity中重写onOptionsItemSelected()方法:

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

安卓开发(3)—1— Activity

 

 

这样生成的APP右上角就会有一个三个点的按钮,这个按钮就是菜单按钮,点开就是我们写的Add和Remove内容,单机菜单的内容,会弹出Toast消息。

安卓开发(3)—1— Activity

 

 

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

这段代码,通过区分item的itemId来分辨是选择了菜单的哪一个选项,ItemId是前面在res资源文件中的menu中定义的菜单资源,然后就通过Toast来达到响应的提示内容。

3.2.6 销毁一个Activity

前面讲述了手动创建Activity,现在要学习怎么销毁一个Activity,调用一个内置的API,finish()就好了。

这里我们把button按键响应的按钮监听器代码改一下,调用一下一个API就好了:

安卓开发(3)—1— Activity

 

 

这样再单击button1这个按钮,就会自动销毁Activity。

3.2.0 总结

Android项目讲究的是逻辑和视图分离,代码逻辑主要是在Activity中,视图则是在res资源中,通过在res资源中定义的一些标识符,可以直接在代码逻辑中使用来一一对应确定。

3.3 使用intent在Activity之间穿梭

一个完整的Android项目是会在多个Activity之间交换,这一节就是分析如何切换Activity。

3.3.1 使用显示Intent

新建一个Activity文件,这次勾选上Generate Layout File,自动配置布局文件,但不要勾选:

安卓开发(3)—1— Activity

 

 

AS会自动帮我们生成一些必要文件:

安卓开发(3)—1— Activity

 

 

 

只不过自动生成的layout文件有点看不懂:

安卓开发(3)—1— Activity

 

 

将其替换为和第一个自己手动建立的Activity源代码类似的框架:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
?
  <Button
      android:id="@+id/button2"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Button 2"
      />
</LinearLayout>

安卓开发(3)—1— Activity

 

 

该代码还是定义了一个Button按钮,只不过这次改名为Button2了,Activity的代码也自动帮我们生成了,暂时也不用改吧,然后还有创建Activity的最后一步,就是在AndroidManifest文件中注册该Activity(通常AS会自动帮忙注册:安卓开发(3)—1— Activity

 

 

这样一个新的Activity就创建完成了,其实还是挺简单的,按照流程来就好了。

这个新建的Activity并不是一个主Activity所以也没有必要添加intent-filter标签来修饰,那么如何来启动这个Activity呢,就要用到Android里面的一个新的概念:Intent

Intent:是Android中的各种组件之间进行交互的一种重要方式,不仅可以用来指明动作,还可以用来传递数据。Intent一般用来启动Activity,启动Service以及发送广播等场景(这里先专注于启动Activity)。

Intent一般分为两种:显示Intent和隐式Intent。

先分析显示Intent:Intent有多个钩子函数的重载,其中一个是Intent(Context packageContext,Class<?>cls),第一个参数Context要求提供一个启动Activity的上下文,第二个参数class用于指定想要启动的目标Activity,通过这个构造函数就可以构建出Intent,那么如何启动这个intent呢,Activity类中提供了一个startActivity()方法专门用来启动Activity,它接受一个Intent参数,这里将构建好的intent传入到startActivity()函数中,就可以启动目标Activity了。

安卓开发(3)—1— Activity

 

 

//修改FirstActivity中的button点击事件来实现:
      var button1: Button = findViewById(R.id.button1)
      button1.setOnClickListener {
          val intent = Intent(this,SecondActivity::class.java)
          startActivity(intent)
      }
//这里首先新建了一个Intent对象,第一个参数传入this,也就是把FirstActivity作为上下文
//第二个参数传入了SecondActivity::class.java作为启动目标的activity
//在Kotlin中的SecondActivity::class.java就和java里面的SecondActivity.class的写法一样
//接下来再通过这个startActivity()来执行这个Intent就好了。

总结:建立一个intent来指定下一个Activity,然后再通过API调用Intent就可以跳转到下一个Activity。

3.3.2 隐式调用Intent

隐式调用比显示调用要麻烦很多,采用一些列的action和category等信息来调用,然后由系统去分析这个Intent,并找出合适的Activity来启动,系统会自动找出可以响应该隐士Intent的Activity来调用,通过在<active>标签下配置<intent-filter>的内容,可以指定当前的Activity能够响应的action和category:

安卓开发(3)—1— Activity

 

 

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

在这个<action>标签中我们指明了当前Activity中可以响应com.example.activitytest.ACTION_START这个action,而<category>这个标签中则附加了一些附加信息,更精确地指明了当前Activity能够响应的Intent中还可能带有的category,只有action和category中的内容同时匹配Intent中的内容时,这个Activity才能响应该Intent。

修改FirstActivity中按钮的点击事件:

安卓开发(3)—1— Activity

 

 

        var button1: Button = findViewById(R.id.button1)
      button1.setOnClickListener {
          val intent = Intent("com.example.activitytest.ACTION_START")
          startActivity(intent)
      }

这里使用了Intent的另一个构造函数,直接将action传了进来,而category有一个默认值:android.intent.category.DEFAULT,所以这里就可以不用传参了。每一个Intent中只能指定一个action,但能指定多个category,当这个Intent触发时,随之绑定的都会触发。

3.3.3 更多的隐式调用Intent用法

使用隐式Intent不仅可以启动自己程序内的Activity,还可以启动其它程序的Activity。

修改FirstActivity中按钮点击事件的代码:

        var button1: Button = findViewById(R.id.button1)
      button1.setOnClickListener {
          val intent = Intent(Intent.ACTION_VIEW)
          intent.data = Uri.parse("https://www.baidu.com")
          startActivity(intent)
      }

这里指定了Intent的action是Intent.ACTION_VIEW这是android系统内置的动作,它的常量值为android.intent.action.VIEW,然后通过Uri.parse()函数,将一个网址解析为uri对象,再调用intent的setData()函数将这个uri对象传递进去。最后的内置API:startActivity函数就是直接调用了这个intent对应的Activity。

这样再单击按钮button1就会直接进入系统内置的浏览器并且访问前面输入的url网站了。

还可以在AndroidManifest文件中的<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前Activity能够响应的数据。

<data>可以配置一下数据:只有当<data>标签中指定的内容和Intent中携带的Data内容完全一致时,才能响应对应的Intent。

 

   
android:scheme 用于指定数据的协议部分,就好比前面的url的https这一部分
android:host 用于指定数据的主机名部分:好比前面那个的www.baidu.com
android:port 用于指定数据的端口部分,一般紧随在主机名后面
android:path 用于指定域名后面的部分
android:mimeType 用于指定可以处理的数据类型,允许使用通配符的方式来指定。

比如前面的响应浏览器访问百度,如果把android:scheme指定为https那么就只能响应https协议的Intent了。

例如:这里我们新建一个Activity来响应网页的intent。

1 新建一个Activity叫ThirdActivity,再新建一个layout布局文件叫third_layout :

安卓开发(3)—1— Activity

 

 

然后修改third_laytout文件内容为以下代码:

<?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/button3"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="button3"
      />
</LinearLayout>

ThirdActivity的代码可以不用更改,最后再在AndroidManifest.xml中修改ThirdActivty的注册信息:

安卓开发(3)—1— Activity

 

 

代码讲解

这里首先用 action和category指定了intent的调用响应值,然后<data android:scheme中指定了响应的协议必须是https协议。

安卓开发(3)—1— Activity

 

 

这样再启用后就会有选择了,是使用普通的chrome还是使用只能有https。

3.3.4 向下一个Activity传递数据

使用Intent启动Activity的时候还可以传递数据。

Intent中提供了一系列的putExtra()函数的重载,可以把想要传递的数据暂存在Intent中,然后在启动另一个Activity后,只需要将其从Intent数据中取出就可以了。

比如说:在FirstActivity中有一个字符串想传递给ThirdActivity中就可以这样写:

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

这段代码采用的显示传递intent,然后通过putExtra()来传递字符串,putExtra的第一个参数是健用于之后从Intent中取值,第二个参数才是真正要传递的数据。

然后再在ThirdActivity中将传递的数据取出来打印,代码如下:

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

 

安卓开发(3)—1— Activity

 

安卓开发(3)—1— Activity

上一篇:ubuntu20.04下firefox浏览器不能播放视频的解决方法


下一篇:Photoshop cs5仿制图章精确修改图片