Android四大组件之Activity

Android 开发的四大组件分别是:活动(Activity),用于表现功能;服务(Service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),用于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。

定义:Activity是用户操作的可视化界面,它为用户提供了一个完成操作指令的窗口。在Android App 中只要能看见的几乎都要依托于Activity,所以Activity是在开发中使用最频繁的一种组件。

手动创建活动:选择Add No Activity→右击app/src/main/java/com.example.activitytest包→NewActivityEmpty Activity,我们将活动命名为FirstActivity,注意不要勾选Generate Layout FileLauncher Activity这两个选项。

勾选Generate Layout File表示会自动为FirstActivity创建一个对应的布局文件;勾选Launcher Activity表示会自动将FirstActivity设置为当前项目的主活动;勾选Backwards Compatibility表示会为项目启用向下兼容的模式,这个选项要勾上。

项目中的任何活动都应该重写Activity的onCreate()方法,Android Studio已经帮我们写好了。

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

可以看到,onCreate()方法非常简单,就是调用了父类的onCreate()方法。

创建和加载布局:右击app/src/main/res目录→New→Directory,创建一个名为layout的目录,然后对着layout目录右键→New→Layout resource file,将布局命名为first_layout

<?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/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 1"/>

</LinearLayout>

在活动中加载布局

回到FirstActivity,在onCreate()方法中加入如下代码:

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
    }
}

这里调用了setContentView()方法给当前的活动加载一个布局。在setContentView()方法中,我们会传入一个布局文件的id,只需要调用R.layout.first_layout就可。

在AndroidManifest文件中注册:

所有活动都要在AndroidManifest文件中注册才能生效,实际上FirstActivity已经在AndroidManifest.xml注册过了,打开app/src/main/AndroidManifest.xml文件可看到:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.firstactivity">

    <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/AppTheme">
        <activity android:name=".FirstActivity"></activity>
    </application>
</manifest>

可以看到,活动的注册声明要放在<application>标签内,通过<activity>标签来对活动进行注册。由于最外层的<manifest>标签中已经通过package属性指定了程序的包名是com.example.firstactivity,所以我们直接将.FirstActivity填入name即可。

不过,这样只是注册了活动,还没有给程序配置主活动,也就是说,当程序运行起来的时候,不知道要首先开启哪个活动。

配置主活动只需要在<activity>标签内加入内部标签<intent-filter>,在<intent-filter>中加入如下两句即配置完成。我们还可以使用android:label指定活动中标题栏的内容,标题栏是显示在活动最顶部的,给主活动指定的label不仅会成为标题栏的内容,还会成为启动器(Launcher)中应用程序显示的名称。

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

在活动中使用Toast:

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

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.first_layout);
    Button button1 = (Button) findViewById(R.id.button_1);
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
        }
    });
}

在活动中,可以通过findViewById()方法获取到在布局文件中定义的元素,findViewById()方法返回的是一个View对象,我们将它转成Button对象。通过调用setOnClickListener()方法为按钮注册一个监听器,点击按钮时就会执行监听器中的onClick()方法,所以弹出Toast的功能在onClick()方法中编写。

Toast的用法非常简单,使用方法makeText()方法创建一个Toast对象,然后调用show()将Toast显示出来即可。makeText()方法需要传入3个参数:①Context,也就是Toast在哪里弹出,由于活动本身就是一个Context对象,所以直接传入FirstActivity.this即可。②Toast显示的文本内容③Toast显示的时长。

在活动中使用Menu:(android.app.Activity)

在res目录下新建一个menu文件夹,右击res目录→New→Directory,输入文件名menu。接着在这个文件夹下再新建一个名为main的菜单文件,右击menu文件夹→New→Menu resource file。

打开main.xml:

<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="Romove"/>

</menu>

<item>标签就是用来创建具体的某一个菜单项。接着回到FirstActivity中重写onCreateOptionsMenu()方法。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main,menu);
    return true;
}

通过getMenuInflater()方法能够得到MenuInflater对象,再调用它的inflate()方法就可以给当前活动创建菜单了。inflate()方法接收两个参数:①用于指定我们通过哪一个资源文件来创建菜单②用于指定我们的菜单项将添加到哪一个Menu对象当中,可以直接使用onCreateOptionsMenu()方法中传入的menu参数,然后给这个方法返回true,表示允许创建的菜单显示出来。

接着,为了让菜单可以用,我们定义菜单的响应事件。在FirstActivity中重写onOptionsItemSelected()方法。

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()){
        case R.id.add_item:
            Toast.makeText(this,"You clicked Add",Toast.LENGTH_SHORT).show();
            break;
        case R.id.remove_item:
            Toast.makeText(this,"You clicked Remove",Toast.LENGTH_SHORT).show();
            break;
        default:
    }
    return true;
}

通过调用item.getItemId()来判断我们点击的是哪一个菜单项,然后给每个菜单项加入自己的逻辑处理。

package com.example.activitytest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class FirstActivity extends AppCompatActivity {

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(this,"You clicked Add",Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this,"You clicked Remove",Toast.LENGTH_SHORT).show();
                break;
            default:
        }
        return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        Button button1 = (Button) findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 2"/>

</LinearLayout>

使用显式Intent:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.first_layout);
    Button button1 = (Button) findViewById(R.id.button_1);
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
            startActivity(intent);
        }
    });
}

首先,我们构建了一个Intent,传入FirstActivity.this作为上下文,传入SecondActivity.class作为目标活动,接着通过startActivity()方法来执行Intent。

使用隐式Intent:

隐式Intent并不明确指出我们想要启动哪一个活动,而是指定一系列抽象的action和category等信息,然后交由系统去分析。

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

通过在<activity>标签下配置<intent-filter>,指定当前活动能够响应的action和category。

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

button1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent("com.example.activitytest.ACTION_START");
        startActivity(intent);
    }
});

因为android.intent.category.DEFAULT是一种默认的category,在调用startActivity()方法时会自动将其添加到Intent中。

每个Intent中只能指定一个action,但可以指定多个category。

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

public void onClick(View v) {
    Intent intent = new Intent("com.example.activitytest.ACTION_START");
    intent.addCategory("com.example.activitytest.MY_CATEGORY");
    startActivity(intent);
}

可以调用Intent中的addCategory()方法来添加一个category。

更多隐式Intent的用法:

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

public void onClick(View v) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.baidu.com"));
    startActivity(intent);
}

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

新建ThirdActivity

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ThirdActivity">
    <Button
        android:id="@+id/button_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 3"/>

</LinearLayout>
<activity android:name=".ThirdActivity">
    <intent-filter tools:ignore="AppLinkUrlError">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="http"/>
    </intent-filter>
</activity>

<activity android:name=".ThirdActivity">
    <intent-filter >
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="http"/>
    </intent-filter>
</activity>

下面代码展示如何在我们的程序中调用系统拨号界面:

public void onClick(View v) {
    Intent intent = new Intent(Intent.ACTION_DIAL);
    intent.setData(Uri.parse("tel:10086"));
    startActivity(intent);
}

首先指定了Intent的action是Intent.ACTION_DIAL,这也是一个Android系统的内置动作,在data部分指定协议是tel,号码是10086。

向下一个活动传递数据:

在FirstActivity中:

public void onClick(View v) {
    String data = "Hello SecondActivity";
    Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
    intent.putExtra("extra_data",data);//第一个参数是键,用于后面从Intent取值
    startActivity(intent);
}

在SecondActivity中(接收参数):

public class SecondActivity extends android.app.Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity",data);
    }
}

通过getIntent()方法获取到用于启动SecondActivity的Intent,调用getStringExtra()方法,传入相应的键值,即可得到传递的数据。

传递的是整型数据,使用getIntExtra()方法;传递的是布尔型数据,使用getBooleanExtra()方法。

返回数据给上一个活动:

Activity中还有一个startActivityForResult()方法也是用于启动活动的,这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。

在FirstActivity中:

public void onClick(View v) {
    Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
    startActivityForResult(intent,1);//第一个参数是Intent,第二个参数是请求码
}

在SecondActivity中:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.second_layout);
    Button button2 = (Button) findViewById(R.id.button_2);
    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent();
            intent.putExtra("data_return","Hello FirstActivity");
            setResult(RESULT_OK,intent);
            finish();
        }
    });
}

由于我们是使用startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁后会回调上一个活动的onActivityResult()方法,所以我们要在FirstActivity中重写这个方法。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case 1:
            if (resultCode == RESULT_OK){
                String returnedData = data.getStringExtra("data_return");
                Log.d("FirstActivity",returnedData);
            }
            break;
        default:
    }
}

按下Back键回到FirstActivity返回数据:通过重写onBackPressed()中的代码即可。

@Override
public void onBackPressed() {
    Intent intent = new Intent();
    intent.putExtra("data_return","Hello FirstActivity");
    setResult(RESULT_OK,intent);
    finish();
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>