Android四大组件之广播接收者BroadcastReceiver

news2024/11/24 8:41:31

一、全局广播

Android中的广播可以分为两种类型:标准广播和有序广播
标准广播:一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序。无法进行截断。
有序广播:一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。此时的广播接收器是有先后顺序的,优先级高的广播就可以先收到广播,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息。

1.系统广播

Android内置了许多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到各种系统的状态信息。比如手机开机,电量变化,时间或时区发生变化也会发出一条广播。如果想要接收这些广播,就需要广播接收器。

2.静态注册

1、注册方式:在AndroidManifest里进行注册。
首先在Application节点里头,添加一个receiver节点。name则是我们的广播接收者。
比如说,我们监听开机广播,那么我们跟前面一样,创建一个收音机,也就是广播接收者:

package com.sunofbeaches.broadcastreceiverdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;


public class BootCompletedReceiver extends BroadcastReceiver {

    public static final String TAG = "BootCompletedReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "actions -- >" + action);
        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
            Log.d(TAG, "开机完成");
        }
    }
}

接着,这就是静态注册了,在AndroidMainfest.xml里的application节点里添加receiver节点,并且添加意图过滤的action:

 <receiver android:name=".BootCompletedReceiver">
 <!--用来接收广播-->
           <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
           </intent-filter>
  </receiver>

并且需要添加权限:
在这里插入图片描述
在这里插入图片描述

静态注册内部类广播要注意什么呢?
首先是静态注册,其次是内部广播接收者!
1、这个内部广播接收者需要声明为静态的;
2、这个内部的静态接收者必须是public的;
3、在receiver的name里是外部类的名字$内部类的名字

3.动态注册

假设我们做一个地图软件 ,当我们知道屏幕锁定以后,那么就不去更新数据,如果是屏幕打开了,就去更新数据。为什么要这么做呢,一是省电,二是省流量,对吧!
怎么做呢?
首先,我们编写一个广播接收者:
我是在MainActivity这个类里头创建了这个广播接收者,一般来说,动态接收的广播多数情况下是内部类,这样子可以操作外部类(外部类可以操作内部类)。

package com.sunofbeaches.broadcastdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private ScreenStatusReceiver mScreenStatusReceiver;

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

        //动态注册广播
        //第一步,创建意图过滤器
        IntentFilter intentFilter = new IntentFilter();
        //第二步,添加要监听的广播action
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        //第三步,创建广播接收者,并且设置成成员变量,以便于取消注册,释放资源
        if (mScreenStatusReceiver == null) {
            mScreenStatusReceiver = new ScreenStatusReceiver();
        }
        //第四步,注册广播接收者
        this.registerReceiver(mScreenStatusReceiver, intentFilter);
    }

    private class ScreenStatusReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                //屏幕关闭
                Log.d(TAG, "屏幕关闭...停止数据更新");
            } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                //屏幕打开
                Log.d(TAG, "屏幕关闭...继续数据更新");
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消广播注册
        if (mScreenStatusReceiver != null) {
            this.unregisterReceiver(mScreenStatusReceiver);
            mScreenStatusReceiver = null;
        }
    }
}
两种注册方式的区别

静态注册可以一直监听着,即使应用没有起来,也可以监听着,但是耗资源,长期监听着。
静态注册的广播优先级高于动态注册的广播。
动态注册的优点就是省资源,需要的时候才监听,不需要的时候需要取消注册。

不可以静态注册的广播

有些广播,只可以动态注册的。有那些呢?

android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
android.intent.action.BATTERY_CHANGED
android.intent.action.CONFIGURATION_CHANGED
android.intent.action.TIME_TICK

二、发送自定义广播

1.发送标准广播
前面说到了,要注意的是,内部广播接收者类,需要是静态的,Public的,注册的时候,是外部类名$内部类名

package com.sunofbeaches.broadcastdemo;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

/**
 * Created by TrillGates on 18/3/18.
 * God bless my code!
 */
public class SendBroadcastActivity extends Activity {

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

    }

    public void sendBroadcast(View view) {
        Intent intent = new Intent();
        //action只能有一个,所以叫setAction而不是addActon。
        //而广播接收者可以监听多个广播,所以是addAction
        //action的命名一般是报名+动作名,这样子比较唯一
        intent.setAction("com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK");
        //也可以携带数据
        intent.putExtra("Content", "这是我点击按钮发送的广播!");
        sendBroadcast(intent);
    }

    public static class InnerReceiver extends BroadcastReceiver{

        private static final String TAG = "InnerReceiver";

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "Inner receiver 接收到的actions... " + action);
            if ("com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK".equals(action)) {
                String content = intent.getStringExtra("Content");
                Log.d(TAG, "content is == " + content);
            }
        }
    }
}

静态注册

        <receiver android:name=".SendBroadcastActivity$InnerReceiver">
            <intent-filter>
                <action android:name="com.sunofbeaches.broadcastdemo.SEND_BROADCAST_CLICK"/>
            </intent-filter>
        </receiver>

注意版本问题需要改为

 Intent intent=new Intent("com.example.boradcasttest.MY_BROADCAST");
 //参数是“包名”,接收器类名(也要加上包名)
 intent.setComponent(new ComponentName("com.example.boradcasttest","com.example.boradcasttest.MyBroadcastReceiver"));
 sendOrderedBroadcast(intent,null);

2.发送有序广播

  Intent AnotherIntent=new Intent("com.example.boradcasttest.MY_BROADCAST");
 AnotherIntent.setComponent(new ComponentName("com.example.boradcasttest","com.example.boradcasttest.BroadcastText2"));
sendOrderedBroadcast(AnotherIntent,null);
        

priority优先级,优先级是1000~-1000之间,超出了范围则会使用边界值

   <receiver
            android:name=".BroadcastText2"
            android:enabled="true"
            android:exported="true">
            <intent-filter
                android:priority="20">
                <action android:name="com.example.boradcasttest.MY_BROADCAST" />
            </intent-filter>

        </receiver>
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter
                android:priority="100">
                <action android:name="com.example.boradcasttest.MY_BROADCAST" />
            </intent-filter>
        </receiver>
  //终止广播往下传
        abortBroadcast();

三、本地广播

系统广播很容易引起安全性问题,比如我们发送的一些携带关键性数据的广播有可能被其他应用程序截获,或者其他的程序不停向我们的广播接收器里发送各种垃圾广播。为了能解决,使得我们的发出的广播只能在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播。
本地广播主要使用一个LocalBroacastManager来对广播进行管理,并提供了发送广播和广播接收器的方法。

package com.example.boradcasttest;

import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    //private NetworkChangeReceiver networkChangeReceiver;
    private MyBroadcastReceiver myBroadcastReceiver;
    private BroadcastText2 anotherBroadcastReceiver;
    private LocalBroadcastManager localBroadcastManager;
    private LocalReceiver localReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);//获取实例
        Button button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);//发送本地广播
           
            }
        });
        //动态注册(本地广播接受器)
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(localReceiver);

    }
    //接受到广播就执行以下操作
      class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_LONG).show();
        }
    }
}

首先通过LocalBroadcastManager的getInstance方法得到了它的一个实例,然后在注册广播接收器的时候调用的是LocalBroadcastManage的registerReceiver()方法,在发送广播的时候调用 localBroadcastManager的sendBroadcast()方法。

强制下线

package com.example.broadcastbestpractice;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

/**
 * 由于广播接收器里面需要弹出一个对话框来阻塞用户的正常操作,但如果创建的是一个静态注册的广播接收器,是没办法在onReceive()方法
 * 里弹出对话框这样的UI控件的,而我们显然不可能在每个活动中都去注册一个动态的广播接收器,我们在BaseActivity中动态注册一个
 * 广播接收器就行了,因为所有活动都继承自BaseActivity。
 */
//创建BaseActivity类作为所有活动的父类
public class BaseActivity extends AppCompatActivity {
   private ForceOfflineReceiver receiver;

    @Override
    protected void onCreate(@Nullable  Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityCollector.addActivity(this);
    }

    /**
     * 我们再onResume和onPause注册和取消注册广播接收器
     * 是因为我们始终需要保证只有处在栈顶的活动才能接收到这条强制下线广播,非栈顶的活动不应该也没必要接收到这条广播
     */
    @Override
    protected void onResume() {
        //注册广播
        super.onResume();
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
        //用来接收广播
        receiver=new ForceOfflineReceiver();
        registerReceiver(receiver,intentFilter);
    }

    @Override
    protected void onPause() {
        //取消注册广播
        super.onPause();
        if(receiver!=null)
        {
            unregisterReceiver(receiver);
            receiver=null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }


    /**
     *广播接收器(注册什么广播,接收什么广播)
     */
    class ForceOfflineReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent) {
            AlertDialog.Builder builder=new AlertDialog.Builder(context);
            builder.setTitle("Warning");
            builder.setMessage("You are forced to be offline .Please try to login  again.");
            //将对话框设置为不可取消,否则用户按一下Back就可以关闭对话框
            builder.setCancelable(false);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    ActivityCollector.finishAll();//销毁所以活动
                    Intent intent=new Intent(context,LoginActivity.class);
                    context.startActivity(intent);//重新启动LoginActivity
                }
            });
            builder.show();
        }
    }
}

package com.example.broadcastbestpractice;

import android.app.Activity;

import java.util.ArrayList;
import java.util.List;

/**
 * 由于强制下线需要关闭所有的活动,然后回到登录界面。因此我们创建
 * 一个ActivityCollector类用于管理所有的活动
 */
public class ActivityCollector {
    public static List<Activity>  activities=new ArrayList<>();
    public static void addActivity(Activity activity)
    {
        activities.add(activity);
    }
    public static void removeActivity(Activity activity)
    {
        activities.remove(activity);
    }
    public static void finishAll()
    {
        for (Activity activity:activities)
        {
            if(!activity.isFinishing())
            {
                activity.finish();
            }
        }
        activities.clear();
    }
}

package com.example.broadcastbestpractice;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button forceOffline=(Button) findViewById(R.id.force_offline);
        forceOffline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE");
                sendBroadcast(intent);
            }
        });
    }

}
 package com.example.broadcastbestpractice;

import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class LoginActivity extends BaseActivity {
private EditText accountEdit;
private EditText passwordEdit;
private Button login;
private SharedPreferences.Editor mEditor;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        accountEdit=(EditText) findViewById(R.id.account);
        passwordEdit=(EditText) findViewById(R.id.password);
        login=(Button) findViewById(R.id.login);
        SharedPreferences.Editor editor=getSharedPreferences("data",MODE_PRIVATE).edit();
        PreferenceManager.getDefaultSharedPreferences(this);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account=accountEdit.getText().toString();
                String password=passwordEdit.getText().toString();
                //如果账号是admin,且密码是123456,就认为登录成功
                if(account.equals("Chen")&&password.equals("123456"))
                {
                    Intent intent=new Intent(LoginActivity.this,MainActivity.class);
                    startActivity(intent);
                    finish();
                }else{
                    Toast.makeText(LoginActivity.this,"account or password is invalid",Toast.LENGTH_LONG).show();

                }
            }
        });
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/461678.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vector-常用CAN工具 - 入门到精通 - 专栏链接

一、CANoe篇 1、CANoe入门到精通_软件安装 2、CANoe入门到精通_硬件及环境搭建 3、CANoe入门到精通_软件环境配置 4、CANoe入门到精通_Network Node CAPL开发 5、CANoe入门到精通_Node节点开发基本数据类型 6、CANoe入门到精通_Test Node节点开发设置 7、CANoe入门到精通…

《Cocos Creator游戏实战》AIGC之将草稿内容转为真实内容

目录 前言 训练AI 从识别结果中提取必要数据 发送图片并生成最终代码 总结与提高 资源下载 前言 当创作灵感来的时候&#xff0c;我们可能会先把灵感记录在草稿上&#xff0c;之后再去实现它。比方说有一天&#xff0c;我突然来了游戏创作灵感&#xff0c;想着那可以先把…

gpt 怎么用-免费gpt下载使用方法

gpt 怎么用 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer的神经网络模型&#xff0c;用于自然语言处理任务&#xff0c;例如文本生成、摘要生成、翻译、问答等。以下是使用GPT进行文本生成的一般步骤&#xff1a; 首先&#xff0c;您…

编译预处理

编译预处理 1、宏定义1.1、 无参宏定义1.2、使用宏定义的优点1.3、宏定义注意点1.4、带参数的宏(重点)1.5、条件编译1.6、宏定义的一些巧妙用法(有用)1.7、结构体占用字节数的计算原则&#xff08;考题经常考&#xff0c;要会画图&#xff09;1.8、#在宏定义中的作用&#xff0…

转型产业互联网,新氧能否再造辉煌?

近年来&#xff0c;“颜值经济”推动医美行业快速发展&#xff0c;在利润驱动下&#xff0c;除了专注医美赛道的企业之外&#xff0c;也有不少第三方互联网平台正强势进入医美领域&#xff0c;使以新氧为代表的医美企业面对不小发展压力&#xff0c;同时也展现出强大的发展韧性…

六、CANdelaStudio入门-通信参数编辑

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的通信参数编辑,欢迎各位朋友订阅、评论,…

Kubernetes 笔记(16)— 集群管理、使用名字空间分隔系统资源、给名字空间设置资源限额、默认资源配额的使用

1. 为什么要有名字空间 首先要明白&#xff0c;Kubernetes 的名字空间并不是一个实体对象&#xff0c;只是一个逻辑上的概念。它可以把集群切分成一个个彼此独立的区域&#xff0c;然后我们把对象放到这些区域里&#xff0c;就实现了类似容器技术里 namespace 的隔离效果&…

MATLAB符号运算(七) 更新中...

目录 1、实验目的&#xff1a; 2、实验内容&#xff1a; 1、实验目的&#xff1a; 1&#xff09;掌握定义符号对象和创建符号表达式的方法&#xff1b; 2&#xff09;掌握符号运算基本命令和规则&#xff1b; 3&#xff09;掌握符号表达式的运算法则以及符号矩阵运算&#xf…

93、Dehazing-NeRF: Neural Radiance Fields from Hazy Images

简介 论文&#xff1a;https://arxiv.org/pdf/2304.11448.pdf 从模糊图像输入中恢复清晰NeRF 使用大气散射模型模拟有雾图像的物理成像过程&#xff0c;联合学习大气散射模型和干净的NeRF模型&#xff0c;用于图像去雾和新视图合成 通过将NeRF 3D场景的深度估计与大气散射模…

【牛客刷题专栏】23:JZ22 链表中倒数最后k个结点(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录 前言问…

LeetCode-344. 反转字符串

题目链接 LeetCode-344. 反转字符串 题目描述 题解 题解一&#xff08;Java&#xff09; 作者&#xff1a;仲景 直接双指针前后一直交换即可 class Solution {public void reverseString(char[] s) {if (s.length 1)return;// 双指针int lp 0, rp s.length - 1;while (lp…

【百度智能云】基于http3的xcdn 开放直播方案设计与实践

大神:柯老师 现有的融合CDN 0 需要集成sdksdk 是集成在端侧缺点 sdk 对端侧有影响多云模式下,sdk不互通、 XCDN 设计目标 :保持现有cdn的优势 承载各种业务:直播点播让各家的cdn互通cdn 厂家屏蔽了差异性,集成起来比较简单,对接简单开发的互联网生态。使用统一的http3标…

理解缓冲区

文章目录 一.缓冲区1.什么是缓冲区2.缓冲区的意义3.缓冲区的刷新策略4.我们目前谈论的缓冲区在哪里5.仿写FILE5.1myStdio.h5.2myStdio.c 6.操作系统的缓冲区 一.缓冲区 int main() {printf("hello linux");sleep(2);return 0; }对于这样的代码&#xff0c;首先可以肯…

C++11 unique_ptr智能指针

#include<iostream> using namespace std;class test { public:test() {cout << "调用构造函数" << endl;}~test() {cout << "调用析构函数" << endl;} };int main(void) {//1.构造函数unique_ptr<test>t1;unique_ptr…

数据结构之KMP算法:彻底搞懂kmp算法

数据结构的学习&#xff0c;kmp匹配算法困扰我许久&#xff0c;此处来一个总结&#xff08;仅供自己复习了解参考使用&#xff09;&#xff0c;如果有不对的地方请多多指点。好了废话不多说我们直接开始好吧。 目录 关于暴力匹配原理的讲解&#xff1a; kmp算法&#xff1a; …

ChatGPT - 如何高效的调教ChatGPT (指令建构模型-LACES问题模型)

文章目录 定义1. Limitation&#xff08;限定条件&#xff09;2. Assignment&#xff08;分配角色&#xff09;3. Context&#xff08;背景或上下文&#xff09;4. Example&#xff08;示例&#xff09;5. Step by Step&#xff08;拆分任务&#xff09; 小Demo 定义 LACES问题…

尚硅谷大数据技术Spark教程-笔记04【SparkCore(核心编程,RDD-行动算子-序列化-依赖关系-持久化-分区器-文件读取与保存)】

视频地址&#xff1a;尚硅谷大数据Spark教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据技术Spark教程-笔记01【Spark&#xff08;概述、快速上手、运行环境、运行架构&#xff09;】尚硅谷大数据技术Spark教程-笔记02【SparkCore&#xff08;核心编程&#xff0c;RDD-核心属…

加强人工智能共性技术研发与产业化协同发展

央视网消息&#xff1a;“以5G为代表的新一代信息技术与制造业、交通、旅游等实体经济重要领域深度融合。”4月20日下午&#xff0c;国新办举行一季度工业和信息化发展情况新闻发布会&#xff0c;相关部门负责人在答问时表示&#xff0c;将用好融合应用这把金钥匙&#xff0c;开…

ReactHook学习(第一篇-N)

文章目录 Hook简介概述class组件的不足什么是 Hook?Hook 使用规则 state的研究&#xff08;useState&#xff09;State&#xff1a;组件的记忆&#xff08;响应式数据&#xff09;当普通的变量无法满足时添加一个 state 变量遇见你的第一个 Hook剖析 useState 赋予一个组件多个…

【C++】面向对象

文章目录 3.1 类与对象3.1.1 类成员的访问控制3.1.2 类的成员函数对象的访问方式成员函数的实现内联成员函数 3.1.3 构造函数复制构造函数调用复制构造函数的三种情况深复制与浅复制&#xff1f; 析构函数类的组合 3.1.4 前向引用声明3.1.5 结构体与类对比3.1.6 UML类图属性表示…