Kotlin高仿微信-第11篇-单聊-语音

news/2025/1/14 9:42:43/

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

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

效果图:

详细的聊天功能请查看Kotlin高仿微信-第8篇-单聊,这里是提示文本功能的部分实现。

实现代码:

我的语言布局:

<LinearLayoutandroid:id="@+id/chat_item_me_voice_layout"app:layout_constraintEnd_toStartOf="@+id/chat_item_me_avatar"app:layout_constraintTop_toTopOf="@+id/chat_item_me_avatar"app:layout_constraintBottom_toBottomOf="@+id/chat_item_me_avatar"android:layout_width="120dp"android:layout_height="40dp"android:layout_marginEnd="10dp"android:background="@drawable/wc_base_voice_green_normal"android:gravity="center"android:visibility="visible"android:orientation="horizontal"><androidx.appcompat.widget.AppCompatTextViewandroid:id="@+id/chat_item_me_voice_second"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="1'"android:layout_marginRight="4dp"android:textSize="20sp"/><ImageViewandroid:id="@+id/chat_item_me_voice"android:layout_width="22dp"android:layout_height="22dp"android:src="@drawable/wc_chat_me_volume_2"android:visibility="visible"/></LinearLayout>

好友的语音布局:

<LinearLayoutandroid:id="@+id/chat_item_other_voice_layout"app:layout_constraintStart_toEndOf="@+id/chat_item_other_avatar"app:layout_constraintTop_toTopOf="@+id/chat_item_other_avatar"app:layout_constraintBottom_toBottomOf="@+id/chat_item_other_avatar"android:layout_width="120dp"android:layout_height="40dp"android:layout_marginStart="10dp"android:gravity="center"android:visibility="visible"android:background="@drawable/wc_base_voice_green_normal"android:orientation="horizontal"><ImageViewandroid:id="@+id/chat_item_other_voice"android:layout_width="22dp"android:layout_height="22dp"android:src="@drawable/wc_chat_other_volume_2"android:visibility="visible"/><androidx.appcompat.widget.AppCompatTextViewandroid:id="@+id/chat_item_other_voice_second"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="1'"android:layout_marginLeft="4dp"android:textSize="20sp"/></LinearLayout>
<com.wn.wechatclientdemo.view.ChatRecordButtonandroid:id="@+id/chat_record_btn"android:layout_width="0dp"android:layout_height="38dp"android:visibility="gone"android:layout_marginHorizontal="10dp"android:background="@drawable/wc_chat_voice_selector"app:layout_constraintStart_toEndOf="@+id/chat_audio"app:layout_constraintEnd_toStartOf="@+id/chat_emoji"app:layout_constraintTop_toTopOf="@+id/chat_audio"app:layout_constraintBottom_toBottomOf="@+id/chat_audio"android:text="按住说话"/>

/*** Author : wangning* Email : maoning20080809@163.com* Date : 2022/5/4 17:36* Description : 聊天语言按钮*/
class ChatRecordButton : AppCompatButton {constructor(context: Context) : super(context)constructor(context: Context, attributeSet: AttributeSet) :super(context, attributeSet)constructor(context: Context, attributeSet: AttributeSet, defStyle : Int) : super(context, attributeSet, defStyle)private var mFile : String = ""private var mFileMp3 : String = ""private var finishedListener: OnFinishedRecordListener? = null/*** 最短录音时间*/private val MIN_INTERVAL_TIME = 1000/*** 最长录音时间*/private val MAX_INTERVAL_TIME = 1000 * 60private var view: View? = nullprivate var mStateTV: TextView? = nullprivate var mStateIV: ImageView? = nullcompanion object var mRecorder: MediaRecorder? = nullprivate val mThread: ObtainDecibelThread? = nullprivate var volumeHandler: Handler? = nullprivate var y1 : Float = 0fprivate var anim: AnimationDrawable? = nullfun setOnFinishedRecordListener(listener: OnFinishedRecordListener?) {finishedListener = listener}private var startTime: Long = 0private var recordDialog: Dialog? = nullprivate val res = intArrayOf(R.drawable.wc_chat_volume_0,R.drawable.wc_chat_volume_1,R.drawable.wc_chat_volume_2,R.drawable.wc_chat_volume_3,R.drawable.wc_chat_volume_4,R.drawable.wc_chat_volume_5,R.drawable.wc_chat_volume_6,R.drawable.wc_chat_volume_7,R.drawable.wc_chat_volume_8)//private var audioRecordTool: AudioRecordTool? = nullinit {volumeHandler = object : Handler() {override fun handleMessage(msg: Message) {if (msg.what == -100) {stopRecording()recordDialog!!.dismiss()} else if (msg.what != -1) {mStateIV!!.setImageResource(res.get(msg.what))}}}}override fun onTouchEvent(event: MotionEvent?): Boolean {val action = event!!.actiony1 = event.yif (mStateTV != null && mStateIV != null && y1 < 0) {mStateTV?.text = "松开手指,取消发送"mStateIV?.setImageDrawable(resources.getDrawable(R.drawable.wc_chat_volume_cancel))} else if (mStateTV != null) {mStateTV?.text = "手指上滑,取消发送"}when (action) {MotionEvent.ACTION_DOWN -> {text = "松开发送"initDialogAndStartRecord()}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {this.text = "按住录音"if (y1 >= 0 && System.currentTimeMillis() - startTime <= MAX_INTERVAL_TIME) {TagUtils.d("结束录音:")finishRecord()} else if (y1 < 0) {  //当手指向上滑,会cancelcancelRecord()}}}return true}/*** 初始化录音对话框 并 开始录音*/private fun initDialogAndStartRecord() {startTime = System.currentTimeMillis()recordDialog = Dialog(context, R.style.like_toast_dialog_style)// view = new ImageView(getContext());view = inflate(context, R.layout.wc_chat_dialog_record, null)mStateIV = view?.findViewById<ImageView>(R.id.rc_audio_state_image)mStateTV = view?.findViewById<TextView>(R.id.rc_audio_state_text)mStateIV?.setImageDrawable(resources.getDrawable(R.drawable.anim_mic))anim = mStateIV?.getDrawable() as AnimationDrawableanim?.start()mStateIV?.setVisibility(VISIBLE)//mStateIV.setImageResource(R.drawable.ic_volume_1);mStateTV?.setVisibility(VISIBLE)mStateTV?.setText("手指上滑,取消发送")recordDialog?.setContentView(view!!, LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT))recordDialog?.setOnDismissListener(onDismiss)val lp = recordDialog?.getWindow()!!.attributeslp.gravity = Gravity.CENTERstartRecording()recordDialog?.show()}/*** 放开手指,结束录音处理*/private fun finishRecord() {val intervalTime: Long = System.currentTimeMillis() - startTimeif (intervalTime < MIN_INTERVAL_TIME) {TagUtils.d("录音时间太短")volumeHandler!!.sendEmptyMessageDelayed(-100, 500)//view.setBackgroundResource(R.drawable.ic_voice_cancel);mStateIV!!.setImageDrawable(resources.getDrawable(R.drawable.wc_chat_volume_wraning))mStateTV!!.text = "录音时间太短"anim!!.stop()val file = File(mFile!!)file.delete()return} else {stopRecording()recordDialog!!.dismiss()}TagUtils.d("录音完成的路径:$mFile")val mediaPlayer = MediaPlayer()try {mediaPlayer.setDataSource(mFile)mediaPlayer.prepare()mediaPlayer.durationTagUtils.d("获取到的时长:" + mediaPlayer.duration / 1000)} catch (e: Exception) {}//if (finishedListener != null) finishedListener!!.onFinishedRecord( mFile, mediaPlayer.duration / 1000)//删除原文件TagUtils.d("amr录音保存路径:${mFile}")File(mFile).delete()/*TagUtils.d("pcm录音保存路径:${audioRecordTool?.pcmFileName}")audioRecordTool?.deletePcmFile()//最终使用的是wav录音文件,音质非常的好mFile = audioRecordTool?.wavFileName!!TagUtils.d("wav录音保存路径:${audioRecordTool?.wavFileName!!}")*/TagUtils.d("mp3录音保存路径:${mFileMp3}")if (finishedListener != null) finishedListener!!.onFinishedRecord( mFileMp3, mediaPlayer.duration / 1000)}/*** 取消录音对话框和停止录音*/fun cancelRecord() {stopRecording()recordDialog!!.dismiss()val file = File(mFile)file.delete()LameMp3Manager.instance.cancelRecorder()var mp3File = File(mFileMp3)mp3File.delete()}/*** 执行录音操作*/private fun startRecording() {if(ContextCompat.checkSelfPermission(WcApp.getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){mFile = FileUtils.getBaseFile("voice_" + System.currentTimeMillis() + ".amr").absolutePathmFileMp3 = FileUtils.getBaseFile("voice_" + System.currentTimeMillis() + ".mp3").absolutePath} else {ToastUtils.makeText(R.string.wc_permission_tip_record)return}//使用MP3文件代替wav,因为mp3语音清晰,占用空间小LameMp3Manager.instance.startRecorder(mFileMp3)/*audioRecordTool = AudioRecordTool()//初始化audioRecordTool?.createAudioRecord()audioRecordTool?.start()*/if (mRecorder != null) {mRecorder?.reset()} else {mRecorder = MediaRecorder()}mRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)mRecorder?.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB)mRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)mRecorder?.setOutputFile(mFile)try {mRecorder?.prepare()mRecorder?.start()} catch (e: Exception) {TagUtils.d("preparestart异常,重新开始录音:$e")e.printStackTrace()mRecorder?.release()mRecorder = nullstartRecording()}}private fun stopRecording() {//audioRecordTool?.stop()LameMp3Manager.instance.stopRecorder()if (mThread != null) {mThread.exit()//mThread = null}if (mRecorder != null) {try {mRecorder?.stop() //停止时没有prepare,就会报stop failedmRecorder?.reset()mRecorder?.release()mRecorder = null} catch (pE: RuntimeException) {pE.printStackTrace()} finally {if (recordDialog!!.isShowing) {recordDialog!!.dismiss()}}}}private class ObtainDecibelThread(val obj: ChatRecordButton) : Thread() {@Volatileprivate var running = truefun exit() {running = false}override fun run() {TagUtils.d("检测到的分贝001:")while (running) {if (obj.mRecorder == null || !running) {break}// int x = recorder.getMaxAmplitude(); //振幅val db: Int = obj.mRecorder!!.getMaxAmplitude() / 600TagUtils.d("检测到的分贝002:$")if (db != 0 && obj.y1 >= 0) {val f = (db / 5)if (f == 0) obj.volumeHandler?.sendEmptyMessage(0) else if (f == 1) obj.volumeHandler?.sendEmptyMessage(1) else if (f == 2) obj.volumeHandler?.sendEmptyMessage(2) else if (f == 3) obj.volumeHandler?.sendEmptyMessage(3) else if (f == 4) obj.volumeHandler?.sendEmptyMessage(4) else if (f == 5) obj.volumeHandler?.sendEmptyMessage(5) else if (f == 6) obj.volumeHandler?.sendEmptyMessage(6) else obj.volumeHandler?.sendEmptyMessage(7)}obj.volumeHandler?.sendEmptyMessage(-1)if (System.currentTimeMillis() - obj.startTime > 20000) {obj.finishRecord()}try {sleep(200)} catch (e: InterruptedException) {e.printStackTrace()}}}}private val onDismiss = DialogInterface.OnDismissListener { stopRecording() }interface OnFinishedRecordListener{fun onFinishedRecord(audioPath : String, time : Int)}}

//录音完成回调
chat_record_btn.setOnFinishedRecordListener(object : ChatRecordButton.OnFinishedRecordListener{override fun onFinishedRecord(audioPath: String, time: Int) {chat_content.isFocusable = falseSoftInputUtils.hideSoftInput(chat_record_btn)AddFileListener.sendFile(ChatBean.CONTENT_TYPE_VOICE, audioPath, toUserId, time)}
})

/*** 发送图片、小视频、语音* @param fileType Int* @param picPath String* @param toUserID String*/
fun sendFile(fileType: Int, filePath : String, toUserId : String, time: Int) {CoroutineScope(Dispatchers.IO).launch {//语音、小视频多少秒val toId: String = BaseUtils.getChatId(toUserId) + "/Smack"var resultFilePath = ""if(TextUtils.isEmpty(filePath)){return@launch}if(!File(filePath).exists()){return@launch}var second = timeif(fileType == ChatBean.CONTENT_TYPE_VOICE){second = time} else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){second = CommonUtils.Media.getMediaTime(filePath, fileType)}//先刷新页面,再慢慢上传文件var chatBean = processSendChatBean(toUserId, fileType, filePath, second)if(fileType == ChatBean.CONTENT_TYPE_IMG){//图片//压缩图片后路径var resultPicPath = UploadFileUtils.getCompressFile(filePath)resultFilePath = resultPicPath} else if(fileType == ChatBean.CONTENT_TYPE_VOICE){//语音resultFilePath = filePathTagUtils.d("语音时间:${second}")} else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){//小视频var videoFilePath = UploadFileUtils.getVideoCompressFile()//TagUtils.d("开始发送小视频压缩前文件2:${videoFilePath}")var compressResult = VideoController.getInstance().convertVideo(filePath, videoFilePath, VideoController.COMPRESS_QUALITY_LOW, object : VideoController.CompressProgressListener {override fun onProgress(percent: Float) {//TagUtils.d("压缩小视频进度:${percent}")}})TagUtils.d("小视频时间:${second}")resultFilePath = videoFilePath}TagUtils.d("上传文件:${resultFilePath}")val filetosend = File(resultFilePath)if (!filetosend.exists()) {return@launch}try {var account : String = DataStoreUtils.getAccount()if(fileType == ChatBean.CONTENT_TYPE_IMG){//图片TagUtils.d("图片发送成功。")var chatBeanServer = UploadFileUtils.uploadChatImages(account, toUserId, resultFilePath,0)if(chatBeanServer != null){chatBeanServer.imgPath = chatBeanServer.imgPathchatBean = chatBeanServer}} else if(fileType == ChatBean.CONTENT_TYPE_VOICE){//录音完成,要转码,等待0.2秒再发送delay(100)//语音var chatBeanServer = UploadFileUtils.uploadChatVoice(account, toUserId, resultFilePath, second)if(chatBeanServer != null){chatBeanServer.voiceLocal = resultFilePathchatBean = chatBeanServer}} else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){//小视频var chatBeanServer = UploadFileUtils.uploadChatVideo(account, toUserId, resultFilePath, second)if(chatBeanServer != null){chatBeanServer.videoLocal = resultFilePathchatBean = chatBeanServer}}chatBean?.let {ChatRepository.updateChat(it)}var baseSystemBoolean = BaseSystemRepository.getBaseSystemSync(WcApp.getContext().packageName)if(baseSystemBoolean != null && baseSystemBoolean.sync == CommonUtils.Sync.SERVER_SYNC){//同步不需要使用transfer上传文件,因为transfer上传太慢了, 直接上传到服务器,然后发送普通的消息if(fileType == ChatBean.CONTENT_TYPE_VOICE){var content = CommonUtils.Chat.VOICE_MARK + chatBean.voiceChatManagerUtils.getInstance().sendMessage(toUserId, content)} else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){var content = CommonUtils.Chat.VIDEO_MARK + chatBean.videoChatManagerUtils.getInstance().sendMessage(toUserId, content)} else if(fileType == ChatBean.CONTENT_TYPE_IMG){var content = CommonUtils.Chat.IMAGE_MARK + chatBean.imgPathChatManagerUtils.getInstance().sendMessage(toUserId, content)}return@launch}val fileTransferManager = getFileTransferManager()val transfer = fileTransferManager.createOutgoingFileTransfer(toId) // 创建一个输出文件传输对象//对方用户在线才需要上传文件if(XmppConnectionManager.getInstance().isOnLine(toUserId)){TagUtils.d("${toUserId} 在线 开始上传。")transfer.sendFile(filetosend,"recv img")while (!transfer.isDone) {if (transfer.status == FileTransfer.Status.error) {TagUtils.d("聊天文件上传错误 , ERROR!!! " + transfer.error)} else {TagUtils.d("聊天文件上传 " + transfer.status +" , " + transfer.progress)}Thread.sleep(20)}} else {TagUtils.d("toUserId 不在线")}if (transfer.isDone) {//上传完成}} catch (e1: XMPPException) {e1.printStackTrace()}}
}

//接收图片、语音、小视频文件监听
fun addFileListerer() {val manager = getFileTransferManager()manager.addFileTransferListener { request ->CoroutineScope(Dispatchers.IO).launch {//文件接收val transfer = request.accept()OutgoingFileTransfer.getResponseTimeout()//获取文件名字val fileName = transfer.fileNameTagUtils.d("接收图片、语音:${fileName}")//本地创建文件val sdCardDir  = File(FileUtils.CHAT_ALBUM_PATH)if (!sdCardDir.exists()) { //判断文件夹目录是否存在sdCardDir.mkdir() //如果不存在则创建}//val savePath: String = FileUtils.CHAT_ALBUM_PATH + fileNameval savePath: String = FileUtils.getBaseFile(fileName).pathval file = File(savePath)//接收文件try {transfer.recieveFile(file)while (!transfer.isDone) {if (transfer.status == FileTransfer.Status.error) {TagUtils.d("接收、语音文件 ERROR!!! " + transfer.error)} else {TagUtils.d("接收、语音文件" + transfer.status + " , " + transfer.progress)}//接收小视频,要停顿一下,否则小视频不完整打不开。Thread.sleep(20)}if (transfer.isDone) {var account = DataStoreUtils.getAccount()var chatBean : ChatBean? = nullvar userType = ChatBean.USER_TYPE_OTHERvar peer = transfer.peerTagUtils.d("接收文件完成peer:${peer}")var toUserId = BaseUtils.getChatAccountFrom(peer)TagUtils.d("接收文件完成toUserId:${toUserId}, account = ${account}")if(fileName.endsWith(".mp3", true)){//接收语音var second = CommonUtils.Media.getMediaTime(savePath, ChatBean.CONTENT_TYPE_VOICE)chatBean = CommonUtils.Chat.getChatBeanVoice(toUserId, account, userType, ChatBean.CONTENT_TYPE_VOICE, savePath, second)} else if(fileName.endsWith(".mp4", true)){//接收小视频var second = CommonUtils.Media.getMediaTime(file.path, ChatBean.CONTENT_TYPE_VIDEO)TagUtils.d("接收的小视频文件:${savePath}, ${second}秒")chatBean = CommonUtils.Chat.getChatBeanVideo(toUserId, account, userType,  ChatBean.CONTENT_TYPE_VIDEO, savePath, second)} else {//接收图片chatBean = CommonUtils.Chat.getChatBean(toUserId, account, userType, "", ChatBean.CONTENT_TYPE_IMG, savePath,0.0, 0.0)}chatBean?.let {ChatRepository.insertChat(chatBean)EventBus.getDefault().post(chatBean)}}} catch (e: XMPPException) {e.printStackTrace()}}}
}

 

//web服务器方式下载
override fun chatCreated(chat: Chat, createdLocally: Boolean) {TagUtils.d("消息监听回调:chat = ${chat} , createdLocally = ${createdLocally}")if(!createdLocally){chat.addMessageListener { chat, message ->TagUtils.d("获取好友发来的信息 ${message.from} , ${message.to}, ${message.body}")var content = message.getBody()if(!TextUtils.isEmpty(content) && content.length > 0){var fromUser = BaseUtils.getChatAccountFrom(message.from)var toUser = BaseUtils.getChatAccount(message.to)var userType = ChatBean.USER_TYPE_OTHERif(content.startsWith(CommonUtils.Chat.LOCATION_MARK)){//发送定位//去掉location###标志var remarkContent = CommonUtils.Chat.getLocation(content)//使用逗号分隔符,分别读取经纬度var contents = remarkContent.split(",")var latitude = contents[0].toDouble()var longitude = contents[1].toDouble()var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_LOCATION, "", latitude, longitude)ChatRepository.insertChat(chatBean)chatBean.isReceive = trueEventBus.getDefault().post(chatBean)} else if(content.startsWith(CommonUtils.Chat.REDPACKET_MARK)){//发送红包, 去掉redpacket###写入数据库content = CommonUtils.Chat.getRedpacket(content).toString()var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_REDPACKET, "",0.0, 0.0)ChatRepository.insertChat(chatBean)chatBean.isReceive = trueEventBus.getDefault().post(chatBean)} else if(content.startsWith(CommonUtils.Chat.VOICE_MARK)){//发送语音, 去掉voice###写入数据库content = CommonUtils.Chat.getMedia(content, CommonUtils.Chat.VOICE_MARK)var chatBean = CommonUtils.Chat.getChatBeanVoiceServer(fromUser, toUser, userType,ChatBean.CONTENT_TYPE_VOICE, content,0)chatBean.isReceive = trueprocessDownload(chatBean)} else if(content.startsWith(CommonUtils.Chat.VIDEO_MARK)){//发送小视频, 去掉video###写入数据库content = CommonUtils.Chat.getMedia(content, CommonUtils.Chat.VIDEO_MARK)var chatBean = CommonUtils.Chat.getChatBeanVideoServer(fromUser, toUser, userType,ChatBean.CONTENT_TYPE_VIDEO, content,0)chatBean.isReceive = trueprocessDownload(chatBean)} else if(content.startsWith(CommonUtils.Chat.IMAGE_MARK)){//发送图片, 去掉image###写入数据库content = CommonUtils.Chat.getMedia(content, CommonUtils.Chat.IMAGE_MARK)var chatBean = CommonUtils.Chat.getChatBeanImageServer(fromUser, toUser, userType,ChatBean.CONTENT_TYPE_IMG, content,0)chatBean.isReceive = trueprocessDownload(chatBean)} else if(content.startsWith(CommonUtils.Chat.TRANSFER_MARK)){//发送转账, 去掉transfer###写入数据库content = CommonUtils.Chat.getTransfer(content).toString()var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_TRANSFER, "",0.0, 0.0)ChatRepository.insertChat(chatBean)chatBean.isReceive = trueEventBus.getDefault().post(chatBean)} else if(content.startsWith(CommonUtils.QRCommon.QR_RECEIVE_CODE)){//向个人发送收款var balance = content.substring(CommonUtils.QRCommon.QR_RECEIVE_CODE.length, content.length)TagUtils.d("MyChatManagerListener 向个人发送收款金额: ${fromUser} , ${toUser},  ${balance}")updateBalanceServer(fromUser, toUser, CommonUtils.User.OPERATOR_PLUS, balance.toFloat())} else if(content.startsWith(CommonUtils.QRCommon.QR_PAYMENT_CODE)){//向商家付款var balance = content.substring(CommonUtils.QRCommon.QR_RECEIVE_CODE.length, content.length)TagUtils.d("MyChatManagerListener 向商家付款金额: ${fromUser} , ${toUser}, ${balance}")updateBalanceServer(fromUser, toUser, CommonUtils.User.OPERATOR_MINUS, balance.toFloat())} else {var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_TEXT, "",0.0, 0.0)ChatRepository.insertChat(chatBean)chatBean.isReceive = trueEventBus.getDefault().post(chatBean)}ChatNotificationUtils.sendNotification(fromUser)}}}
}/*** 下载图片、语音、小视频*/
private fun processDownload(chatBean : ChatBean){var fileName = ""if(chatBean.contentType == ChatBean.CONTENT_TYPE_VOICE){fileName = chatBean.voice} else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VIDEO){fileName = chatBean.video} else if(chatBean.contentType == ChatBean.CONTENT_TYPE_IMG){fileName = chatBean.imgPath} else {return}var videoUrl = CommonUtils.Moments.getReallyImageUrl(fileName)var videoFile = FileUtils.getBaseFile(fileName)TagUtils.d("下载多媒体Url :${videoUrl} ")TagUtils.d("下载多媒体File :${videoFile} ")VideoDownloadManager.downloadFast(videoUrl, videoFile, object : VideoDownloadInter {override fun onDone(filePath: String) {TagUtils.d("小视频多媒体完成:${filePath}")if(chatBean.contentType == ChatBean.CONTENT_TYPE_VOICE){var second = CommonUtils.Media.getMediaTime(filePath, chatBean.contentType)chatBean.second = secondchatBean.voiceLocal = filePath} else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VIDEO){chatBean.videoLocal = filePathvar second = CommonUtils.Media.getMediaTime(filePath, chatBean.contentType)chatBean.second = second} else if(chatBean.contentType == ChatBean.CONTENT_TYPE_IMG){chatBean.imgPathLocal = filePath}ChatRepository.insertChat(chatBean)EventBus.getDefault().post(chatBean)}override fun onError() {}override fun onProgress(process: Int) {}})
}

http://www.ppmy.cn/news/849371.html

相关文章

你吐槽过微信语音消息吗?

微信作为一款国民 APP&#xff0c;日活 10 亿&#xff0c;不夸张的说&#xff0c;很多的人生活已经不能离开微信了&#xff0c;但在使用微信的同时也存在着一些让人不是那么满意的地方&#xff0c;今天我们来聊聊微信语音的问题。 先来看下大家是怎么吐槽微信语音消息的。 在我…

怎么把mp3转发微信语音发出去,从技术角度分析可行性

有什么需要帮助的&#xff0c;看不明白的 &#xff0c;可以加微信 258032791 做微信营销的朋友&#xff0c;很多喜欢做群营销&#xff0c;个人营销&#xff0c; 这个时候&#xff0c;如果人工一句句话去说&#xff0c;肯定能累个半死&#xff0c;如果每天应付几百人 能把你累…

高仿微信语音库--LQRAudioRecord

LQRAudioRecord 本库集成录音与播音功能&#xff0c;使用简单方便&#xff0c;让IM集成语音不再是难题。 一、简述 该库可进行语音录制及播放&#xff0c;方便IM项目集成语音功能。 录音可获取分贝&#xff0c;并默认回传10秒倒计时。播放时贴耳自动转为听筒播放&#xff0…

springboot 使用多个yml文件

如果我有很多配置和/或环境,通常我会这样做: $ cat src/main/resources/application.yml: spring:profiles:include: >profile1,profile2,...profileN

基于linux下的高并发服务器开发(第一章)-GCC(1)1.2

打开XShell,在连接虚拟机Ubuntu的窗口中输入&#xff1a;sudo apt install gcc g gcc -v,查看gcc的版本,gcc version 7.5.0 也可以是gcc --version,查看信息相对少一些 g -v g --version ls查看当前目录的文件/文件夹 cd Linux/ 进入Linux文件夹 mkdir lession02 创建lession0…

C语言联合体

一、联合体的概念 联合 (union) 是一个能在同一个存储空间里 ( 但不同时) 存储不同类型数据的复合数据类型。 大致结构如下&#xff1a; n union foo /* 定义一个联合类型foo */ n { q int digit; q double bigfl[10]; q char letter; n }baz; /* 定义一个example类型的联合变量…

SQL Server JSON 数据操作

使用内置函数 (SQL Server) 验证、查询和更改 JSON 数据 使用 OPENJSON 分析和转换 JSON 数据 (SQL Server) 1、JSON 内置函数 ISJSON 测试字符串是否包含有效 JSON。 JSON_VALUE 从 JSON 字符串中提取标量值。 JSON_QUERY 从 JSON 字符串中提取对象或数组。 JSON_MODIFY 更…

[M双指针] lc80. 删除排序数组中的重复项 II(双指针+经典)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;80. 删除排序数组中的重复项 II 2. 题目解析 时间复杂度&#xff1a; O ( n ) O(n) O(n)。空间复杂度&#xff1a; O ( 1 ) O(1) O(1) 代码&#xff1a; class Solution { public:int removeDuplicates(vect…