欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android錄制mp3格式文件

 更新時(shí)間:2017年08月11日 11:30:49   作者:Maximilian_M  
這篇文章主要為大家詳細(xì)介紹了Android錄制mp3格式文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

最近做一個(gè)即時(shí)通信類的項(xiàng)目,由于要保證pc端,iOS端和Android端的通用性,最終統(tǒng)一為MP3格式,一直擔(dān)心MP3格式會(huì)不會(huì)很大,但是實(shí)測(cè)還是可以接受的。下面來看看具體步驟:

工具

MP3格式是用一個(gè)開源項(xiàng)目轉(zhuǎn)的,MP3lame,由于該項(xiàng)目用到了jni,所以需要大家配置好ndk環(huán)境,環(huán)境配置在此就不多說了,大家可以自行百度,最新的應(yīng)該很好配置。

創(chuàng)建jni

拷貝文件

下載好后(我下載的是3.98.4版本)打開,找到libmp3lame文件,將里面的.h和.c拷貝下來,在自己的工程里創(chuàng)建jni文件夾,在jni文件夾下新建一個(gè)文件夾(我的命名為lame-3.98.4_libmp3lame,后面會(huì)用到),將剛才拷貝的文件復(fù)制進(jìn)去,然后再把include文件夾里的lame.h也拷貝進(jìn)去。

創(chuàng)建Android.mk

在jni中創(chuàng)建文件,Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LAME_LIBMP3_DIR := lame-3.98.4_libmp3lame

LOCAL_MODULE  := mp3lame
LOCAL_SRC_FILES := $(LAME_LIBMP3_DIR)/bitstream.c $(LAME_LIBMP3_DIR)/fft.c $(LAME_LIBMP3_DIR)/id3tag.c $(LAME_LIBMP3_DIR)/mpglib_interface.c $(LAME_LIBMP3_DIR)/presets.c $(LAME_LIBMP3_DIR)/quantize.c $(LAME_LIBMP3_DIR)/reservoir.c $(LAME_LIBMP3_DIR)/tables.c $(LAME_LIBMP3_DIR)/util.c $(LAME_LIBMP3_DIR)/VbrTag.c $(LAME_LIBMP3_DIR)/encoder.c $(LAME_LIBMP3_DIR)/gain_analysis.c $(LAME_LIBMP3_DIR)/lame.c $(LAME_LIBMP3_DIR)/newmdct.c $(LAME_LIBMP3_DIR)/psymodel.c $(LAME_LIBMP3_DIR)/quantize_pvt.c $(LAME_LIBMP3_DIR)/set_get.c $(LAME_LIBMP3_DIR)/takehiro.c $(LAME_LIBMP3_DIR)/vbrquantize.c $(LAME_LIBMP3_DIR)/version.c com_maxi_mp3record_MP3Recorder.c

include $(BUILD_SHARED_LIBRARY)


**注意:**LAME_LIBMP3_DIR := lame-3.98.4_libmp3lame 需要將其改為你的項(xiàng)目中的文件名,即上面說的jni下新建的文件夾。

大家應(yīng)該看到了最后一句的com_maxi_mp3record_MP3Recorder.c
很明顯這是我自己創(chuàng)建的.c文件。用來調(diào)用mp3lame中的接口的,對(duì)應(yīng)著我java中的com.maxi.mp3record.MP3Recorder.java。咱們先創(chuàng)建java文件。

創(chuàng)建MP3Recorder.java

對(duì)應(yīng)你的包名建一個(gè)MP3Recorder.java文件,該文件是java文件對(duì)應(yīng)你的包名建立即可。

package cn.ctvonline.android.modules.project.widget;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Handler;

/**
 * <b>類功能描述:</b><div style="margin-left:40px;margin-top:-10px">
 * MP3實(shí)時(shí)錄制功能,可暫停,注意因踩用Native開發(fā),不能混淆
 */
public class MP3Recorder {
 private String filePath;
 private int sampleRate;
 private boolean isRecording = false;
 private boolean isPause = false;
 private Handler handler;

 /**
  * 開始錄音
  */
 public static final int MSG_REC_STARTED = 1;

 /**
  * 結(jié)束錄音
  */
 public static final int MSG_REC_STOPPED = 2;

 /**
  * 暫停錄音
  */
 public static final int MSG_REC_PAUSE = 3;

 /**
  * 繼續(xù)錄音
  */
 public static final int MSG_REC_RESTORE = 4;

 /**
  * 緩沖區(qū)掛了,采樣率手機(jī)不支持
  */
 public static final int MSG_ERROR_GET_MIN_BUFFERSIZE = -1;

 /**
  * 創(chuàng)建文件時(shí)撲街了
  */
 public static final int MSG_ERROR_CREATE_FILE = -2;

 /**
  * 初始化錄音器時(shí)撲街了
  */
 public static final int MSG_ERROR_REC_START = -3;

 /**
  * 錄緊音的時(shí)候出錯(cuò)
  */
 public static final int MSG_ERROR_AUDIO_RECORD = -4;

 /**
  * 編碼時(shí)掛了
  */
 public static final int MSG_ERROR_AUDIO_ENCODE = -5;

 /**
  * 寫文件時(shí)掛了
  */
 public static final int MSG_ERROR_WRITE_FILE = -6;

 /**
  * 沒法關(guān)閉文件流
  */
 public static final int MSG_ERROR_CLOSE_FILE = -7;

 public MP3Recorder(int sampleRate) {
  this.sampleRate = sampleRate;
 }

 public void setFilePath(String filePath) {
  this.filePath = filePath;
 }

 /**
  * 開片
  */
 public void start() {
  if (isRecording) {
   return;
  }

  new Thread() {
   @Override
   public void run() {
    android.os.Process
      .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
    // 根據(jù)定義好的幾個(gè)配置,來獲取合適的緩沖大小
    final int minBufferSize = AudioRecord.getMinBufferSize(
      sampleRate, AudioFormat.CHANNEL_IN_MONO,
      AudioFormat.ENCODING_PCM_16BIT);
    if (minBufferSize < 0) {
     if (handler != null) {
      handler.sendEmptyMessage(MSG_ERROR_GET_MIN_BUFFERSIZE);
     }
     return;
    }
    AudioRecord audioRecord = new AudioRecord(
      MediaRecorder.AudioSource.MIC, sampleRate,
      AudioFormat.CHANNEL_IN_MONO,
      AudioFormat.ENCODING_PCM_16BIT, minBufferSize * 2);
    // 5秒的緩沖
    short[] buffer = new short[sampleRate * (16 / 8) * 1 * 5];
    byte[] mp3buffer = new byte[(int) (7200 + buffer.length * 2 * 1.25)];

    FileOutputStream output = null;
    try {
     File file = createSDFile(filePath);
     output = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
     if (handler != null) {
      handler.sendEmptyMessage(MSG_ERROR_CREATE_FILE);
     }
     return;
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    MP3Recorder.init(sampleRate, 1, sampleRate, 32);
    isRecording = true; // 錄音狀態(tài)
    isPause = false; // 錄音狀態(tài)
    try {
     try {
      audioRecord.startRecording(); // 開啟錄音獲取音頻數(shù)據(jù)

      if (mListener != null) {
       mListener.wellPrepared();
      }
     } catch (IllegalStateException e) {
      // 不給錄音...
      if (handler != null) {
       handler.sendEmptyMessage(MSG_ERROR_REC_START);
      }
      return;
     }

     try {
      // 開始錄音
      if (handler != null) {
       handler.sendEmptyMessage(MSG_REC_STARTED);
      }

      int readSize = 0;
      boolean pause = false;
      while (isRecording) {
       /*--暫停--*/
       if (isPause) {
        if (!pause) {
         handler.sendEmptyMessage(MSG_REC_PAUSE);
         pause = true;
        }
        continue;
       }
       if (pause) {
        handler.sendEmptyMessage(MSG_REC_RESTORE);
        pause = false;
       }
       /*--End--*/
       /*--實(shí)時(shí)錄音寫數(shù)據(jù)--*/
       readSize = audioRecord.read(buffer, 0,
         minBufferSize);
       voiceLevel = getVoiceSize(readSize, buffer);
       if (readSize < 0) {
        if (handler != null) {
         handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD);
        }
        break;
       } else if (readSize == 0) {
        ;
       } else {
        int encResult = MP3Recorder.encode(buffer,
          buffer, readSize, mp3buffer);
        if (encResult < 0) {
         if (handler != null) {
          handler.sendEmptyMessage(MSG_ERROR_AUDIO_ENCODE);
         }
         break;
        }
        if (encResult != 0) {
         try {
          output.write(mp3buffer, 0, encResult);
         } catch (IOException e) {
          if (handler != null) {
           handler.sendEmptyMessage(MSG_ERROR_WRITE_FILE);
          }
          break;
         }
        }
       }
       /*--End--*/
      }
      /*--錄音完--*/
      int flushResult = MP3Recorder.flush(mp3buffer);
      if (flushResult < 0) {
       if (handler != null) {
        handler.sendEmptyMessage(MSG_ERROR_AUDIO_ENCODE);
       }
      }
      if (flushResult != 0) {
       try {
        output.write(mp3buffer, 0, flushResult);
       } catch (IOException e) {
        if (handler != null) {
         handler.sendEmptyMessage(MSG_ERROR_WRITE_FILE);
        }
       }
      }
      try {
       output.close();
      } catch (IOException e) {
       if (handler != null) {
        handler.sendEmptyMessage(MSG_ERROR_CLOSE_FILE);
       }
      }
      /*--End--*/
     } finally {
      audioRecord.stop();
      audioRecord.release();
     }
    } finally {
     MP3Recorder.close();
     isRecording = false;
    }
    if (handler != null) {
     handler.sendEmptyMessage(MSG_REC_STOPPED);
    }
   }
  }.start();
 }

 public void stop() {
  isRecording = false;
 }

 public void pause() {
  isPause = true;
 }

 public void restore() {
  isPause = false;
 }

 public boolean isRecording() {
  return isRecording;
 }

 public boolean isPaus() {
  if (!isRecording) {
   return false;
  }
  return isPause;
 }

 // 獲得聲音的level
 public int getVoiceSize(int r, short[] buffer) {
  if (isRecording) {
   try {
    long v = 0;
    // 將 buffer 內(nèi)容取出,進(jìn)行平方和運(yùn)算
    for (int i = 0; i < buffer.length; i++) {
     v += buffer[i] * buffer[i];
    }
    // 平方和除以數(shù)據(jù)總長度,得到音量大小。
    double mean = v / (double) r;
    double volume = 10 * Math.log10(mean);
    return (((int) volume / 10) - 1);
   } catch (Exception e) {
    // TODO Auto-generated catch block

   }
  }

  return 1;
 }
 /**
  * 在SD卡上創(chuàng)建文件
  * 
  * @throws IOException
  */
 public static File createSDFile(String fileName) throws IOException {
  File file = new File(fileName);
  if (!isFileExists(file))
   if (file.isDirectory()) {
    file.mkdirs();
   } else {
    file.createNewFile();
   }
  return file;
 }
 private int voiceLevel;

 public int getVoiceLevel() {
  return voiceLevel;
 }

 public interface AudioStageListener {
  void wellPrepared();
 }

 public AudioStageListener mListener;

 public void setOnAudioStageListener(AudioStageListener listener) {
  mListener = listener;
 }

 /**
  * 錄音狀態(tài)管理
  * 
  * @see RecMicToMp3#MSG_REC_STARTED
  * @see RecMicToMp3#MSG_REC_STOPPED
  * @see RecMicToMp3#MSG_REC_PAUSE
  * @see RecMicToMp3#MSG_REC_RESTORE
  * @see RecMicToMp3#MSG_ERROR_GET_MIN_BUFFERSIZE
  * @see RecMicToMp3#MSG_ERROR_CREATE_FILE
  * @see RecMicToMp3#MSG_ERROR_REC_START
  * @see RecMicToMp3#MSG_ERROR_AUDIO_RECORD
  * @see RecMicToMp3#MSG_ERROR_AUDIO_ENCODE
  * @see RecMicToMp3#MSG_ERROR_WRITE_FILE
  * @see RecMicToMp3#MSG_ERROR_CLOSE_FILE
  */
 public void setHandle(Handler handler) {
  this.handler = handler;
 }

 /*--以下為Native部分--*/
 static {
  System.loadLibrary("mp3lame");
 }

 /**
  * 初始化錄制參數(shù)
  */
 public static void init(int inSamplerate, int outChannel,
   int outSamplerate, int outBitrate) {
  init(inSamplerate, outChannel, outSamplerate, outBitrate, 7);
 }

 /**
  * 初始化錄制參數(shù) quality:0=很好很慢 9=很差很快
  */
 public native static void init(int inSamplerate, int outChannel,
   int outSamplerate, int outBitrate, int quality);

 /**
  * 音頻數(shù)據(jù)編碼(PCM左進(jìn),PCM右進(jìn),MP3輸出)
  */
 public native static int encode(short[] buffer_l, short[] buffer_r,
   int samples, byte[] mp3buf);

 /**
  * 據(jù)說錄完之后要刷干凈緩沖區(qū)
  */
 public native static int flush(byte[] mp3buf);

 /**
  * 結(jié)束編碼
  */
 public native static void close();
}

創(chuàng)建c文件

在創(chuàng)建c文件,創(chuàng)建在jni下,命名就按你的java文件所在的包名命名”.”替換為“_”。例如:com_maxi_mp3record_MP3Recorder.c。當(dāng)然還得有頭文件:com_maxi_mp3record_MP3Recorder.h。

com_maxi_mp3record_MP3Recorder.c

#include "lame-3.98.4_libmp3lame/lame.h"
#include "com_maxi_mp3record_MP3Recorder.h"

static lame_global_flags *glf = NULL;

JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_init(
  JNIEnv *env, jclass cls, jint inSamplerate, jint outChannel,
  jint outSamplerate, jint outBitrate, jint quality) {
 if (glf != NULL) {
  lame_close(glf);
  glf = NULL;
 }
 glf = lame_init();
 lame_set_in_samplerate(glf, inSamplerate);
 lame_set_num_channels(glf, outChannel);
 lame_set_out_samplerate(glf, outSamplerate);
 lame_set_brate(glf, outBitrate);
 lame_set_quality(glf, quality);
 lame_init_params(glf);
}

JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_encode(
  JNIEnv *env, jclass cls, jshortArray buffer_l, jshortArray buffer_r,
  jint samples, jbyteArray mp3buf) {
 jshort* j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL);

 jshort* j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL);

 const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);
 jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

 int result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r,
   samples, j_mp3buf, mp3buf_size);

 (*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0);
 (*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0);
 (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

 return result;
}

JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_flush(
  JNIEnv *env, jclass cls, jbyteArray mp3buf) {
 const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);
 jbyte* j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

 int result = lame_encode_flush(glf, j_mp3buf, mp3buf_size);

 (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

 return result;
}

JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_close(
  JNIEnv *env, jclass cls) {
 lame_close(glf);
 glf = NULL;
}

com_maxi_mp3record_MP3Recorder.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_maxi_mp3record_MP3Recorder */

#ifndef _Included_com_maxi_mp3record_MP3Recorder
#define _Included_com_maxi_mp3record_MP3Recorder
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:  com_maxi_mp3record_MP3Recorder
 * Method: init
 * Signature: (IIIII)V
 */
JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_init
 (JNIEnv *, jclass, jint, jint, jint, jint, jint);

/*
 * Class:  com_maxi_mp3record_MP3Recorder
 * Method: encode
 * Signature: ([S[SI[B)I
 */
JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_encode
 (JNIEnv *, jclass, jshortArray, jshortArray, jint, jbyteArray);

/*
 * Class:  com_maxi_mp3record_MP3Recorder
 * Method: flush
 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_com_maxi_mp3record_MP3Recorder_flush
 (JNIEnv *, jclass, jbyteArray);

/*
 * Class:  com_maxi_mp3record_MP3Recorder
 * Method: close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_maxi_mp3record_MP3Recorder_close
 (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

這倆文件別只復(fù)制不看內(nèi)容啊,里面可都是連接java和c的接口,所以不能有差錯(cuò)。舉個(gè)例子吧,#ifndef _Included_com_maxi_mp3record_MP3Recorder,這個(gè)就得替換成你對(duì)應(yīng)的包名,里面所有都得替換成你自己的程序?qū)?yīng)的包名。

編譯ndk

創(chuàng)建Application.mk在你的項(xiàng)目文件的jni下,在里面寫入:
APP_ABI := all
如果不加,NDK只會(huì)編譯“armeabi”,然而安卓有很多不同類型的處理器,所以我們不止需要arm。相信你們搞到現(xiàn)在了肯定ndk都配置好了,然后打開終端,進(jìn)入到你的項(xiàng)目(找到你的ndk目錄下的ndk-bulid,最好把它添加到環(huán)境變量里,對(duì)于以后編譯比較方便,在此默認(rèn)你沒添加環(huán)境變量),執(zhí)行ndk-bulid。稍等片刻你會(huì)發(fā)現(xiàn)你的項(xiàng)目里多了一個(gè)obj文件夾,obj文件夾下會(huì)生成”arm64-v8a”、”armeabi”、”armeabi-v7a”、”mips”、”mips64”、”x86”、”x86_64”。打開它,各個(gè)文件夾下會(huì)有一個(gè)libmp3lame.so。ok,沒錯(cuò)那就是你要的“滑板鞋”。將它放入你的libs文件下,沒有自行創(chuàng)建,各個(gè)平臺(tái)便都可以加載了。

使用方法

MP3Recorder recorder = new MP3Recorder(8000);
recorder.setFilePath(voicePath);//錄音保存目錄
recorder.start();//開始錄音
recorder.stop();//錄音結(jié)束
recorder.getVoiceLevel()//這是我封裝的獲取音頻振幅接口,大家可以用來錄音的時(shí)候顯示聲音大小,數(shù)據(jù)自行調(diào)節(jié)。

總結(jié)

之前一直用MediaRecorder錄音,發(fā)現(xiàn)錄出來的只能是amr、acc等格式,用lame轉(zhuǎn)MP3感覺是不可行的。我試了沒能成功,不知道具體是什么原因,所以大家有時(shí)間可以研究研究,沒時(shí)間就不要嘗試了。

Mp3lame錄制出來的聲音還是挺靠譜的(不過據(jù)聽說iOS就有些莎莎聲),然后錄制出來的大小還是可以接受的,五秒鐘的音頻大概在20k左右的樣子吧。使用還是很方便的。如果有什么疑問或建議請(qǐng)留言哈。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android實(shí)現(xiàn)View滑動(dòng)的幾種方式

    Android實(shí)現(xiàn)View滑動(dòng)的幾種方式

    Android中的View類是所有UI控件的基類(Base class),也就是說我們平時(shí)所有到的各種UI控件,比如Button、ImagView等等都繼承自View類。這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)View滑動(dòng)的幾種方式,需要的朋友可以參考下
    2016-04-04
  • Android獲取SD卡中選中圖片的路徑(URL)示例

    Android獲取SD卡中選中圖片的路徑(URL)示例

    一個(gè)圖片上傳功能需要提供上傳圖片在SD卡中的路徑,總結(jié)了網(wǎng)上的一些列子,修改了一下,代碼很簡(jiǎn)單,感興趣的朋友可以參考下哈,希望對(duì)大家有所幫助
    2013-07-07
  • 基于Android實(shí)現(xiàn)的文件同步設(shè)計(jì)方案

    基于Android實(shí)現(xiàn)的文件同步設(shè)計(jì)方案

    隨著用戶對(duì)自身數(shù)據(jù)保護(hù)意識(shí)的加強(qiáng),讓用戶自己維護(hù)自己的數(shù)據(jù)也成了獨(dú)立開發(fā)產(chǎn)品時(shí)的一個(gè)賣點(diǎn),若只針對(duì)少量的文件進(jìn)行同步,則實(shí)現(xiàn)起來比較簡(jiǎn)單,當(dāng)針對(duì)一個(gè)多層級(jí)目錄同步時(shí),情況就復(fù)雜多了,本文我分享下我的設(shè)計(jì)思路
    2023-10-10
  • android多種滑動(dòng)沖突的解決方案

    android多種滑動(dòng)沖突的解決方案

    本篇文章主要介紹了android多種滑動(dòng)沖突的解決方案,解決方案主要有2種,外部攔截法 和內(nèi)部攔截法,有興趣的可以了解一下。
    2017-02-02
  • android使用ViewPager組件實(shí)現(xiàn)app引導(dǎo)查看頁面

    android使用ViewPager組件實(shí)現(xiàn)app引導(dǎo)查看頁面

    這篇文章主要為大家詳細(xì)介紹了android使用ViewPager組件實(shí)現(xiàn)app引導(dǎo)查看頁面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Android自定義View基礎(chǔ)開發(fā)之圖片加載進(jìn)度條

    Android自定義View基礎(chǔ)開發(fā)之圖片加載進(jìn)度條

    這篇文章主要介紹了Android自定義View基礎(chǔ)開發(fā)之圖片加載進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 詳解Android Studio實(shí)現(xiàn)用戶登陸界面demo(xml實(shí)現(xiàn))

    詳解Android Studio實(shí)現(xiàn)用戶登陸界面demo(xml實(shí)現(xiàn))

    這篇文章主要介紹了詳解Android Studio實(shí)現(xiàn)用戶登陸界面demo,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 詳解Android消息機(jī)制完整的執(zhí)行流程

    詳解Android消息機(jī)制完整的執(zhí)行流程

    經(jīng)過前面幾篇文章的鋪墊,介紹了Hanlder、Message等類相關(guān)使用,分析了其與Looper、MessageQueue的部分源碼,本篇文章主要是集中梳理Android整個(gè)消息機(jī)制執(zhí)行的完整流程,需要的可以參考一下
    2022-10-10
  • Flutter基于Dart Unwrapping Multiple Optional小技巧

    Flutter基于Dart Unwrapping Multiple Optional小技巧

    這篇文章主要為大家介紹了Flutter Unwrapping Multiple Optional打開多個(gè)選項(xiàng)小技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Android使用setCustomTitle()方法自定義對(duì)話框標(biāo)題

    Android使用setCustomTitle()方法自定義對(duì)話框標(biāo)題

    Android有自帶的對(duì)話框標(biāo)題,但是不太美觀,如果要給彈出的對(duì)話框設(shè)置一個(gè)自定義的標(biāo)題,使用AlertDialog.Builder的setCustomTitle()方法非常方便,接下來通過本文給大家介紹Android使用setCustomTitle()方法自定義對(duì)話框標(biāo)題,感興趣的朋友一起學(xué)習(xí)吧
    2016-02-02

最新評(píng)論