Android第二章(活动)

2.1 活动是什么
活动定义:活动是一种可以包含用户界面的组件,主要用于和用户进行交互,我们在手机软件上的操作界面就是由一个一个活动组成的
2.2 活动基本用法
2.2.1活动的创建
手动创建一个活动
1、新建项目时 ,选择Add No Activity,而不选择Empty Activity,这样子创建出来的项目就没有活动(手动创建活动)
2、创建一个Empty Activity的步骤在这里插入图片描述

Generate ~ ~:表示自动创建一个对应的布局文件
Launcher ~ ~:表示自动将该被创建的活动设置为当前项目的*主活动*

2.2.2创建和加载布局
1、创建布局
在这里插入图片描述
在布局编辑器中:页面的左下角Design是当前可视化布局编辑器;Text则是通过XML文件的方式来编辑布局

2、如何在布局中添加按钮:

<?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"//在Button中,Android:id是给当前的元素定义一个唯一标识符,之后可以在代码中对此元素进行操作
        android:layout_width="match_parent"//“match_parent”表示当前元素的宽度(长度等)与父元素一样宽
        android:layout_height="wrap_content"//”wrap_content”表示当前元素的高度只要能刚好包含里面的内容就行
        android:text="Button 1"//指定文字的内容
        />
</LinearLayout>

3、加载布局
在主活动中的onCreate()方法中调用setContentView方法,此方法括号里引入了刚刚编写的first_layout的布局

public class MainActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);//调用布局的方法,括号内就是被调用的布局文件
    }
}

2.2.3在AndroidManifest文件中注册
1、活动注册的声明都放在application标签下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activityapp">
    <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=".MainActivity"></activity>// android:name来指定具体注册哪一个活动
    </application>
</manifest>

2、将该活动配置成主活动的方法:(次活动都不需要进行如下声明)

<activity android:name=".MainActivity"
			 android:label="This is MainActivity"> //用于指定活动中标题栏的内容,该内容显示在活动中的最顶部
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

2.2.4 在活动中使用Toast
Toast关键字是Android系统提供的一种非常好的提醒方式,可以将一些短小的信息通知给用户,且信息会在一段时间后消失,不会占用任何屏幕空间
如何定义:

@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(MainActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
            }
        });
    }

其中: 1、findViewById(R.id.button_1),传入了R.id.button_1;来得到按钮的实例,其中的button_1是根据first_layout中android:id指定的
2、调用了setOnClickListener(new View.OnClickListener()方法为按钮注册一个监听器,点击按钮就会执行监听器中onClick(View v)方法
3、在onClick(View v)方法中,调用makeText()方法,依次传入Toast要求的上下文(即活动名称),Toast显式的文本内容和Toast显式的时长
2.2.5在活动中使用Menu
Menu菜单一般出现在活动界面的右上角
1、创建一个menu文件
在这里插入图片描述
1、在menu目录下main.xml文件中,这里创建了两个菜单项,其中<item 标签用来创建具体的某一菜单项,id给菜单项指定一个唯一的标识符,title给菜单项命名

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

2、在FirstActivity中,重写 onCreateOptionsMenu(Menu menu)方法, getMenuInflater()方法能够得到MenuInflater对象,inflate()中前者传入指定通过哪一个资源文件来创建菜单,后者指定的菜单项将添加到哪一个Menu对象当中

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

3定义菜单响应事件:
在FirstActivity中,重写 onOptionsItemSelected(@NonNull MenuItem item) 方法,我们通过item.getItemId()方法来判断我们点击的是哪个菜单项,然后给每个菜单项加入自己的逻辑进行处理

   @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;
    }

2.2.6 销毁一个活动
在程序中通过代码来销毁一个活动的方法,修改监听器中的代码,如下所示:

   button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                 finish();
            }
        });

2.3 使用Intent在活动之间穿梭
Intent定义:Intent是Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据 ,它起到一个桥梁作用,使得可以从此活动界面进入到另一个活动界面当中。Intent一般可被用于启动活动、启动服务以及发送广播等场景。它的分类大致可分为两种 :显式Intent 隐式Intent
2.3.1 使用显式Intent:直接创建一个Intent对象并“搭建”两边的“桥头”
先创建一个次要活动:
在这里插入图片描述
Intent中的参数:第一个参数表示提供一个启动活动的上下文,第二个参数表示指定要启动的目标活动
在主活动的类中:

   button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);//启动活动的方法
            }
        });

2.3.2使用隐式Intent:在AndroidManifest.xml文件中配置内容
1、我们在AndroidManifest.xml文件中

 <activity android:name=".SecondActivity">
         <intent-filter>
              <action android:name="com.example.activityapp.ACTION_START"/>//指明当前活动可以相应某包下的主活动
              <category android:name="android.intent.category.DEFAULT"/>//更精准地指明了当前活动能够指明的对象
         </intent-filter>
  </activity>

在MainActivity类中,

    button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                Intent intent = new Intent("com.example.activityapp.ACTION_START");//隐式指明要被调用的活动
                startActivity(intent);
            }
        });

只有action和category中的内容同时能够匹配上时,活动才能够执行
2、每一个Intent中只能制定一个action,但可以指定多个category,在AndroidManifest.xml文件中,如下图:

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

在MainActivity类中,

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

2.3.3 更多的隐式Intent的用法:隐式的Intent除了可以调用自己程序内的活动外,还可以启动其他的活动
1、隐式调用浏览器

   button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));//调用Uri.parse方法,将一个网址字符串解析成一个Uri对象,在调用setData方法这个对象传进去
                startActivity(intent);
            }
        });

在这里插入图片描述
在这里插入图片描述
在AndroidManifest.xml文件中

  <activity android:name=".ThirdActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="http"/>//我们指定数据的协议必须为kttp协议,这样ThirdActivity就可以和浏览器一样,能够响应一个打开网页的Intent
            </intent-filter>
        </activity>

这样,在主活动中,通过"http://www.baidu.com"中的“http”我们就可以响应ThirdActivity

2、隐式调用指定电话号码

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

2.3.4向下一个活动传递数据
Intent中提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂存在Intent当中,启动了另一个活动后,只需要把这些数据再从Intent中取出就可以了
在主活动中,我们显示Intent方式来传参。其中putExtra()方法中的第一个参数是键,用于后面从Intent中取值,第二个参数才是真正传递的数据

    button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                String data = "Hello SecondActivity";
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                intent.putExtra("extra data",data);
                startActivity(intent);
            }
        });

次要活动中,我们通过getIntent()方法获取到实例,然后调用getStringExtra()方法传入相应的键值,就可以得到传递的数据了

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

结果:
在这里插入图片描述2.3.5 返回数据给上一个活动:通过Activity中的startActivityForResult()方法也可以启动活动,但是这个方法期望在活动被销毁时能够返回一个结果给上一个活动
在MainActivity活动中,使用startActivityForResult()方法并传入intent和和请求码1

   button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivityForResult(intent,1);
            }
        });

在Second活动中,给一个按钮注册点击事件

		Button button = (Button)findViewById(R.id.button_2);
        button.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                Intent intent = new Intent();
                intent.putExtra("data_return","Hello MainActivity");//设置键和值
                setResult(RESULT_OK,intent);//该方法专门用于向上一个活动返回数据,它接受的第一个参数用于向上一个活动返回处理结果,一般只有RESULT_OK和RESULT_CANCELED两个值,;第二个参数则把带有数据的Intent传回去
                finish();//销毁当前活动
            }
        });

再回到MainActivity活动中,

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

onActivityResult()方法的第一个参数为传入请求码,第二个参数为传入返回的处理结果,第三个参携带着返回数据的Intent。该方法中我们接收得到的请求码,通过switch比较判断数据的来源。确定之后再判断处理结果是否成功,最后打印信息
结果:
在这里插入图片描述
如果用户在SecondActivity中是通过按下Back键回到FirstActivity,这样数据就不能返回,但是在SecondActivity中重写了onPressed()方法就可以实现数据的返回

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

2.4 活动的生命周期
2.4.1返回栈
Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,此栈就被称为返回栈。每当我们按下Back键或调用finish()方法去销毁一个活动时,处于栈顶的活动就会出栈,此时前一个入栈的活动就会重新处于栈顶的位置
2.4.2活动状态
每个活动在其生命周期中最多可能会有4种状态
1、运行状态:活动位于栈顶时
2、暂停状态:活动不再位于栈顶,但仍然可见,在内存极低的情况下系统才可能会回收
3、停止状态:活动不再处于栈顶,且完全不可见时
4、销毁状态:活动从返回栈中被移除后
2.4.3活动的生存期
Activity类种定义了7个回调方法,覆盖活动生命周期的每一个环节
1、onCreate():在活动第一次被创建时调用,此方法中完成活动的初始化操作,如加载布局、绑定事件等
2、onStart():在活动由不可见变为可见时调用
3、onResume():在活动准备好和用户进行交互时调用,此时活动必位于栈顶,且处于运行状态
4、onPause():在系统准备启去动或恢复另一个活动时调用
5、onStop():在活动完全不可见时调用。与onPause方法不同之处在于如果启动的新活动是一个对话框式的活动,onPause()方法会得到执行,而onStop()方法不会执行
6、onDestroy():在活动被销毁前调用
7、onRestart():在活动由停滞状态变为运行状态之前调用
分类:
1、完整生存期:一个活动在onCreate()完成初始化操作,onDestroy()完成释放内存操作,在这两个方法之间经历的为完整生存期
2、可见生存期:在onStart()和onStop()之间经历的为可见生存期,此生存期内活动对于用户来说总是可见的,可以用于合理地管理对用户可见的资源,在前者方法中对资源加载,后者方法中资源释放
3、前台生存期:在onResume()和onPause()之间经历的为前台生存期,此生存期中活动总是处于运行状态,且活动可以和用户进行交互的在这里插入图片描述
小知识点:
如何设置活动主题?
在AndroidManifest.xml文件中,假定我们现在要将DialogActivity活动设置为对话框式主题,则

<activity android:name = ".DialogActivity"
	android:theme = "@style/Theme.AppCompat.Dialog">
</activity>

2.4.4活动被回收了怎么办
Acitvity类提供了一个onSaveInstanceState()回调方法,可以保证在活动能够被回收之前一定会被调用,因此我们可以通过这个方法来解决活动被回收时临时数据得不到保存的问题
代码如下:

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
    
    
        super.onSaveInstanceState(outState, outPersistentState);
        String tempData = "Something u just typed";
        outState.putString("data_key",tempData);
    }

在onCreate()方法中传入了一个Bundle类型的参数,这个参数一般情况下为null,我们可以利用这个参数判断是否有数据传进来,若有则保存读取数据
在这里插入图片描述
2.5活动的启动模式
启动模式分为四种:standard、singleTop、singleTask、singleInstance,一般在AndroidManifest.xml中通过给<2activity 标签指定android:launchMode属性来选择启动模式
2.5.1 standard
standard是活动默认的启动模式,在不进行显示指定的情况下,所有活动都会自动使用这种启动模式。在standard模式下,每当启动一个新的活动,他就会在返回栈中入栈,并处于栈顶的位置。对于使用该模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例
示例创建的代码:
在这里插入图片描述
我们连续两次点击按钮,可以看到:
在这里插入图片描述
算上初始化一次,点击按钮两次,我们发现每点击一次就会创建一个活动并压入返回栈中
在这里插入图片描述
2.5.2singleTop
当活动的启动模式指定为singleTop时,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它。
该模式可以说是standard的进阶版
修改注册文件中的FirstActivity,加上如下语句
在这里插入图片描述
再重新运行程序,重复前一个模式的操作,我们发现,无论点击多少次,都只有一个活动在这里插入图片描述
但是如果FirstActivity活动不是位于栈顶的时候,此时要是启动FirstActivity活动,还是要重新创建
示例:
我们在FirstActivity中修改:
在这里插入图片描述
SecondActivity中修改:
在这里插入图片描述
我们在FirstActivity点击按钮进入SecondActivity,再在SecondActivity点击回到FirstActivity,我们发现,
系统创建了两个FirstActivity活动实例
在这里插入图片描述
在这里插入图片描述

2.5.3singleTask
当活动的启动模式指定为singleTask时,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例
singleTask为singleTop的进阶版
示例:
首先修改注册文件中的启动模式:
在这里插入图片描述
在FirstActivity中写一个日志信息:
在这里插入图片描述
在SecondActivity中也写一个日志信息:
在这里插入图片描述
在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮,回到FirstActivity得到如下结果
在这里插入图片描述
我们发现,在SecondActivity中点击按钮,由于返回栈中已经有FirstActivity,则SecondActivity会出栈,激活FirstActivity使其回到栈顶,
因此打印onRestart,同时SecondActivity会被销毁,打印onDestroy
在这里插入图片描述
2.5.4 singleIntance
指定为singleIntance模式的活动会启用一个新的返回栈来管理这个活动,可以使其他程序和我们的程序共享这个活动的实例
示例:
首先我们在注册文件中对SecondActivity进行活动的修改:
在这里插入图片描述
然后对FirstActivity、SecondActivity、ThirdActivity分别进行修改
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界面点击按钮进入ThirdActivity,得到如下结果,打印:
在这里插入图片描述
我们发现FirstActivity和ThirdActivity处在同一个返回栈中,SecondActivity处在另一个返回栈中。
当我们按back键时,ThirdActivity会直接返回到FirstActivity,然后再回到SecondActivity在这里插入图片描述
2.6 活动的最佳实践
2.6.1 知晓当前是在哪一个活动
如何知道每个界面对应的是哪个活动
1、创建一个Java class类:让该类继承 AppCompatActivity并重写其中的onCreate()方法
在这里插入图片描述
在这里插入图片描述
打印日志里面的getClass().getSimpleName()获取当前活动的类名
2、让FirstActivity、SecondActivity、ThirdActivity等活动全部继承BaseActivity,运行依次进入FirstActivity、SecondActivity、ThirdActivity等活动,得到如下:
在这里插入图片描述
这样子我们每点击一个活动,就会得到一个打印语句,我们就可以以此得到该界面的活动的类是哪一个类
2.6.2 随时随地退出程序
如何创建一个可以随时随地注销或者退出的功能
我们新建一个ActivityCollector类作为一个专门对所有活动进行管理的类,让它作为活动管理器,代码如下:
在这里插入图片描述
其中我们通过一个List集合来暂存活动,提供一个addActivity()方法用于向List中添加一个活动,removeActivity()方法用于从List中移除活动,提供一个finishAll()方法用于将List中存储的活动全部销毁
在BaseActivity中:
在这里插入图片描述
调用ActivityCollector的addActivity()方法,将当前正在创建的活动添加到活动管理器里,重写onDestroy()方法,调用removeACtivity()方法,表明将一个马上要销毁的活动从活动管理器里移除
此后,不论你想在什么地方退出程序,只要调用ActivityCollector.finishAll()方法即可。
例如,在ThirdActivity界面点击按钮直接退出程序
在这里插入图片描述
2.6.3 启动活动的最佳写法
假设在SecondActivity中需要用到两个非常重要的字符串参数,在启动SecondActivity时必须要从FirstActivity中传过来,我们就可以如下图所示:
在SecondActivity中,修改后的代码如下
在这里插入图片描述
FirstActivity中,
在这里插入图片描述
2.7 小结
1、活动是代码与界面分离的,界面的布置一般是在布局文件中实现的,在活动的主类中加载布局文件
2、活动要在AndroidManifest文件中注册,

<activity android:name=".MainActivity"></activity>

3、将某个活动配置为主活动,需要在AndroidManifest文件中声明

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

4、Toast是一种非常好的提醒方式
5、Menu可以节约活动界面,使得界面更美观
6、使用Intent可以在活动等场景中自由穿梭
7、Intent一般分为显示Intent和隐式Intent
8、可以用隐式Intent调用浏览器等活动
9、利用Intent可以向下一个活动传递数据,同时利用Intent可以向上一个活动返回数据
10、活动是存在一个返回栈中的
11、活动状态可分为运行、暂停、停止和销毁状态
12、活动分为四种启动模式:standard、singleTop、singleTask、singleIntance
13、活动的最佳实践,提供三个方法:知晓当前是在哪一个活动;随时随地的退出程序;启动活动的最佳写法

猜你喜欢

转载自blog.csdn.net/Cristiano_san/article/details/105932769