Android --- 消息机制与异步任务

在Android中,只有在UIThread(主线程)中才能直接更新界面,

在Android中,长时间的工作联网都需要在workThread(分线程)中执行

在分线程中获取服务器数据后,需要立即到主线程中去更新UI来显示数据,

所以,如何实现线程间的通信(消息机制)

消息机制原理

消息机制原理 尚硅谷

handler发送消息到 MessageQueue 消息队列中,消息队列内部是一个链表的结构,Looper会取出消息队列中待处理的消息,调用handler的dispatchMessage()分发消息,handler中处理消息的方法有三种,最常用的是第三种

Message的callback

handler的callback

handler的handleMessage方法

消息机制相关API

Message 消息

可理解为线程间通信的数据单元,可通过message携带需要的数据

创建对象:Message.obtain()、new Message()

Message.obtain()使用了Message中的消息池,比直接new一个对象更高效

常用参数:

  • what: id标识,用以区分来自哪个线程
  • arg1/arg2: 子线程需要向主线程传递整型参数
  • obj: Object 任意对象

Handler 处理器

handler并不是只能用在处理message上,定时循环调度等工作也能使用它。

Handler 是Message 的处理器,也负责消息的发送和移除工作。

  • 发送即时消息 
public final boolean sendMessage(@NonNull Message msg),实际上调用了sendMessageDelayed()发送一个延迟时间为0的消息
public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
  • 发送延时消息,并不是指延时发送,而是延时处理
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis)
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
  • 发送空消息
public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
 }

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

不管是发送什么消息,最后都要调用 sendMessageAtTime 方法

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
  • 处理消息 (回调方法) 在主线程中执行
public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        boolean handleMessage(@NonNull Message msg);
    }
  • 移除未处理消息,比如发送的延时消息:让消息队列调用 removeMessages 方法移除消息
    public final void removeCallbacks(@NonNull Runnable r) {
        mQueue.removeMessages(this, r, null);
    }

MessageQueue 消息队列

它是一个按Message的when(被处理时间)排序的优先级队列,用来存放通过 Handler 发送的消息。

实例

创建Handler对象,并重写 handleMessage 方法

在主/分线程创建Message对象,利用handler对象发送消息

在 handleMessage 中处理消息

  • 创建Handler对象,并重写 handleMessage 方法 

只要 handle 发了消息,就一定会触发 handleMessage 方法,并传入一个 Message 对象,根据Message 对象的what属性判断属于哪个线程。

public class HandleActivity extends AppCompatActivity {

    TextView textView ;
    String httpDate = "";

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


    // 利用 handller 处理
    // 1.实例化一个 Handler
   Handler handler = new Handler(
      // 只要 handle 发了消息,就一定会触发 handleMessage 方法,并传入一个 Message 对象
            new Handler.Callback() {
                @Override
                // 3.由handle对象接收消息并处理,在Handler的内部类中处理
                public boolean handleMessage(@NonNull Message msg) {
                    Log.e("handler 处理消息", "这是handler发送的消息,此时是空");

                    // 根据 Message 的 what 属性,区分来源于哪个线程
                    if (msg.what == 1) {
                        textView1 = findViewById(R.id.t1);
                        textView1.setText(httpDate);
                    } else if (msg.what == 2) {
                        textView2 = findViewById(R.id.t2);
                        textView2.setText(httpDate);
                    } else if (msg.what == 3) {
                        textView3 = findViewById(R.id.t3);
                        textView3.setText("msg.what = "+msg.what+"\n"+msg.obj.toString());
                    }
                    return false;
                }
            }
    );
}
  • 在主/分线程创建Message对象,利用handler对象发送消息

当消息没有包含数据时,可以使用handler.sendEmptyMessage(int what) 发送一个空消息

new Thread() {
    @Override
    public void run() {
       super.run();
       getHttp();
       // 当 handler 需要传送数据时,需要使用到 Message,使用 sendMessage 方法
                   
       Message message = new Message();
       message.what = 3;
       DataBean dataBean = new DataBean(1,"157181@qq.com","ybr","scl","asiudh");
       message.obj = dataBean;
       handler.sendMessage(message);
       }
   }.start();
  • 设置一个网络操作方法 
 // 网络操作
    private void getHttp() {
        try {
            // 1. 实例化一个 URL 对象
            URL url = new URL("https://reqres.in/api/users");
            // 2. 获取 HttpURLConnection 实例,使用URL的
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            // 3. 设置请求相关属性
            httpURLConnection.setRequestMethod("GET"); // 请求方法
            httpURLConnection.setConnectTimeout(6000); // 超时时间
            // 4. 获取响应码 200 成功 404 未请求到指定资源 500 服务器异常(此时已经发起请求)
            // 5. 判断响应码并获取响应数据(响应的正文)
            if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = httpURLConnection.getInputStream(); // 获取了服务器返回的输入流
                byte[] bytes = new byte[1024]; // bytes 数组,每次最多可以存放 1024 个字节
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();// 存储从输入流中读取的数据
                int len = 0;
                while ((len = inputStream.read(bytes)) > -1) {
                    // 将字节数组中的内容写入到缓存流
                    /* 参数1:要存入的字节数组
                     * 参数2:起点
                     * 参数3:要存入的长度*/
                    byteArrayOutputStream.write(bytes, 0, len);
                }
                httpDate = new String(byteArrayOutputStream.toByteArray());
                Log.e("GET返回的数据", httpDate);
            }
        } catch (ProtocolException ex) {
            throw new RuntimeException(ex);
        } catch (MalformedURLException ex) {
            throw new RuntimeException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

 全部代码

package com.example.androidstudiostudy;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.androidstudiostudy.data.DataBean;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;

public class HandleActivity extends AppCompatActivity {

    TextView textView1, textView2, textView3;
    String httpDate = "";

    // 利用 handller 处理
    // 1.实例化一个 Handler
    Handler handler = new Handler(
            // 只要 handle 发了消息,就一定会触发 handleMessage 方法,并传入一个 Message 对象
            new Handler.Callback() {
                @Override
                // 3.由handle对象接收消息并处理,在Handler的内部类中处理
                public boolean handleMessage(@NonNull Message msg) {
                    Log.e("handler 处理消息", "这是handler发送的消息,此时是空");

                    // 根据 Message 的 what 属性,区分来源于哪个线程
                    if (msg.what == 1) {
                        textView1 = findViewById(R.id.t1);
                        textView1.setText(httpDate);
                    } else if (msg.what == 2) {
                        textView2 = findViewById(R.id.t2);
                        textView2.setText(httpDate);
                    } else if (msg.what == 3) {
                        textView3 = findViewById(R.id.t3);
                        textView3.setText("msg.what = "+msg.what+"\n"+msg.obj.toString());
                    }
                    return false;
                }
            }
    );

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

    // 此时有两个线程,这两线程发送的消息都能被 Handle接收,但如何区分不同线程发送的消息从而做不同处理呢?
    public void getDate(View view) {
        int id = view.getId();
        // 第一个线程
        if (id == R.id.handle1) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();
                    // 此时会报错:Only the original thread that created a view hierarchy can touch its views.
                    /*TextView textView = findViewById(R.id.t1);
                    textView.setText(httpDate);*/

                    // 解决办法 1 runOnUiThread 方法 ==> 相当于在主线程中跑 (初学阶段)
                    /*runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            TextView textView = findViewById(R.id.t1);
                            textView.setText(httpDate);
                        }
                    });*/
                    // 解决办法 2 利用 Handle 处理
                    // 2.在子线程中发送(空)消息,此时发送的是空消息
                    handler.sendEmptyMessage(1);
                }
            }.start();
        }
        // 第二个线程
        else if (id == R.id.handle2) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();
                    httpDate = httpDate + "\n第2个线程";
                    handler.sendEmptyMessage(2);
                }
            }.start();
        }
        // 第三个线程
        else if (id == R.id.handle3) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();
                    // 当 handler 需要传送数据时,需要使用到 Message,使用 sendMessage 方法
                    /* 1. 实例化一个 Message
                     * 2. 参数
                     ** what:用于区分 handler 发送消息的不同线程来源
                     ** arg1/arg2: 子线程需要向主线程传递整型参数
                     ** obj: Object 任意对象*/
                    Message message = new Message();
                    message.what = 3;

                    DataBean dataBean = new DataBean(1,"157181@qq.com","ybr","scl","asiudh");
                    message.obj = dataBean;
                    handler.sendMessage(message);
                }
            }.start();
        }
    }

    // 网络操作
    private void getHttp() {
        try {
            // 1. 实例化一个 URL 对象
            URL url = new URL("https://reqres.in/api/users");
            // 2. 获取 HttpURLConnection 实例,使用URL的
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            // 3. 设置请求相关属性
            httpURLConnection.setRequestMethod("GET"); // 请求方法
            httpURLConnection.setConnectTimeout(6000); // 超时时间
            // 4. 获取响应码 200 成功 404 未请求到指定资源 500 服务器异常(此时已经发起请求)
            // 5. 判断响应码并获取响应数据(响应的正文)
            if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = httpURLConnection.getInputStream(); // 获取了服务器返回的输入流
                byte[] bytes = new byte[1024]; // bytes 数组,每次最多可以存放 1024 个字节
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();// 存储从输入流中读取的数据
                int len = 0;
                while ((len = inputStream.read(bytes)) > -1) {
                    // 将字节数组中的内容写入到缓存流
                    /* 参数1:要存入的字节数组
                     * 参数2:起点
                     * 参数3:要存入的长度*/
                    byteArrayOutputStream.write(bytes, 0, len);
                }
                httpDate = new String(byteArrayOutputStream.toByteArray());
                Log.e("GET返回的数据", httpDate);
            }
        } catch (ProtocolException ex) {
            throw new RuntimeException(ex);
        } catch (MalformedURLException ex) {
            throw new RuntimeException(ex);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Looper 循环器

  • 负责循环取出 MessageQueue 中当前需要处理的Message
  • 交给对应的handler进行处理
  • 处理完后,将Message缓存到消息池中,以备复用

每个线程都可以有一个关联的Looper对象,用于处理该线程的消息队列。主要功能是接收来自消息队列的消息并将其分发给对应的Handler处理。

在Android中,主线程已经自动创建了一个Looper对象,并启动了消息循环,我们可以在主线程中方便地使用Handler来处理UI事件。

而对于其他线程,如果需要处理消息,就需要手动创建一个Looper对象,并调用Looper.loop()方法来启动消息循环。

  • 必须确保在创建Handler对象之前,在线程中调用了Looper.prepare()方法创建Looper对象并初始化。
  • 通过调用Looper.loop()方法,线程会进入一个无限循环,不断地从消息队列中取出消息,并将其分发给对应的Handler进行处理。当调用Looper.quit()方法时,消息循环会停止,线程会退出循环。
 Handler handler2;

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

        // 开一个新的线程,用于接收主线程向子线程传递消息
        new Thread(new Runnable() {
            @Override
            public void run() {

                // 系统会自动为主线程开启消息循环(自动调用这句代码),与此同时创建一个 Looper 对象,不断的从 MessageQue中读取消息,交给主线程处理
                Looper.prepare(); // 准备开启一个消息循环

                handler2 = new Handler(new Handler.Callback() {
                    @Override
                    public boolean handleMessage(@NonNull Message msg) {
                        Log.e("主线程向子线程中发送消息", "" + msg.what + "" + msg.arg1);
                        return false;
                    }
                });

                Looper.loop(); //开始消息循环,相当于 while(true) ,在这里等待消息
            }
        }).start();
    }

    // 此时有两个线程,这两线程发送的消息都能被 Handle接收,但如何区分不同线程发送的消息从而做不同处理呢?
    public void getDate(View view) {
        int id = view.getId();
        // 第一个线程
        if (id == R.id.handle1) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();
                    // 此时会报错:Only the original thread that created a view hierarchy can touch its views.
                    /*TextView textView = findViewById(R.id.t1);
                    textView.setText(httpDate);*/

                    // 解决办法 1 runOnUiThread 方法 ==> 相当于在主线程中跑 (初学阶段)
                    /*runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            TextView textView = findViewById(R.id.t1);
                            textView.setText(httpDate);
                        }
                    });*/
                    // 解决办法 2 利用 Handle 处理
                    // 2.在子线程中发送(空)消息,此时发送的是空消息
                    handler.sendEmptyMessage(1);
                }
            }.start();
        }
        // 第二个线程
        else if (id == R.id.handle2) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();
                    httpDate = httpDate + "\n第2个线程";
                    handler.sendEmptyMessage(2);
                }
            }.start();
        }
        // 第三个线程
        else if (id == R.id.handle3) {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();                  
                    Message message = new Message();
                    message.what = 3;

                    DataBean dataBean = new DataBean(1, "157181@qq.com", "ybr", "scl", "asiudh");
                    message.obj = dataBean;
                    handler.sendMessage(message);
                }
            }.start();
        }
        // 第四个线程- 主线程向子线程发送消息
        else if (id == R.id.handle4) {
            Message message2 = new Message();
            message2.what = 999;
            message2.arg1 = 1234;
            handler2.sendMessage(message2);
        }
    }

线程中更新UI

runOnUiThread 方法

==> 相当于在主线程中跑 (初学阶段)

public void getDate() {
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    getHttp();
                    // 此时会报错:Only the original thread that created a view hierarchy can touch its views.
                    /*TextView textView = findViewById(R.id.t1);
                    textView.setText(httpDate);*/

                    // 解决办法 1 runOnUiThread 方法 ==> 相当于在主线程中跑 (初学阶段)
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            TextView textView = findViewById(R.id.t1);
                            textView.setText(httpDate);
                        }
                    });
                }
            }.start();
        }

利用Handler 

 new Thread() {
     @Override
     public void run() {
       super.run();
       getHttp();
       // 此时会报错:Only the original thread that created a view hierarchy can touch its views.
       // 2.在子线程中发送(空)消息,此时发送的是空消息
       handler.sendEmptyMessage(1);
       }
}.start();
Handler handler = new Handler(
     new Handler.Callback() {
     @Override
     // 3.由handle对象接收消息并处理,在Handler的内部类中处理
     public boolean handleMessage(@NonNull Message msg) {
             Log.e("handler 处理消息", "这是handler发送的消息,此时是空");
             textView = findViewById(R.id.t1);
             textView.setText(httpDate);
             return false;
        }
      }
    );

什么是异步任务?

逻辑上:以多线程的方式完成的功能需求

API上:指AsyncTask类

在没有 AsyncTask 前,我们可以使用 Thread+Handler 实现异步任务,而 AsyncTask 是对Thread+Handler 功能的封装,使用更简洁,效率更高效

AsyncTask 是一个抽象类,需要指定3个泛型参数

public abstract class AsyncTask<Params, Progress, Result>
  • Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型。
  • Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型。
  • Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型。

而 AsyncTask目前已被弃用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员的五大方法论

前言&#xff1a; 最近看了一篇总结程序员学习&#xff0c;晋升方法的文章&#xff0c;颇有感想&#xff0c;决定分享给大家&#xff0c;原文地址&#xff1a;给程序员的5条学习方法论 (qq.com)https://mp.weixin.qq.com/s/xVFlF9qTf9c74Emmdm0DqA 在繁忙的工作中&#xff0c;持…

如何在postman上提交文件格式的数据

如何在postman上提交文件格式的数据 今天在写一个文件上传的功能接口时&#xff0c;想用postman进行提交&#xff0c;花了些时间才找到在postman提交文件格式的数据。记录一下吧&#xff01; 1.打开postman&#xff0c;选择POST提交方式&#xff0c;然后在Params那一行的Head…

代码随想录算法训练营DAY45|C++动态规划Part7|70.爬楼梯(进阶版)、322. 零钱兑换、279.完全平方数

文章目录 70.爬楼梯&#xff08;进阶版&#xff09;322. 零钱兑换思路CPP代码 279.完全平方数思路CPP代码 70.爬楼梯&#xff08;进阶版&#xff09; 卡码网&#xff1a;57. 爬楼梯 文章讲解&#xff1a;70.爬楼梯(进阶版) 322. 零钱兑换 力扣题目链接 文章讲解&#xff1a;322…

安装英伟达nvidia p4计算卡驱动@FreeBSD14

FreeBSD也能跑cuda AI训练拉&#xff01; 在FreeBSD安装好pytorch和飞桨cpu版本后&#xff0c;尝试安装英伟达nvidia p4计算卡驱动。毕竟全靠cpu速度太慢了&#xff0c;还是GPU快啊&#xff01;在磕磕绊绊几天后&#xff0c;终于成功成功安装好nvidia p4的cuda驱动&#xff0c…

从零开始:Django项目的创建与配置指南

title: 从零开始&#xff1a;Django项目的创建与配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 后端开发 tags: DjangoWebDevPythonORMSecurityDeploymentOptimization Django简介&#xff1a; Django是一个开源的高级Python Web框架&#xff…

The Role of Subgroup Separability in Group-Fair Medical Image Classification

文章目录 The Role of Subgroup Separability in Group-Fair Medical Image Classification摘要方法实验结果 The Role of Subgroup Separability in Group-Fair Medical Image Classification 摘要 研究人员调查了深度分类器在性能上的差异。他们发现&#xff0c;分类器将个…

PHP源码_最新在线工具箱网站系统源码

项目运行截图 源码贡献 https://githubs.xyz/boot?app41 部分数据库表 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for toolbox_category -- ---------------------------- DROP TABLE IF EXISTS toolbox_category…

【网络原理】HTTP 协议的基本格式和 fiddler 抓包工具的用法

系列文章目录 【网络通信基础】网络中的常见基本概念 【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序&#xff08;万字博文&#xff09; 【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制&#xff08;CRC算法、MD5算法&#xff09; 【网络…

下载安装 VisualVM

1、下载安装 VisualVM 第1步&#xff1a;下载地址&#xff1a;https://visualvm.github.io/ 第2步&#xff1a;解压到制定位置 第3步&#xff1a;指定jdk路径 下载完成后&#xff0c;在etc文件夹下找到visualvm.conf文件&#xff0c;设置jdk路径visualvm_jdkhome"D:\ITS…

ICode国际青少年编程竞赛- Python-1级训练场-路线规划

ICode国际青少年编程竞赛- Python-1级训练场-路线规划 1、 Dev.step(3) Dev.turnLeft() Dev.step(4)2、 Dev.step(3) Dev.turnLeft() Dev.step(3) Dev.step(-6)3、 Dev.step(-2) Dev.step(4) Dev.turnLeft() Dev.step(3)4、 Dev.step(2) Spaceship.step(2) Dev.step(3)5、…

ElasticSearch教程入门到精通——第一部分(基于ELK技术栈elasticsearch 8.x新特性)

ElasticSearch教程入门到精通——第一部分&#xff08;基于ELK技术栈elasticsearch 8.x新特性&#xff09; 1. ElasticSearch安装&#xff08;略&#xff09;2. ElasticSearch基础功能2.1 索引操作2.1.1 创建索引2.1.2 Head 索引2.1.3 查询索引2.1.3.1 查询单独索引2.1.3.2 查询…

【MATLAB】GUI初步设计

MATLAB界面设计 前言一、基本步骤1.1 创建GUI文件1.2 界面设计 总结 前言 为了完成图像处理的作业&#xff0c;简直就是生活不易啊 找到一个很棒的教学视频 基于MATLAB的GUI界面设计流程讲解 一、基本步骤 1.1 创建GUI文件 由于在写博文之前我已经创建好文件了&#xff0c;…

邊緣智能2024—AI開發者峰會(5月9日)數碼港即將啟幕

隨著 AI &#xff08;人工智能&#xff09;技術的飛速發展&#xff0c;我們正迎來邊緣計算智能化與分布式AI深度融合的新時代&#xff0c;共同演繹分布式智能創新應用的壯麗篇章。"邊緣智能2024 - AI開發者峰會"將聚焦於這一前沿領域&#xff0c;探討如何通過邊緣計算…

中国发布首个汽车大模型标准

&#x1f989; AI新闻 &#x1f680; 中国发布首个汽车大模型标准 摘要&#xff1a;中国信息通信研究院于4月28日发布了国内首个汽车大模型标准&#xff0c;标志着汽车行业正式迈向“人工智能&#xff0b;”时代。该标准包含三个核心能力域&#xff1a;场景丰富度、能力支持度…

Pytorch学习笔记——环境配置安装

1、下载和配置环境 Anacodna必备&#xff08;工具包里面都包含的有&#xff0c;集成与运用科学分析的软件&#xff0c;比较方便&#xff09; 点击这个网页:Download Now | Anacondahttps://www.anaconda.com/download/success 按照教程安装&#xff08;教程可以自己在网上搜…

XY_RE复现(五)

一&#xff0c;给阿姨倒一杯卡布奇诺 是一道魔改TEA加密 给出了一些初始化&#xff0c;然后输入的flag拆分&#xff0c;两两一组&#xff0c;通过for循环放入encrypt加密函数 #include <stdio.h> #define uint32_t unsigned intvoid decrypt(uint32_t *v, uint32_t *ke…

拆单算法交易(Algorithmic Trading)

TWAP TWAP交易时间加权平均价格Time Weighted Average Price 模型&#xff0c;是把一个母单的数量平均地分配到一个交易时段上。该模型将交易时间进行均匀分割&#xff0c;并在每个分割节点上将拆分的订单进行提交。例如&#xff0c;可以将某个交易日的交易时间平均分为N 段&am…

守护数据安全: 零信任视角下的勒索病毒防范之道

前言 就在近日&#xff0c;鸿海集团旗下半导体设备大厂——京鼎精密科技股份有限公司&#xff08;以下简称“京鼎”&#xff09;遭到了黑客的入侵。黑客在京鼎官网公布信息直接威胁京鼎客户与员工&#xff0c;如果京鼎不支付赎金&#xff0c;客户资料将会被公开&#xff0c;员…

pyqt 滑动条控件QSlider

pyqt 滑动条控件QSlider 滑动条控件QSlider效果代码 滑动条控件QSlider QSlider 是 PyQt中的一个控件&#xff0c;它允许用户通过拖动滑块或点击滑块轨道上的任意位置来选择一系列值。 QSlider 有两种主要的类型&#xff1a;Qt.Horizontal&#xff08;水平滑块&#xff09;和 …

java版数据结构:深入理解栈和队列:数据结构与应用(vector,stack,queue)

目录 前言 动态数组类&#xff08;vector&#xff09; 特点&#xff1a; 应用&#xff1a; 栈&#xff08;Stack&#xff09; 栈的基础概念&#xff1a; 栈的常用方法&#xff1a; 模拟栈操作&#xff1a; 队列&#xff08;Queue&#xff09; 队列的基础概念 队列的常…