Kotlin高仿微信-第54篇-扫一扫

news2024/9/24 1:18:16

  Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。

Kotlin高仿微信-项目实践58篇,点击查看详情

效果图:

实现代码:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <SurfaceView
        android:id="@+id/preview_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"/>

    <com.wn.wechatclientdemo.qrcodescan.ViewfinderView
        android:id="@+id/viewfinder_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</RelativeLayout>
</layout>

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/19 18:01
 * Description :
 */
class ViewfinderView : View {

    /**
     * 刷新界面的时间
     */
    private val ANIMATION_DELAY = 10L
    private val OPAQUE = 0xFF

    /**
     * 四个绿色边角对应的长度
     */
    private var ScreenRate = 0

    /**
     * 四个绿色边角对应的宽度
     */
    private val CORNER_WIDTH = 5

    /**
     * 扫描框中的中间线的宽度
     */
    private val MIDDLE_LINE_WIDTH = 6

    /**
     * 扫描框中的中间线的与扫描框左右的间隙
     */
    private val MIDDLE_LINE_PADDING = 5

    /**
     * 中间那条线每次刷新移动的距离
     */
    private val SPEEN_DISTANCE = 5

    /**
     * 手机的屏幕密度
     */
    private var density = 0f

    /**
     * 字体大小
     */
    private val TEXT_SIZE = 16

    /**
     * 字体距离扫描框下面的距离
     */
    private val TEXT_PADDING_TOP = 30

    /**
     * 画笔对象的引用
     */
    private var paint: Paint? = null

    /**
     * 中间滑动线的最顶端位置
     */
    private var slideTop = 0

    /**
     * 中间滑动线的最底端位置
     */
    private var slideBottom = 0

    /**
     * 将扫描的二维码拍下来,这里没有这个功能,暂时不考虑
     */
    private var resultBitmap: Bitmap? = null
    private var maskColor = 0
    private var resultColor = 0

    private var resultPointColor = 0
    private var possibleResultPoints: MutableCollection<ResultPoint>? = null
    private var lastPossibleResultPoints: Collection<ResultPoint>? = null

    var isFirst = false

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){
        density = context.resources.displayMetrics.density
        //将像素转换成dp
        ScreenRate = (15 * density).toInt()
        paint = Paint()
        val resources = resources
        maskColor = resources.getColor(R.color.viewfinder_mask)
        resultColor = resources.getColor(R.color.result_view)
        resultPointColor = resources.getColor(R.color.possible_result_points)
        possibleResultPoints = HashSet(5)
    }

    override fun onDraw(canvas: Canvas) {
        //中间的扫描框,你要修改扫描框的大小,去CameraManager里面修改
        val frame: Rect = CameraManager.get()?.getFramingRect() ?: return

        //初始化中间线滑动的最上边和最下边
        if (!isFirst) {
            isFirst = true
            slideTop = frame.top
            slideBottom = frame.bottom
        }

        //获取屏幕的宽和高
        val width = canvas.width
        val height = canvas.height
        paint!!.color = if (resultBitmap != null) resultColor else maskColor

        //画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面
        //扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边
        canvas.drawRect(0f, 0f, width.toFloat(), frame.top.toFloat(), paint!!)
        canvas.drawRect(
            0f, frame.top.toFloat(), frame.left.toFloat(), (frame.bottom + 1).toFloat(),
            paint!!
        )
        canvas.drawRect(
            (frame.right + 1).toFloat(),
            frame.top.toFloat(),
            width.toFloat(),
            (frame.bottom + 1).toFloat(),
            paint!!
        )
        canvas.drawRect(
            0f,
            (frame.bottom + 1).toFloat(),
            width.toFloat(),
            height.toFloat(),
            paint!!
        )
        if (resultBitmap != null) {
            // Draw the opaque result bitmap over the scanning rectangle
            paint!!.alpha = OPAQUE
            canvas.drawBitmap(resultBitmap!!, frame.left.toFloat(), frame.top.toFloat(), paint)
        } else {

            //画扫描框边上的角,总共8个部分
            paint!!.color = Color.GREEN
            canvas.drawRect(
                frame.left.toFloat(), frame.top.toFloat(), (frame.left + ScreenRate).toFloat(), (
                        frame.top + CORNER_WIDTH).toFloat(),
                paint!!
            )
            canvas.drawRect(
                frame.left.toFloat(),
                frame.top.toFloat(),
                (frame.left + CORNER_WIDTH).toFloat(),
                (frame.top
                        + ScreenRate).toFloat(),
                paint!!
            )
            canvas.drawRect(
                (frame.right - ScreenRate).toFloat(), frame.top.toFloat(), frame.right.toFloat(), (
                        frame.top + CORNER_WIDTH).toFloat(),
                paint!!
            )
            canvas.drawRect(
                (frame.right - CORNER_WIDTH).toFloat(),
                frame.top.toFloat(),
                frame.right.toFloat(),
                (frame.top
                        + ScreenRate).toFloat(),
                paint!!
            )
            canvas.drawRect(
                frame.left.toFloat(), (frame.bottom - CORNER_WIDTH).toFloat(), (frame.left
                        + ScreenRate).toFloat(), frame.bottom.toFloat(), paint!!
            )
            canvas.drawRect(
                frame.left.toFloat(), (frame.bottom - ScreenRate).toFloat(), (
                        frame.left + CORNER_WIDTH).toFloat(), frame.bottom.toFloat(), paint!!
            )
            canvas.drawRect(
                (frame.right - ScreenRate).toFloat(), (frame.bottom - CORNER_WIDTH).toFloat(),
                frame.right.toFloat(), frame.bottom.toFloat(), paint!!
            )
            canvas.drawRect(
                (frame.right - CORNER_WIDTH).toFloat(), (frame.bottom - ScreenRate).toFloat(),
                frame.right.toFloat(), frame.bottom.toFloat(), paint!!
            )


            //绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE
            slideTop += SPEEN_DISTANCE
            if (slideTop >= frame.bottom) {
                slideTop = frame.top
            }
            val lineRect = Rect()
            lineRect.left = frame.left
            lineRect.right = frame.right
            lineRect.top = slideTop
            lineRect.bottom = slideTop + 18
            canvas.drawBitmap(
                (resources.getDrawable(R.drawable.qrcode_scan_line) as BitmapDrawable).bitmap,
                null,
                lineRect,
                paint
            )

            //画扫描框下面的字
            paint!!.color = Color.WHITE
            paint!!.textSize = TEXT_SIZE * density
            paint!!.alpha = 0x40
            paint!!.typeface = Typeface.create("System", Typeface.BOLD)
            val text = resources.getString(R.string.scan_text)
            val textWidth = paint!!.measureText(text)
            canvas.drawText(
                text, (width - textWidth) / 2, frame.bottom + TEXT_PADDING_TOP.toFloat() * density,
                paint!!
            )
            val currentPossible: Collection<ResultPoint>? = possibleResultPoints
            val currentLast = lastPossibleResultPoints
            if (currentPossible!!.isEmpty()) {
                lastPossibleResultPoints = null
            } else {
                possibleResultPoints = HashSet(5)
                lastPossibleResultPoints = currentPossible
                paint!!.alpha = OPAQUE
                paint!!.color = resultPointColor
                for (point in currentPossible) {
                    canvas.drawCircle(
                        frame.left + point.x, frame.top
                                + point.y, 6.0f, paint!!
                    )
                }
            }
            if (currentLast != null) {
                paint!!.alpha = OPAQUE / 2
                paint!!.color = resultPointColor
                for (point in currentLast) {
                    canvas.drawCircle(
                        frame.left + point.x, frame.top
                                + point.y, 3.0f, paint!!
                    )
                }
            }

            //只刷新扫描框的内容,其他地方不刷新
            postInvalidateDelayed(
                ANIMATION_DELAY, frame.left, frame.top,
                frame.right, frame.bottom
            )
        }
    }

    fun drawViewfinder() {
        resultBitmap = null
        invalidate()
    }

    /**
     * Draw a bitmap with the result points highlighted instead of the live
     * scanning display.
     *
     * @param barcode
     * An image of the decoded barcode.
     */
    fun drawResultBitmap(barcode: Bitmap?) {
        resultBitmap = barcode
        invalidate()
    }

    fun addPossibleResultPoint(point: ResultPoint) {
        possibleResultPoints!!.add(point)
    }

}

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/19 18:10
 * Description : 扫一扫
 */
class QRCodeScanFragment : BaseDataBindingFragment<QrcodeActivityCaptureBinding>(), Callback{

    private var handler: CaptureActivityHandler? = null
    private var viewfinderView: ViewfinderView? = null
    private var hasPermission = false
    private var hasSurface = false
    private var decodeFormats: Vector<BarcodeFormat>? = null
    private var characterSet: String? = null
    private var inactivityTimer: InactivityTimer? = null
    private var mediaPlayer: MediaPlayer? = null
    private var playBeep = false
    private val BEEP_VOLUME = 0.10f
    private var vibrate = false

    private val REQUEST_CODE = 100
    private val REQUEST_CAMERA_CODE = 101
    private val PARSE_BARCODE_SUC = 300
    private val PARSE_BARCODE_FAIL = 303
    private var mProgress: ProgressDialog? = null
    private var photo_path: String? = null
    private var scanBitmap: Bitmap? = null
    private var navCollection : NavController? = null

    override fun getLayoutRes() = R.layout.qrcode_activity_capture

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        TagUtils.d("扫描 onViewCreated ")
        navCollection = findNavController()
        handlePermission()
    }

    fun init() {
        TagUtils.d("扫描 init ")
        CameraManager.init(requireActivity())
        viewfinderView = viewfinder_view
        hasSurface = false
        inactivityTimer = InactivityTimer(requireActivity())
    }

    companion object {
        fun onOpen(activity: Activity){
            var intent = Intent(activity, QRCodeScanFragment::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            WcApp.getContext().startActivity(intent)
        }
    }

    private fun handlePermission() {
        if(ContextCompat.checkSelfPermission(requireActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
            requestPermissions(arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_CODE)
        } else {
            hasPermission = true
            init()
        }
    }

    override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if(requestCode == REQUEST_CAMERA_CODE && grantResults != null && grantResults.size > 0){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                TagUtils.d("扫描 onRequestPermissionsResult ")
                hasPermission = true
                init()
                val surfaceHolder = preview_view.holder
                initCamera(surfaceHolder)
            }
        }
    }

//    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
//        /**
//         * 此方法用于初始化菜单,其中menu参数就是即将要显示的Menu实例。 返回true则显示该menu,false 则不显示;
//         * (只会在第一次初始化菜单时调用) Inflate the menu; this adds items to the action bar
//         * if it is present.
//         */
//        menuInflater.inflate(R.menu.qrcode_activity_main, menu)
//        return true
//    }

//    override fun onOptionsItemSelected(item: MenuItem): Boolean {
//        /**
//         * 菜单项被点击时调用,也就是菜单项的监听方法。
//         * 通过这几个方法,可以得知,对于Activity,同一时间只能显示和监听一个Menu 对象。 TODO Auto-generated
//         * method stub
//         */
//        when (item.itemId) {
//            R.id.menu_settings -> {
//                //打开手机中的相册
//                val innerIntent =
//                    Intent(Intent.ACTION_GET_CONTENT) //"android.intent.action.GET_CONTENT"
//                innerIntent.type = "image/*"
//                val wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片")
//                this.startActivityForResult(wrapperIntent, REQUEST_CODE)
//            }
//        }
//        return super.onOptionsItemSelected(item)
//    }

    private val mHandler: Handler = MyHandler(this)

    inner class MyHandler(activity: QRCodeScanFragment) : Handler() {
        private val activityReference: WeakReference<QRCodeScanFragment>
        override fun handleMessage(msg: Message) {
            val activity = activityReference.get()
            activity!!.mProgress!!.dismiss()
            when (msg.what) {
                PARSE_BARCODE_SUC -> activity.onResultHandler(
                    msg.obj as String,
                    activity.scanBitmap
                )
                PARSE_BARCODE_FAIL -> Toast.makeText(requireActivity(),msg.obj as String,Toast.LENGTH_LONG).show()
            }
            super.handleMessage(msg)
        }

        init {
            activityReference = WeakReference(activity)
        }
    }

    /*override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == RESULT_OK) {
            when (requestCode) {
                REQUEST_CODE -> {
                    //获取选中图片的路径
                    val cursor = contentResolver.query(data.data!!, null, null, null, null)
                    if (cursor!!.moveToFirst()) {
                        photo_path =
                            cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
                    }
                    cursor.close()
                    mProgress = ProgressDialog(this@MipcaActivityCapture)
                    mProgress!!.setMessage("正在扫描...")
                    mProgress!!.setCancelable(false)
                    mProgress!!.show()
                    Thread {
                        val result = scanningImage(photo_path)
                        if (result != null) {
                            val m = mHandler.obtainMessage()
                            m.what = PARSE_BARCODE_SUC
                            m.obj = result.text
                            mHandler.sendMessage(m)
                        } else {
                            val m = mHandler.obtainMessage()
                            m.what = PARSE_BARCODE_FAIL
                            m.obj = "Scan failed!"
                            mHandler.sendMessage(m)
                        }
                    }.start()
                }
            }
        }
    }*/

    /**
     * 扫描二维码图片的方法
     * @param path
     * @return
     */
    fun scanningImage(path: String?): Result? {
        if (TextUtils.isEmpty(path)) {
            return null
        }
        val hints = Hashtable<DecodeHintType, String?>()
        hints[DecodeHintType.CHARACTER_SET] = "UTF8" //设置二维码内容的编码
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true // 先获取原大小
        scanBitmap = BitmapFactory.decodeFile(path, options)
        options.inJustDecodeBounds = false // 获取新的大小
        var sampleSize = (options.outHeight / 200f).toInt()
        if (sampleSize <= 0) sampleSize = 1
        options.inSampleSize = sampleSize
        scanBitmap = BitmapFactory.decodeFile(path, options)
        val source = RGBLuminanceSource(scanBitmap!!)
        val bitmap1 = BinaryBitmap(HybridBinarizer(source))
        val reader = QRCodeReader()
        try {
            return reader.decode(bitmap1, hints)
        } catch (e: NotFoundException) {
            e.printStackTrace()
        } catch (e: ChecksumException) {
            e.printStackTrace()
        } catch (e: FormatException) {
            e.printStackTrace()
        }
        return null
    }


    override fun onResume() {
        super.onResume()
        TagUtils.d("扫描 onResume ${hasSurface} , ${hasPermission}")
        //没有权限直接返回
        if(!hasPermission){
            return
        }
        //val surfaceView = findViewById<View>(R.id.preview_view) as SurfaceView
        val surfaceView = preview_view
        val surfaceHolder = surfaceView.holder
        if (hasSurface) {
            initCamera(surfaceHolder)
        } else {
            surfaceHolder.addCallback(this)
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
        }
        decodeFormats = null
        characterSet = null
        playBeep = true
        val audioService = requireActivity().getSystemService(AUDIO_SERVICE) as AudioManager
        if (audioService.ringerMode != AudioManager.RINGER_MODE_NORMAL) {
            playBeep = false
        }
        initBeepSound()
        vibrate = true
    }

    override fun onPause() {
        super.onPause()
        TagUtils.d("扫描 onPause ${hasPermission}")
        if(!hasPermission){
            return
        }
        handler?.quitSynchronously()
        handler = null
        CameraManager.get()?.closeDriver()
    }

    override fun onDestroy() {
        TagUtils.d("扫描 onDestroy ")
        inactivityTimer?.shutdown()
        super.onDestroy()
    }

    /**
     * 处理扫描结果
     * @param result
     * @param barcode
     */
    fun handleDecode(result: Result, barcode: Bitmap?) {
        inactivityTimer!!.onActivity()
        playBeepSoundAndVibrate()
        val resultString = result.text
        onResultHandler(resultString, barcode)
    }

    /**
     * 跳转到上一个页面
     * @param resultString
     * @param bitmap
     */
    private fun onResultHandler(resultString: String, bitmap: Bitmap?) {
        if (TextUtils.isEmpty(resultString)) {
            Toast.makeText(requireActivity(), "Scan failed!", Toast.LENGTH_SHORT).show()
            return
        }
        TagUtils.d("二维码返回字符串:${resultString}")
        Navigation.findNavController(preview_view).popBackStack()
        if(resultString.startsWith(CommonUtils.QRCommon.QR_RECEIVE_CODE)){
            //向个人付款
            TagUtils.d("跳转向个人付款 ")
            var tempResult = resultString.substring(CommonUtils.QRCommon.QR_RECEIVE_CODE.length, resultString.length)
            var toUser = tempResult.split(":")[1]
            var balance = tempResult.split(":")[0]
            var bundle = bundleOf(CommonUtils.QRCommon.BALANCE to balance.toFloat(), CommonUtils.QRCommon.TO_USER to toUser)
            navCollection?.navigate(R.id.action_personal_payment, bundle)
        } else if(resultString.startsWith(CommonUtils.QRCommon.QR_PAYMENT_CODE)){
            //向商家付款
            var toUser = resultString.substring(CommonUtils.QRCommon.QR_PAYMENT_CODE.length, resultString.length)
            TagUtils.d("跳转向商家付款 ${toUser}")
            var bundle = bundleOf(CommonUtils.QRCommon.TO_USER to toUser)
            navCollection?.navigate(R.id.action_merchant_payment, bundle)
        } else if(resultString.startsWith("http") || resultString.startsWith("https")){
            //跳转到网站
            CommonUtils.Base.goWebsite(resultString)
        } else if(resultString.startsWith(CommonUtils.QRCommon.QR_ADD_FRIEND)){
            var userInfo = resultString.substring(CommonUtils.QRCommon.QR_ADD_FRIEND.length, resultString.length)
            //account+"###"+it.nickName+"###"+it.avatar
            var userInfos = userInfo.split("###")
            var toUser = userInfos[0]
            var nickName = userInfos[1]
            var avatar = userInfos[2]

            var contactsBean = ContactsRepository.getContactsLocalAsync(toUser)
            if(contactsBean != null){
                //如果是好友,直接打开聊天
                var bundle = bundleOf(ChatFragment.USER_ID to toUser)
                navCollection?.navigate(R.id.nav_chat, bundle)
            } else {
                var userBean = UserBean(toUser)
                userBean.avatar = avatar
                userBean.nickName = nickName
                //跳转到添加好友页面
                val bundle = bundleOf("userbean" to userBean)
                navCollection?.navigate(R.id.action_contacts_search_friends_details, bundle)
            }
        } else {
            TagUtils.d("跳转空")
        }
    }

    private fun initCamera(surfaceHolder: SurfaceHolder) {
        TagUtils.d("扫描 initCamera ")

        try {
            CameraManager.get()?.openDriver(surfaceHolder)
        } catch (ioe: IOException) {
            return
        } catch (e: RuntimeException) {
            return
        }
        if (handler == null) {
            handler = CaptureActivityHandler( this, decodeFormats, characterSet )
        }
    }

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

    override fun surfaceCreated(holder: SurfaceHolder) {
        TagUtils.d("扫描 surfaceCreated ")
        if (!hasSurface) {
            hasSurface = true
            initCamera(holder)
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        hasSurface = false
    }

    fun getViewfinderView(): ViewfinderView? {
        return viewfinderView
    }

    fun getHandler(): Handler? {
        return handler
    }

    fun drawViewfinder() {
        viewfinderView!!.drawViewfinder()
    }

    private fun initBeepSound() {
        if (playBeep && mediaPlayer == null) {
            // The volume on STREAM_SYSTEM is not adjustable, and users found it
            // too loud,
            // so we now play on the music stream.
            requireActivity().volumeControlStream = AudioManager.STREAM_MUSIC
            mediaPlayer = MediaPlayer()
            mediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC)
            mediaPlayer!!.setOnCompletionListener(beepListener)
            val file = resources.openRawResourceFd(R.raw.beep)
            try {
                mediaPlayer!!.setDataSource(
                    file.fileDescriptor,
                    file.startOffset, file.length
                )
                file.close()
                mediaPlayer!!.setVolume(BEEP_VOLUME, BEEP_VOLUME)
                mediaPlayer!!.prepare()
            } catch (e: IOException) {
                mediaPlayer = null
            }
        }
    }

    private val VIBRATE_DURATION = 200L

    private fun playBeepSoundAndVibrate() {
        if (playBeep && mediaPlayer != null) {
            mediaPlayer!!.start()
        }
        if (vibrate) {
            val vibrator = requireActivity().getSystemService(VIBRATOR_SERVICE) as Vibrator
            vibrator.vibrate(VIBRATE_DURATION)
        }
    }

    /**
     * When the beep has finished playing, rewind to queue up another one.
     */
    private val beepListener =
        OnCompletionListener { mediaPlayer -> mediaPlayer.seekTo(0) }

}

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

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

相关文章

安卓APP源码和报告——音乐播放器

课 程 设 计 报 告 院 系&#xff1a;专 业&#xff1a;题 目&#xff1a;科 目&#xff1a;学 生&#xff1a;指导教师&#xff1a;完成时间&#xff1a;目 录 1. 引言1 1.1 目的1 1.2 背景1 2. 需求分析1 3. 系统设计1 3.1总体设计1 3.2功能设计1 4. 系统开发2 4.1…

秋招经验分享:最终我还是选择了百度

点击进入—>3D视觉工坊学习交流群自我介绍感谢工坊的邀请&#xff0c;来做这次秋招经验的分享。本科和研究生都是自动化专业&#xff0c;研究生期间做移动机器人的定位方向&#xff0c;现在是百度的一名算法工程师&#xff0c;很喜欢现在的工作环境和氛围&#xff0c;强烈推…

【LeetCode每日一题】——72.编辑距离

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 字符串 二【题目难度】 困难 三【题目编号】 72.编辑距离 四【题目描述】 给你两个单词 word…

【Linux】常用的Linux命令(初学者必读)

一、学习Linux的原因 开源&#xff0c;免费系统迭代更新系统性能稳定安全性高多任务&#xff0c;多用户耗资源少内核小应用领域广泛使用及入门容易 二、Linux常用的命令 我使用的Linux环境是在 腾讯云服务器上的Centos 7和 Xshell。 下面我把常用的一些命令分成了几个部分&am…

VPS8505 微功率隔离电源专用芯片2.3-6VIN/24V/1A 功率管 替代金升阳模块

文章目录 前言一、是什么&#xff1f;二、特点三、应用领域四、简化应用五、引脚及功能六、参数测试电路 总结前言 隔离电源市场&#xff0c;一直被塑封模块产品占领&#xff0c;之前国内无专业 做隔离芯片的厂家&#xff0c;市场以模块厂进口芯片方案为主&#xff1b;…

深入 Java 线程池:从设计思想到源码解读

为什么需要线程池 我们知道创建线程的常用方式就是 new Thread() &#xff0c;而每一次 new Thread() 都会重新创建一个线程&#xff0c;而线程的创建和销毁都需要耗时的&#xff0c;不仅会消耗系统资源&#xff0c;还会降低系统的稳定性。在 jdk1.5 的 JUC 包中有一个 Execut…

从实用角度浅析前端全链路质量监控中台技术方案

大厂技术 高级前端 Node进阶点击上方 程序员成长指北&#xff0c;关注公众号回复1&#xff0c;加入高级Node交流群感谢作者陈煮酒的投稿。前言无论是纯前端业务还是服务端业务&#xff0c;线上质量的保障都是我们的底线要求&#xff0c;也是我们日常需要花费很多精力关注的环…

【大数据入门核心技术-Zookeeper】(五)ZooKeeper集群搭建

目录 一、准备工作 1、集群分布 2、创建数据目录 3、下载安装包 二、解压安装 1、解压 2、修改配置文件zoo.cfg 3、添加myid配置 4、分发zk文件夹和分别新建myid 5、配置环境变量 6、三台机器分别启动zookeeper服务 一、准备工作 1、集群分布 服务器IP主机名myid的…

有损压缩与无损压缩

有损压缩与无损压缩数据压缩有损压缩无损压缩有损压缩与无损压缩的区别Which One to Use?Final Words有损压缩、无损压缩&#xff08;图片、音频、视频&#xff09;图片文件格式音频文件格式视频文件格式数据压缩 数据压缩&#xff08;Data Compression&#xff09;是减小任何…

教你6招轻松搞定 网站被木马反复篡改

提到网络被恶意篡改&#xff0c;应该让很多做了百度竞价的企业官网怀恨已久了吧&#xff1f;这类行为的目的就是通过这些受害网站获得排名并跳转到违法网站&#xff0c;达到不法的目的。对于企业来说不但损失了百度竞价的费用&#xff0c;还对企业形象造成很大的影响。甚至直接…

【Flink】检查点算法实现原理之检查点分界线

一 检查点的实现算法 一种简单的想法&#xff08;同步的思想&#xff09; 暂停应用保存状态到检查点再重新恢复应用&#xff08;Spark Streaming&#xff09; Flink 的改进实现&#xff08;异步的思想&#xff09; 基于 Chandy-Lamport 算法的分布式快照算法将检查点的保存和数…

20221203使用python3处理Google翻译英文SRT格式字幕

20221203使用python3处理Google翻译英文SRT格式字幕 1、暂时不处理UNICODE编码的TXT&#xff0c;本例以ANSI编码的TXT为准。 2、将来处理自动处理目录中的全部TXT文件。&#xff08;甚至递归处理子目录中的TXT文件&#xff09; 源码&#xff1a; #f_pathrC:\Users\Admin\Desk…

如何解hard算法题?

如何解困难题&#xff1f;前言一、案例二、困难题拆解1、自己的思路2、官方的思路3、源码Javagolang总结参考文献前言 上一篇文章写bitCount源码解析&#xff0c;对困难题有一些抽象的理解。 困难题就是一个个简单的知识点组成&#xff0c;加上其内在的逻辑联系。所以一个困难…

S2SH志愿者捐赠管理系统|捐助计算机毕业论文Java项目源码下载

&#x1f496;&#x1f496;更多项目资源&#xff0c;最下方联系我们✨✨✨✨✨✨ 目录 Java项目介绍 资料获取 Java项目介绍 《基于S2SH实现的志愿者捐赠管理系统》该项目采用技术jsp、strust2、Spring、hibernate、tomcat服务器、mysql数据库 &#xff0c;项目含有源码、…

02、数据卷(Data Volumes)以及dockefile详解

目录 1、Docker 数据管理 2、数据卷(Data Volumes) 3、数据卷容器 4、dockerfile 5、dockerfile基本结构 6、docker使用Dockerfile创建jdk容器 启动虚拟机&#xff0c;进入CentOS 7、dockerfile实践经验 1、Docker 数据管理 在生产环境中使用 Docker &#xff0c;往往需…

混合动力电动车优化调度与建模(发动机,电机,电池组等组件建模)(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f4dd;目前更新&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;电力系统相关知识&#xff0c;期刊论文&…

6-4布线问题(分支限界)

6-4布线问题&#xff08;分支限界&#xff09; 一、问题描述 印刷电路板将布线区域划分成m*n个方格阵列,如图(1)所示。 精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线方案。 在布线时,电路只能沿直线或直角布线,如图(2)所示。 为了避免线路相交&#xf…

C语言第十二课(下):操作符详解【逗号表达式、下标引用、函数调用、结构成员操作符与操作符属性】

目录 前言&#xff1a; 一、逗号表达式&#xff08;exp1&#xff0c;exp2&#xff0c;exp3&#xff0c;...&#xff0c;expN&#xff09;&#xff1a; 二、下标引用、函数调用和结构成员[ ]、( )、. 、->&#xff1a; 1.下标引用操作符[ ]&#xff1a; 2.函数调用操作符( …

Tomcat过时了?别多想,很多公司还是在用的。这份Tomcat架构详解,真的颠覆你的认知

Tomcat 不但没有过时&#xff0c;Spring Boot 还给 Tomcat 第二春了。 微服务的兴起&#xff0c;Tomcat 针对很多应用已经做成 embedded 模式了&#xff0c;Tomcat 本身是容器&#xff0c;Tomcat 的出现就是为了解决但是 EJB 和 Weblogic&#xff0c;JBoss 这种大而全的大象导致…

C++ OpenCV【视频合并:多个图像拼接在一张图像】

提示&#xff1a;本文中视频拼接指的是将多张图像按空间合并在一张图像上&#xff0c;而不是将多张图像按时间顺序拼接成一个多帧片段。 文章目录 前言 一、OpenCV知识点 1.OpenCV裁剪矩形区域赋值 2.OpenCV将Mat粘贴到指定位置 二、程序样例 1.程序源码 2.运行结果 前言 C版…