Android子线程可以更新UI

news2024/12/28 18:47:25

目录

  • 1 传统更新UI的七种方式
    • 1.1 new Handler()
    • 1.2 new Handler.Callback()
    • 1.3 new Handler().post(Runnable r)
    • 1.4 new Handler().postDelayed(Runnable r, long delayMillis)
    • 1.5 Activity.runOnUiThread(Runnable action)
    • 1.6 View.post(Runnable action)
    • 1.7 View.postDelayed(Runnable action, long delayMillis)
  • 2 在子线程中更新UI
    • 2.1 先执行一次requestLayout()再更新
    • 2.2 在子线程中调用windowManager.addView()创建一个ViewRootImpl
    • 2.3 让布局的宽高属性为固定值,并开启硬件加速
    • 2.4 使用绘制流程不走checkThread()的SurfaceView来更新
  • 3 对比分析
    • 3.1 在onCreate()中直接更新
    • 3.2 子线程休眠后再更新
    • 3.3 将TextView改成wrap_content
  • 4 测试动画

1 传统更新UI的七种方式

1.1 new Handler()

Button button = new Button(this);

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (msg.what == 1) {
          button.setText("子线程更新UI");
        }
    }
};
new Thread(new Runnable() {
    @Override
    public void run() {
        // Message和Handler均可获得msg
        // Message msg = handler.obtainMessage();
        Message msg = Message.obtain();
        msg.what = 1;
        msg.arg1 = 10;
        handler.sendMessage(msg);
    }
}).start();

1.2 new Handler.Callback()

Button button = new Button(this);

private Handler.Callback callback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
    	if (msg.what == 1) {
        	button.setText("子线程更新UI");
        }
        return true;
    }
};
Handler handler = new Handler(callback);

new Thread(new Runnable() {
    @Override
    public void run() {
    	// Message和Handler均可获得msg
        // Message msg = handler.obtainMessage();
        Message msg = Message.obtain();
        msg.what = 1;
        msg.arg1 = 11;
        handler.sendMessage(msg);
    }
}).start();

1.3 new Handler().post(Runnable r)

Button button = new Button(this);

new Thread(new Runnable() {
    @Override
    public void run() {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                button.setText("子线程更新UI");
            }
        });
    }
}).start();

1.4 new Handler().postDelayed(Runnable r, long delayMillis)

Button button = new Button(this);

new Thread(new Runnable() {
    @Override
    public void run() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                button.setText("子线程更新UI");
            }
        }, 3000);
    }
}).start();

1.5 Activity.runOnUiThread(Runnable action)

Button button = new Button(this);

new Thread(new Runnable() {
   @Override
    public void run() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
				button.setText("子线程更新UI");
            }
        });
    }
}).start();

1.6 View.post(Runnable action)

Button button = new Button(this);
        
new Thread(new Runnable() {
    @Override
    public void run() {
        button.post(new Runnable() {
            @Override
            public void run() {
				button.setText("子线程更新UI");
            }
        });
    }
}).start();

1.7 View.postDelayed(Runnable action, long delayMillis)

Button button = new Button(this);

new Thread(new Runnable() {
    @Override
    public void run() {
        button.postDelayed(new Runnable() {
            @Override
            public void run() {
				button.setText("子线程更新UI");
            }
        }, 3000);
    }
}).start();

其它异步更新UI的方法如AsyncTask、EventBus等框架还有很多。

2 在子线程中更新UI

在子线程中更新UI的方法:
1、先执行一次requestLayout()再更新
2、在子线程中调用windowManager.addView()创建一个ViewRootImpl
3、让布局的宽高属性为固定值,并开启硬件加速
4、使用绘制流程不走checkThread()的SurfaceView来更新

代码中的注释很详细,未全部贴到正文中,一定要看注释啊。

先上概览图
在这里插入图片描述

2.1 先执行一次requestLayout()再更新

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="Hello"
        android:textSize="22sp" />

</FrameLayout>
package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import kotlin.concurrent.thread

/**
 * 布局文件中TextView的宽高可随意设置,都不报错。
 *
 * 在子线程中更新UI报错的主要原因是
 * ViewRootImpl.java -> requestLayout() -> checkThread(),解决方案一:
 * 调用两次requestLayout(),即先在主线程中显示调用一次,
 * 修改UI时会自动再调用一次(隐式调用)但不会再执行。
 *
 * 方案解释:
 * 如果当前ViewRootImpl.java正在处理一个requestLayout()的任务,
 * 再次触发requestLayout()时将不会被执行,相当于第二次触发时绕开了checkThread()。
 */
class RequestBeforeActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_wrap_text)

        val textView = findViewById<TextView>(R.id.textView)

        textView.setOnClickListener {
            /*
            等价于it.requestLayout()。
            
            这行代码会在主线程执行,会执行requestLayout的整个流程,这样就完成了“申请”修改布局。
            此时,在⼦线程⽴即调⽤ textView.text = "xx.." 这个代码就会因为它已经"申请"过requestLayout了,
            就不会层层往上调⽤parent的requestLayout()⽅法,也就不会在⼦线程触发checkThread()⽅法了。
             */
            // textView.text = "Main"

            // 在主线程中执行,触发scheduleTraversals()
            it.requestLayout()
            thread {
                // 子线程修改UI会调用requestLayout()但不会执行,因此绕开了checkThread()。
                textView.text = "先执行requestLayout()再更新"
            }
        }
    }

}

2.2 在子线程中调用windowManager.addView()创建一个ViewRootImpl

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

</FrameLayout>
package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.os.Looper
import android.os.SystemClock
import android.view.WindowManager
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import kotlin.concurrent.thread

/**
 * 本例中布局文件不含子View,只有一个FrameLayout。
 *
 * 在子线程中更新UI报错的主要原因是
 * ViewRootImpl.java -> requestLayout() -> checkThread(),解决方案二:
 * 在子线程中调用windowManager.addView()创建一个ViewRootImpl,
 * 运行到checkThread()时不会进入它的 if (mThread != current)就不报错了。
 * 但ViewRootImpl中有Handler,因此调用addView()之前需要创建looper,详见代码。
 */
class AddViewWithoutMainThreadActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_view_without_main_thread)

        thread {
            Looper.prepare()

            val button = Button(this)
            button.setBackgroundColor(Color.MAGENTA)
            button.text = "在子线程中添加View:I will be added in child thread."
            button.isAllCaps = false
            button.setOnClickListener {
                (it as Button).text =
                    "${Thread.currentThread().name}, ${SystemClock.uptimeMillis()}"
            }

            windowManager.addView(button, WindowManager.LayoutParams().apply {
                this.width = WindowManager.LayoutParams.WRAP_CONTENT
                this.height = WindowManager.LayoutParams.WRAP_CONTENT
            })

            Looper.loop()
        }
    }

}

2.3 让布局的宽高属性为固定值,并开启硬件加速

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="Hello"
        android:textSize="22sp" />

</FrameLayout>
package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import kotlin.concurrent.thread

/**
 * 布局文件中TextView的宽高是固定值时不报错,是wrap_content、match_parent则会报错。
 *
 * 在子线程中更新UI报错的主要原因是
 * ViewRootImpl.java -> requestLayout() -> checkThread(),解决方案三:
 * 当布局文件中子View(TextView)的宽、高属性都是固定值时,在View中开启硬件加速(默认开启),
 * 不会触发requestLayout(),只会触发invalidate(),也绕开了checkThread()。
 *
 * 如果在AndroidManifest.xml中的<application>或<activity>标签中关闭硬件加速,
 * 则在子线程中修改UI将失败,会报checkThread()中定义的CalledFromWrongThreadException。
 *
 * 为什么会报错:
 * 在ViewGroup.java -> invalidateChild()中可以看到,是否开启硬件加速会有不同的处理逻辑。
 * 而开启硬件加速后,TextView.java -> checkForRelayout() -> invalidate()会链接到ViewRootImpl.java -> invalidate()。
 * ViewRootImpl.java -> invalidate()与ViewRootImpl.java -> requestLayout()的区别是它不会调用checkThread()。
 *
 * 结论:
 * 如果布局文件中子View(如TextView)的布局(宽高)没有发生改变(固定值),当只有内容发生改变时,
 * 在启用硬件加速的情况下是不会报错的,因为它不会触发requestLayout(),只会触发invalidate()来刷新。
 *
 * View的布局没有发生改变是指什么呢?
 * ViewRootImpl.java -> performLayout() -> measureHierarchy()会测量View树。
 * measureHierarchy()会传入一个WindowManager.LayoutParams参数,
 * 而WindowManager.java -> LayoutParams()的构造方法会先调用super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
 * measureHierarchy()内部也会判断lp.width == ViewGroup.LayoutParams.WRAP_CONTENT进而走不同的逻辑,
 * 当布局文件中子View宽高都是wrap_content或match_parent时该例子会报错。
 *
 * DecorView是最顶层View,而DecorView的测量与绘制又是由ViewRootImpl完成,
 * ViewRootImpl实现了测量performMeasure()、布局performLayout()、绘制performDraw()各流程。
 * ViewRootImpl.java -> draw()会判断是否开启硬件加速并给出相应处理。
 */
class OnClickActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_on_child_thread)

        val textView = findViewById<TextView>(R.id.textView)
        textView.setOnClickListener {
            thread {
                textView.text = "在点击事件中更新"
            }
        }
    }

}

2.4 使用绘制流程不走checkThread()的SurfaceView来更新

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <SurfaceView
        android:id="@+id/surface"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center" />

</FrameLayout>
package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Color
import android.os.Bundle
import android.os.SystemClock
import android.view.SurfaceHolder
import android.view.SurfaceView
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import java.util.Random
import kotlin.concurrent.thread

/**
 * 布局文件中SurfaceView的宽高可随意设置,都不会报错。
 *
 * 在子线程中更新UI报错的主要原因是
 * ViewRootImpl.java -> requestLayout() -> checkThread(),解决方案四:
 * Android中有⼀个控件SurfaceView,它可以通过holder获得Canvas对象,
 * 可以直接在⼦线程中更新 UI。
 * SurfaceView的绘制流程不走checkThread(),因此可以直接在子线程中更新UI。
 */
@SuppressLint("SetTextI18n")
class SampleSurfaceViewActivity : AppCompatActivity() {
    var destroyed = false

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

        val surface = findViewById<SurfaceView>(R.id.surface)

        surface.holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                thread {
                    while (!destroyed) {
                        val canvas = holder.lockCanvas()
                        val random = Random()
                        val r = random.nextInt(255)
                        val g = random.nextInt(255)
                        val b = random.nextInt(255)
                        canvas.drawColor(Color.rgb(r, g, b))
                        holder.unlockCanvasAndPost(canvas)
                        SystemClock.sleep(500)
                    }
                }
            }

            override fun surfaceChanged(
                holder: SurfaceHolder,
                format: Int,
                width: Int,
                height: Int
            ) {

            }

            override fun surfaceDestroyed(holder: SurfaceHolder) {

            }
        })
    }

}

3 对比分析

3.1 在onCreate()中直接更新

xml文件同《2.3 让布局的宽高属性为固定值,并开启硬件加速》

package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import kotlin.concurrent.thread

/**
 * 布局文件中TextView的宽高可随意设置,都不会报错。
 */
class OnChildThreadActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_on_child_thread)

        val textView = findViewById<TextView>(R.id.textView)
        /*
        子线程中修改UI成功

        ViewRootImpl在Activity处于onResume()之后才被创建的。
        在onCreate()中,此时ViewRootImpl还没有被创建,
        所以不会执行checkThread(),自然不会报错。
         */
        thread {
            textView.text = "在onCreate中直接更新"
        }
    }

}

3.2 子线程休眠后再更新

xml文件同《2.3 让布局的宽高属性为固定值,并开启硬件加速》

package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.os.Bundle
import android.os.SystemClock
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import kotlin.concurrent.thread

/**
 * 布局文件中TextView的宽高是固定值时不报错,是wrap_content、match_parent则会报错。
 *
 * 见解决方案三
 */
class ChangeWithSleepActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_on_child_thread)

        val textView = findViewById<TextView>(R.id.textView)

        /*
        当布局是非固定值时,此时进行耗时操作,则ViewRootImpl已经创建成功,
        会执行checkThread(),所以程序会崩溃。

        布局是固定值时,参考解决方案三。
         */
        thread {
            SystemClock.sleep(2000)
            textView.text = "子线程休眠后再更新"
        }
    }

}

3.3 将TextView改成wrap_content

xml文件同《2.1 先执行一次requestLayout()再更新》

package com.example.customview.layoutdrawprocess

import android.annotation.SuppressLint
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.example.customview.R
import kotlin.concurrent.thread

/**
 * 布局文件中TextView的宽高都是固定值不报错,是wrap_content、match_parent则会报错。
 *
 * 见解决方案三
 */
class WrapTextActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_wrap_text)

        val textView = findViewById<TextView>(R.id.textView)
        textView.setOnClickListener {
            /*
            子线程中修改UI 失败: android.view.ViewRootImpl$CalledFromWrongThreadException:
             */
            thread {
                textView.text = "将TextView的属性改成wrap_content"
            }
        }
    }

}

项目的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="在onCreate()中直接更新"
        android:textAllCaps="false"
        android:textSize="22sp" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="子线程休眠后再更新"
        android:textAllCaps="false"
        android:textSize="22sp" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="3.在点击事件中更新"
        android:textAllCaps="false"
        android:textSize="22sp" />

    <Button
        android:id="@+id/btn4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="将TextView改成wrap_content"
        android:textAllCaps="false"
        android:textSize="22sp" />

    <Button
        android:id="@+id/btn5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="1.先执行requestLayout()再更新"
        android:textAllCaps="false"
        android:textSize="22sp" />

    <Button
        android:id="@+id/btn6"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="2.在子线程中addView()"
        android:textAllCaps="false"
        android:textSize="22sp" />

    <Button
        android:id="@+id/btn7"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="4.使用SurfaceView"
        android:textAllCaps="false"
        android:textSize="22sp" />

</LinearLayout>

MainActivity文件

package com.example.customview

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.customview.layoutdrawprocess.AddViewWithoutMainThreadActivity
import com.example.customview.layoutdrawprocess.ChangeWithSleepActivity
import com.example.customview.layoutdrawprocess.OnChildThreadActivity
import com.example.customview.layoutdrawprocess.OnClickActivity
import com.example.customview.layoutdrawprocess.RequestBeforeActivity
import com.example.customview.layoutdrawprocess.SampleSurfaceViewActivity
import com.example.customview.layoutdrawprocess.WrapTextActivity
import kotlinx.android.synthetic.main.activity_draw_process.btn1
import kotlinx.android.synthetic.main.activity_draw_process.btn2
import kotlinx.android.synthetic.main.activity_draw_process.btn3
import kotlinx.android.synthetic.main.activity_draw_process.btn4
import kotlinx.android.synthetic.main.activity_draw_process.btn5
import kotlinx.android.synthetic.main.activity_draw_process.btn6
import kotlinx.android.synthetic.main.activity_draw_process.btn7

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

        btn1.setOnClickListener {
            startActivity(Intent(this, OnChildThreadActivity::class.java))
        }
        btn2.setOnClickListener {
            startActivity(Intent(this@MainActivity, ChangeWithSleepActivity::class.java))
        }
        btn3.setOnClickListener {
            startActivity(Intent(this@MainActivity, OnClickActivity::class.java))
        }
        btn4.setOnClickListener {
            startActivity(Intent(this@MainActivity, WrapTextActivity::class.java))
        }
        btn5.setOnClickListener {
            startActivity(Intent(this@MainActivity, RequestBeforeActivity::class.java))
        }
        btn6.setOnClickListener {
            startActivity(Intent(this@MainActivity, AddViewWithoutMainThreadActivity::class.java))
        }
        btn7.setOnClickListener {
            startActivity(Intent(this@MainActivity, SampleSurfaceViewActivity::class.java))
        }
    }

}

4 测试动画

在这里插入图片描述
参考文献:
[1] 扔物线官网

微信公众号:TechU
在这里插入图片描述

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

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

相关文章

科普丨如何让语言芯片保持稳定性能

一、勿长期高磁接触 虽然高质量的语音芯片的高声量范围相对较大&#xff0c;但是智能语音芯片一般分为不同情况使用&#xff0c;首先是内外不能混用&#xff0c;不仅如此在室内使用时也要防止长期的高磁接触&#xff0c;这样也会使语音芯片寿命折损。 二、定期清尘擦拭 专业…

计算机网络拓扑结构

什么是计算机网络拓扑结构&#xff1f; 计算机网络拓扑结构是指在网络中连接计算机和设备的方式或布局。它决定了如何在网络中传输数据&#xff0c;以及网络中的设备如何相互通信。不同的拓扑结构适用于不同的场景和需求&#xff0c;因此选择正确的拓扑结构对于网络性能和可用…

详解FreeRTOS:FreeRTOS任务恢复过程源码分析(进阶篇—4)

本篇博文讲解FreeRTOS中任务恢复过程的源代码,帮助各位更好理解恢复任务的原理和流程。 在详解FreeRTOS:FreeRTOS任务管理函数(基础篇—11)中,讲述了任务恢复函数有两个vTaskResume()和xTaskResumeFromISR(),一个是用在任务中的,一个是用在中断中的,但是基本的处理过程…

[C]二叉树的实现——喵喵成长记

宝子&#xff0c;你不点个赞吗&#xff1f;不评个论吗&#xff1f;不收个藏吗&#xff1f; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的很重要…

OpenAI将自研芯片,以解决ChatGPT算力短缺问题

10月6日&#xff0c;路透社消息&#xff0c;OpenAI将自研芯片&#xff0c;以解决ChatGPT算力短缺的问题。 据内部人士透露&#xff0c;OpenAI目前正在评估潜在的芯片厂商&#xff0c;以进行收购。 随着ChatGPT等生成式AI产品的火爆出圈&#xff0c;AI算力成为互联网领域的新一…

SpringBoot, EventListener事件监听的使用

1、背景 在开发工作中&#xff0c;会遇到一种场景&#xff0c;做完某一件事情以后&#xff0c;需要广播一些消息或者通知&#xff0c;告诉其他的模块进行一些事件处理&#xff0c;一般来说&#xff0c;可以一个一个发送请求去通知&#xff0c;但是有一种更好的方式&#xff0c;…

BLIP 小结

论文&#xff1a;Bootstrapping Language-Image Pre-training (BLIP) 代码&#xff1a;https://github.com/salesforce/BLIP 1 motivation 目前多模态模型在图片理解类任务、生成类任务表现卓越主要源于Scale up model and scale up dataset&#xff08;更大的模型&#xff…

加速attention计算的工业标准:flash attention 1和2算法的原理及实现

transformers目前大火&#xff0c;但是对于长序列来说&#xff0c;计算很慢&#xff0c;而且很耗费显存。对于transformer中的self attention计算来说&#xff0c;在时间复杂度上&#xff0c;对于每个位置&#xff0c;模型需要计算它与所有其他位置的相关性&#xff0c;这样的计…

【Unity】万人同屏高级篇, BRG Jobs实战应用, 海量物体同屏

博文开发测试环境&#xff1a; Unity&#xff1a;Unity 2022.3.10f1&#xff0c;URP 14.0.8&#xff0c;Burst 1.8.8&#xff0c;Jobs 0.70.0-preview.7&#xff0c;热更HybridCLR 4.0.6PC&#xff1a;Win11&#xff0c;CPU i7-13700KF&#xff0c;GPU 3070 8G&#xff0c;RAM…

[SWPUCTF 2022 新生赛]善哉善哉题目解析

这一题结合的东西挺多的&#xff0c;但也不是说很难。 他先给了压缩包&#xff0c;正常压缩他没有密码卡你压缩出来是一张图片 打开看没什么提示&#xff0c;就按自己的思路走先查看属性&#xff0c;一般属性是最优先查看的&#xff0c;因为他在属性藏东西的地方不多&#xff…

网络安全(黑客)从零开始的自学指南(第二章)

第二章&#xff1a;黑客入门 2.1 什么是黑客 黑客是指具有高超计算机技术和网络知识的个人或组织&#xff0c;通过技术手段侵入他人的计算机系统或网络&#xff0c;获取非法利益或破坏目标系统的行为。黑客可以分为两类&#xff1a;道德黑客&#xff08;白帽黑客&#xff0…

接扫理解.exe文件的结构原理即运行过程

爱像时间&#xff0c;永恒不变而又短暂&#xff1b;爱像流水&#xff0c;浩瀚壮阔却又普普通通。 .exe .exe文件是Windows操作系统中可执行文件的常见格式&#xff0c;它包含了计算机程序的二进制代码以及其他必要的信息&#xff0c;以便操作系统能够加载和执行该程序。下面是…

秒验:可以自定义UI的一键登录服务

一键登录如今成为越来越多移动应用的首选&#xff0c;但千篇一律的登陆界面在引发用户担忧其安全性的同时&#xff0c;也容易让用户在不同APP切换时产生误解。因此&#xff0c;由国内知名移动应用开发服务商MobTech打造的一键登录工具——秒验&#xff0c;通过允许开发者自定义…

【MVDiffusion】完美复刻场景,可多视图设计的生成式模型

文章目录 MVDiffusion1. 自回归 生成 全景图1.1 错误积累1.2 角度变换大 2. 模型结构2.1 多视图潜在扩散模型(mutil-view LDM)2.1.1 Text-conditioned generation model2.1.2 Image&text-conditioned generation model2.1.3 额外的卷积层 2.2 Correspondence-aware Attenti…

使用 TensorFlow 创建 DenseNet 121

一、说明 本篇示意DenseNet如何在tensorflow上实现&#xff0c;DenseNet与ResNet有类似的地方&#xff0c;都有层与层的“短路”方式&#xff0c;但两者对层的短路后处理有所不同&#xff0c;本文遵照原始论文的技术路线&#xff0c;完整复原了DenseNet的全部网络。 图1&#x…

评价指标篇——IOU(交并比)

什么是IoU(Intersection over Union) IoU是一种测量在特定数据集中检测相应物体准确度的一个标准。 即是产生的候选框&#xff08;candidate bound&#xff09;与原标记框&#xff08;ground truth bound&#xff09;的交叠率 即它们的交集与并集的比值。最理想情况是完全重叠…

CVE-2023-5129:libwebp开源库10分漏洞

谷歌为libwebp漏洞分配新的CVE编号&#xff0c;CVSS评分10分。 Libwebp是一个用于处理WebP格式图像编解码的开源库。9月6日&#xff0c;苹果公司安全工程和架构&#xff08;SEAR&#xff09;部门和加拿大多伦多大学研究人员在libwebp库中发现了一个0 day漏洞&#xff0c;随后&…

Linux SSH连接远程服务器(免密登录、scp和sftp传输文件)

1 SSH简介 SSH&#xff08;Secure Shell&#xff0c;安全外壳&#xff09;是一种网络安全协议&#xff0c;通过加密和认证机制实现安全的访问和文件传输等业务。传统远程登录和文件传输方式&#xff0c;例如Telnet、FTP&#xff0c;使用明文传输数据&#xff0c;存在很多的安全…

水果种植与果园监管“智慧化”,AI技术打造智慧果园视频综合解决方案

一、方案背景 我国是水果生产大国&#xff0c;果园种植面积大、产量高。由于果园的位置大都相对偏远、面积较大&#xff0c;值守的工作人员无法顾及到园区每个角落&#xff0c;因此人为偷盗、野生生物偷吃等事件时有发生&#xff0c;并且受极端天气如狂风、雷暴、骤雨等影响&a…

NOSQL Redis 数据持久化 RDB、AOF(二) 恢复

redis 执行flushall 或 flushdb 也会产生dump.rdb文件&#xff0c;但里面是空的。 注意&#xff1a;千万执行&#xff0c;不然rdb文件会被覆盖的。 dump.rdb 文件如何恢复数据 讲备份文件 dump.rdb 移动到redis安装目录并启动服务即可。 dump.rdb 自动触发 和手动触发 自…