Android中的广播机制

2023-05-16

说明: 本文是郭霖《第一行代码-第3版》的读书笔记

6.1 广播机制简介

Android中的广播分为两种类型:标准广播和有序广播。

标准广播:完全异步执行的广播,在广播发出后,所有的BroadcastReceiver几乎会在同一时刻接收到该广播,因此是无序的,效率会比较高

有序广播:是一种同步执行的广播,在广播发出后,同一时刻只有一个BroadcastReceiver接收到这条广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,才能继续传给其他接收者,此时的BroadcastReceiver是有先后顺序的,优先级高的先收到消息,并且前面的还可以截断正在传递的广播

同步和异步的区别:同步是阻塞模式,异步是非阻塞模式。在操作系统中,

同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;

异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

6.2 接收系统广播

Android中内置了许多系统级别的广播,我们可以在应用程序中监听这些广播来得到系统的状态信息,例如手机开机会发送一条广播,电池的电量发生变化会发送广播、系统时间改变也会发出广播,若想接收这些广播,需要使用BroadcastReceiver

我们可以通过自由地注册BroadcastReceiver的方式自由地选择要接收哪些广播,注册的方式分为两种:

  • 在代码中注册,也称为动态注册
  • AndroidManifest.xml中注册,也称为静态注册

6.2.1 动态注册监听时间变化

要创建一个BroadcastReceiver,只需新建一个类,让他继承自BroadcastReceiver并重写父类的onReceive()方法就可以了。感觉很像Qt里的信号槽的机制。触发事件然后接收。

class MainActivity : AppCompatActivity() {

    lateinit var timeChangeReceiver: TimeChangeReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //注册接收器
        val intentFilter = IntentFilter()
        intentFilter.addAction("android.intent.action.TIME_TICK")
        timeChangeReceiver = TimeChangeReceiver()
        registerReceiver(timeChangeReceiver, intentFilter)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeChangeReceiver)
    }

    inner class TimeChangeReceiver: BroadcastReceiver() {
        override fun onReceive(p0: Context?, p1: Intent?) {
            Toast.makeText(p0, "Time has changed.", Toast.LENGTH_SHORT).show()
        }
    }
}

首先我们创建了一个IntentionFilter的实例,并给他添加了一个值为android.intent.action.TIME_TICK的action,我们的BroadcastReceiver想要监听什么样的广播就需要添加相应的action。

接下来创建一个TimeChangeReceiver的实例,然后调用registerReceiver()方法注册,动态注册的BroadcastReceiver要取消注册,可以在onDestroy()方法中调用unregisterReceiver()方法取消注册。

查看完整的系统广播列表,可以去此路径查看:<AndroidSDK>\platforms\android-32\data\broadcast_actions.txt,可以看到,系统广播大概有三百多条。

6.2.2 静态注册实现开机启动

动态注册的BroadcastReceiver必须在程序启动后才能接收广播,在程序未启动的时候也能接收广播需要用到静态注册的方式。

理论上来说动态注册能监听到的系统广播,静态注册也能听到,但是由于恶意程序利用这个机制,Android 8.0之后,所有隐式广播都不允许使用静态注册的方式来接收,所谓隐式广播,指的是那些没有具体指定发送给哪个应用程序的广播,大多数系统广播都是隐式广播。但是少数特殊的系统广播目前仍然允许使用静态注册的方式来接收。

特殊的系统广播列表: https://developer.android.com/guide/components/broadcast-exceptions.html

除了使用内部类的方式创建BroadcastReceiver,也可以通过Android Studio提供的快捷方式创建。

class BootCompleteReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show()
    }
}

onReceive()方法内使用Toast弹出一段提示信息。

静态的BroadcastReceiver一定要在AndroidManifest.xml中注册才可以使用。由于我们使用快捷方式注册,这一步已经自动生成了。

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

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <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.BoardcastTest">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

注意,我们还需要添加权限声明,为了能够接收开机的action,需要在Receiver内添加intent-filter并指定action为android.intent.action.BOOT_COMPLETED.

最后,不要在onReceive()方法内添加过多的逻辑或任何耗时操作,因为BroadcastReceiver中不允许开启线程,当此方法允许较长时间而未结束时,程序就会出错。

(这个好慢,需要耐心等一会儿,启动好一会才会显示)

6.3 发送自定义广播

6.3.1 发送标准广播

首先使用静态方法定义一个BroadcastReceiver

class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        Toast.makeText(context, "received in MyBroadcastReceiver",Toast.LENGTH_SHORT).show()
    }
}

然后在AndroidManifest.xml中对Receiver添加<intent-filter>

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

    <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.BroadcastNew">
		
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="www"/>
            </intent-filter>
        </receiver>
		...
    </application>

</manifest>

在布局中加入一个button,在主程序中加入点击监听事件:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button: Button = findViewById(R.id.button)
        button.setOnClickListener {
            val intent = Intent()
            intent.action = "www"
            intent.setPackage(packageName)
            sendBroadcast(intent)
        }
    }
}

注意:setPackage()指定广播发给哪个应用程序,前面已经说过,静态注册的BroadcastReceiver无法接收隐式广播,所以需要调用该方法让其成为显示广播。,再调用sendBroadcast()将广播发出去。

记一下Bug

在重写方法的时候,Android Studio一般会提示TODO("Not yet implemented"), 你自己写代码的时候一定要覆盖这句啊,如果这条语句在的话是会报错的,在允许的时候会报xxx keep stoping等等。具体看报错可以在logcat窗口搜索AndroidRuntime

6.3.2 发送有序广播

再加一个AnotherBroadcastReceiver,使其也能收到"www"的自定义广播,然后点击按钮,可以弹出两个Toast。

要发送有序广播只需改动一行代码:

button.setOnClickListener {
    val intent = Intent()
    intent.action = "www"
    intent.setPackage(packageName)
    //sendBroadcast(intent)
    sendOrderedBroadcast(intent, null)
}

sendOrderedBroadcast()接收两个参数,一个是intent,另一个是与权限相关的字符串,这里填null就行。

有序广播指定顺序在注册的时候:

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

    <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.BroadcastNew">
        
        <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="www"/>
            </intent-filter>
        </receiver>

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="www" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

通过intent-filterandroid:priority来指定优先级,值必须是一个整数,如“100”。数值越高,优先级也就越高。默认值为 0。

class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        Toast.makeText(context, "received my",Toast.LENGTH_SHORT).show()
        abortBroadcast()
    }
}

如果在onReceive()方法内调用了abortBroadcast()方法,则会将这条广播截断,后续的接收器就收不到了。

6.4 广播的最佳实践:强制下线

不论当前在哪一个界面都强制退出,可以使用之前写的管理Activity的ActivityCollector单例类:

object ActivityCollector {
    private val activities = ArrayList<Activity>()

    fun addActivity(activity: Activity) {
        activities.add(activity)
    }

    fun removeActivity(activity: Activity) {
        activities.remove(activity)
    }

    fun finishAll() {
        for (activity in activities) {
            if (!activity.isFinishing) {
                activity.finish()
            }
        }
        activities.clear()
    }
}

然后创建Base类作为所有Activity的父类:

open class BaseActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        ActivityCollector.addActivity(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }
}

再新建一个Login的登陆界面:

<?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
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="Account:"/>
        <EditText
            android:id="@+id/accountEdit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="Password:"/>
        <EditText
            android:id="@+id/passwordEdit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>

    <Button
        android:id="@+id/login"
        android:layout_width="200dp"
        android:layout_height="60dp"
        android:layout_gravity="center_horizontal"
        android:text="Login"/>

</LinearLayout>

再修改LoginActivity中的代码:

class LoginActivity:BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        login.setOnClickListener {
            val account = accountEdit.text.toString()
            val password = passwordEdit.text.toString()
            if (account == "admin" && password == "123456") {
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
                finish()
            } else {
                Toast.makeText(this, "invalid account or password.", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

Login界面检查账户和密码是否输入正确,正确就转进MainActivity。MainActivity只有一个Button,用于发送强制下线的广播,这里采用的是动态注册的方法。

class MainActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        forceOffLine.setOnClickListener {
            val intent = Intent("FORCE_OFFLINE")
            sendBroadcast(intent)
        }
    }
}

我们想要的效果是:点击强制下线按钮,会弹出一个对话框,点击确认键后退出所有Activity并返回Login界面,如果是静态注册的BroadcastReceiver,是无法弹出AlertDialog的,因此接收广播需要定义在BaseActivity中,保证无论在哪个Activity都能收到广播。

open class BaseActivity: AppCompatActivity() {

    lateinit var receiver: ForceOfflineReceiver

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        ActivityCollector.addActivity(this)
    }

    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter()
        intentFilter.addAction("FORCE_OFFLINE")
        receiver = ForceOfflineReceiver()
        registerReceiver(receiver, intentFilter)
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(receiver)
    }

    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }

    inner class ForceOfflineReceiver: BroadcastReceiver() {
        override fun onReceive(context: Context, p1: Intent?) {
            AlertDialog.Builder(context).apply {
                setTitle("Warning")
                setMessage("You are forced to be offline, Please try to login again")
                setCancelable(false)
                setPositiveButton("OK") {_, _ ->
                    ActivityCollector.finishAll()
                    val i = Intent(context, LoginActivity::class.java)
                    context.startActivity(i)
                }
                show()
            }
        }
    }
}

我们将接收广播写在了onResume()onPause()方法中。这是因为我们只需要返回栈栈顶的Activity收到广播,其他Activity没必要收。

最后还需要在AndroidManifest.xml中将Login设为启动界面就可以了。

注意:onCreate()方法有多个重载版本,这里用的是只有一个参数Bundle?那个,用错了会出问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android中的广播机制 的相关文章

  • 如何正确显示AChartEngine条形图

    我在用图表引擎 1 0 1 最新 并想演示一个条形图 这就是我要的 我想要的图表 到目前为止我所取得的成就 1 1 view 缩小视图 问题 图表的左右部分在 1 1 视图中丢失 酒吧之间的距离是如此之远 我需要减少它 该栏未正确位于文本标
  • 在S3客户端android中制作私有图像的ImageGallery

    我正在尝试在 Android 应用程序中创建 S3 Bucket 的 imageGallery 我的图像是私人的 所以我不会为每个图像提供任何特定的链接 对于此类私人图像 亚马逊有一个链接生成器 s3Client generatePresi
  • 使用 Cordova 加载应用程序时如何配置状态栏颜色?

    我用 Cordova 创建了一个应用程序 我想改进 UI UX 使其看起来尽可能像本机应用程序 当应用程序第一次加载时 状态栏 和背景 的前几毫秒 实际上不到 1 秒 没有我配置的颜色Cordova 状态栏插件 https cordova
  • 进度条中形状的填充

    我正在使用 xml 文件来定义进度条 我在背景形状上定义了填充 但这个设置有时会正确显示 有时则不能 因此 如果我启动内部带有进度条的应用程序或活动 则会正确显示带有背景和 填充 进度的进度条 然后我关闭我的应用程序并再次启动它 并且 进度
  • 如何在不清除和闪烁地图的情况下刷新谷歌地图上的标记位置?

    是否可以创建无需闪烁 清除整个地图即可更新的 Google 地图 V2 标记 目前我必须清除地图然后添加标记 googleMap clear googleMap addMarker new MarkerOptions position en
  • android 弹出菜单文本颜色(AppCompat)

    我需要更改 popuo 菜单的文本颜色 但我找不到任何方法来执行此操作 我可以更改 popomenu 的背景但不能更改文本 我以这种方式编辑 style xml
  • 检索特定联系人的组

    我想检索联系方式及其所属的组 我得到了列出手机中所有联系人组的代码 Cursor groupC getContentResolver query ContactsContract Groups CONTENT URI null null n
  • 类 X 不是抽象的,并且没有实现 android.os.Parcelable 中定义的 fun writeToParcel()

    在我的 Android 应用程序中 我想添加一个 Bundle 其中包括Place下面描述我的意图的对象 由于 Serialized 速度慢且不推荐 所以我更喜欢 Parcelable 虽然我使用 Kotlin 1 3 31 但在分割某些数
  • Android:由于 Web 服务 Http 请求,活动显示时间过长

    我的一项活动是在启动应用程序时向 Web 服务发出 http 请求以获取一些天气数据 由于 Web 服务请求 活动需要 3 4 秒才能显示的问题 在实际设备上测试 我知道我没有以正确的方式这样做 我所做的就是在 onCreate 方法上 我
  • 华为移动服务的 Android 虚拟设备

    我想将HMS应用到我的应用程序中 然而 购买真正的华为手机并不在我的候选清单上 华为是否为此目的提供 Android 虚拟设备 如果没有 如何测试我的 HMS 实现是否真正有效 是的 华为确实提供了一个 Android 虚拟设备 名为App
  • 如何使用远程 URL 在 Android 模拟器中播放 mp4 视频?

    如何使用远程 URL 在 Android 模拟器中播放 mp4 视频 我使用了以下代码 但此代码给我错误 抱歉 该视频无法播放 07 05 16 58 19 525 INFO AwesomePlayer 34 mConnectingData
  • android,如何重命名文件?

    在我的应用程序中 我需要录制视频 在开始录制之前 我为其指定名称和目录 录制完成后 用户可以重命名其文件 我写了以下代码 但似乎不起作用 当用户输入文件名并单击按钮时 我将执行以下操作 private void setFileName St
  • Android.system.ErrnoException:isConnected失败:ECONNREFUSED(连接被拒绝)

    我使用Java连接MySQL和Json将数据发送到android 当我通过URL地址将数据从Java发送到json时 http 192 168 1 221 9999 rentalcar service category getAllManu
  • 获取当前 GPS 时出现 NullPointerException

    我有一个测试屏幕 其中有一个按钮 按下它会调用该服务 我正在尝试实现一种方法来获取当前用户的当前 GPS 位置 但在尝试调用时它崩溃了 谁能告诉我问题是什么吗 package com example whereyouapp import j
  • 如何将两个 APK 合并为一个,以便两个应用程序可以同时安装

    如何将 2 个 Android 应用程序合并到捆绑包中 以便在安装捆绑包时同时安装两个应用程序 我想将 2 个 APK 合并到一个捆绑包中 以便我可以将其上传到 Android Market 当有人将其安装到设备上时 这两个应用程序都应该安
  • android-security :Google Play 警告:您的应用程序包含 SQL 注入问题

    作为我们应用程序的一部分 我们使用两个 contentProvider 但两者都受到 android exported false 的保护 但我们仍然收到一封 Google Play 警告邮件 您的应用程序包含 SQL 注入问题 他们提到的
  • 在 Android 应用程序中使用传单来显示在线地图

    是否有任何示例项目展示如何正确使用传单在 Android 应用程序中显示在线地图 因为我尝试了很多示例 但每次我的应用程序中都有一个空的网络视图 这是我的代码 private WebView mWebView Override protec
  • android Analytics v4 最简化

    我正在尝试以最简单的方式将谷歌分析连接到我的应用程序 我想实现analytics v4 因为google说他们很快就会强制升级到它 所以我不想做两次同样的工作 在这种情况下 谷歌的教程不是很有效 合并他们在那里所说的内容和我在互联网上找到的
  • 有没有办法检测apk是否存储在SD卡上?

    有没有办法检测apk是否存储在SD卡上 如何 使用 getApplicationInfo sourceDir http developer android com reference android content pm Applicati
  • 按钮的大小取决于屏幕分辨率

    I have LinearLayout有 6 个按钮 在 4 7 英寸大小的分辨率下 按钮几乎是完美的 但在分辨率较高的设备上 它们不会占据整个屏幕 而在分辨率较低的设备上 并非所有按钮都可见 您能否解释一下如何使按钮在不同屏幕分辨率的设备

随机推荐

  • 【iOS】—— 浅谈UISearchController

    UISearchController是iOS的一个系统的搜索控件 xff0c 在平时我们输入信息的时候会出现相应的联想搜索的内容 xff0c 然后通过UITableView展示到搜索框的下面 xff0c 供我们选择 原本还想用UITextF
  • Linux Shell中的正则表达式

    Linux Shell中的正则表达式 正则表达式是什么正则表达式通配符 cut命令awk命令sedsort排序命令wc统计命令 正则表达式是什么 正则表达式是用于描述字符排列和匹配模式的一种语法规则 它主要用于字符串的模式分割 匹配 查找及
  • 【Linux】刚烧录完(相当于是第1次连接),VNC树莓派无法连接

    文章目录 解决方法如下 xff1a 1 在Terminal中输入 96 vncserver 96 2 在Terminal中再输入 96 sudo raspi config 96 3 输入连接即可 刚烧录完 xff0c 然后用 ifconfi
  • QT 配置Opencv+gdal心得

    本人研究僧一枚 xff0c 老师给了使用QT开发遥感图像相关程序的课题 xff0c 完全从零开始学习 xff0c 查阅了许多的资料 xff0c 过程里东拼西凑 xff0c 碰壁无数 所以我就想写一些学习的心得体会 xff0c 给自己复习使用
  • Flink 从 kafka 中读取数据并输出到 kafka

    Kafka 是一个分布式的基于发布 订阅的消息系统 xff0c 本身处理的也是流式数据 kafka和flink二者被称为当前处理流式数据的双子星 下面我们将从以下几个步骤展开讲解 xff1a 目录 一 添加maven依赖 二 编写flink
  • 视图创建与管理实验

    xff08 一 xff09 在job数据库中 xff0c 有聘任人员信息表 xff1a Worklnfo表 xff0c 其表结构如下表所示 xff1a create table workinfo id int 4 not null uniq
  • LaTeX的篇章结构

    LaTeX的篇章结构 一般在撰写一个文档时 xff0c 总是先写出文章的提纲 然后根据该提纲进行展开 xff0c 来撰写其他的内容 文章目录 构建小节构建段落标题格式带章节大纲文档目录 构建小节 xff08 1 xff09 用section
  • LaTeX中的参考文献BibLaTeX

    LaTeX中的参考文献BibLaTeX 文章目录 一 介绍二 配置三 参考文献数据库文件四 引用文献1 导入宏包2 添加参考文献数据库3 不同方式引用参考文献4 输出参考文献列表5 编译执行6 修改标题7 列出没有引用的参考文献8 更多样式
  • 独立按键控制LED亮灭

    目录 一 独立按键 二 独立按键控制LED亮灭 三 按键的抖动 四 独立按键控制LED显示二进制 五 独立按键控制LED移位 一 独立按键 轻触按键 xff1a 相当于一种电子开关 xff0c 按下时开关接通 xff0c 松开时开关断开 x
  • 内网权限维持

    权限维持 以下测试均在win7 拓展方面 windows开启rdp 1 设置远程桌面端口 xff08 可以不用输 xff0c 直接第二步 xff0c 默认开启3389 xff09 reg add 34 HKLM System Current
  • 常见优秀代码汇总

    汇总常见的编程习惯 1 语义简单明确 含义 xff1a 写代码时考虑读者 xff0c 优先采取易于读者理解的写法 define THROTL UNSET 2 define THROTL NO LIMIT 1 bool throttle is
  • 2021/7/20

    8 xff1a 30 9 xff1a 00 学习打卡 9 xff1a 30 13 xff1a 00 二招刷题 15 xff1a 00 19 xff1a 00 二招刷题 1 xff0c a题 给你一个长度为N的序列 xff0c 现在需要把他们
  • python可安装软件的制作

    一 生成可执行文件 xff08 exe 安装打包工具pyinstaller 第一种 xff1a 通过win 43 R打开cmd直接使用下面的命令安装即可 pip install pyinstaller 第二种 xff1a 下载pyinsta
  • 汇编常见指令

    文章目录 常见的运算类汇编指令add指令sub指令mul乘法指令div除法指令inc xff08 自增 xff09 xff08 即C语言 43 43 xff09 dec xff08 自减 xff09 xff08 即 xff09 push x
  • 使用阿里云服务器三分钟搭建网站

    目录 一 购买服务器 二 配置云服务器 三 下载XShell编辑器 四 使用XShell与服务器建立连接 五 安装宝塔 六 配置宝塔 七 配置多个站点 一 购买服务器 注意一定要购买CentOS内核的服务器 二 配置云服务器 购买云服务器之
  • STM32 ---寄存器点灯

    1 创建工程 处理器执行程序的时候怎么执行 处理器执行程序都是先执行汇编程序 xff0c 然后在汇编程序里面跳到主函数里面 xff0c 所以要先写好汇编程序 不过这个一般官方提供了 xff0c 只需把这个文件拷到我们的工程文件夹里面 接着将
  • QMessageBox 方法大全,各种弹窗的方法

    QMessageBox Ok xff1a 显示一个OK按钮 xff1b QMessageBox Open xff1a 显示一个打开文件的按钮 xff1b QMessageBox Save xff1a 显示一个保存文件的按钮 xff1b QM
  • 【Python实现视频转文字操作】

    一 安装moviepy模块 1 如果你用的PyCharm 导包的时候报错后 可以直接按Alt 43 Shift 43 Enter install moviepy 2 也可以在终端输入 pip install moviepy 前提是安装好了p
  • 谈论flutter和jetpack compose学习优先级的背后,Android开发有着怎样的一套进阶逻辑?

    前言 xff1a 在1982年的原版电影 银翼杀手 中 xff0c 人类已经发展出了一种人造的生命形式 xff0c 很难将它们与人类区分开来 这些 复制品 被用于危险的工作 xff0c 当它们开始反抗人类主人时 xff0c 一种被称为 刀锋
  • Android中的广播机制

    说明 xff1a 本文是郭霖 第一行代码 第3版 的读书笔记 6 1 广播机制简介 Android中的广播分为两种类型 xff1a 标准广播和有序广播 标准广播 xff1a 完全异步执行的广播 xff0c 在广播发出后 xff0c 所有的B