編輯:關於Android編程
本實例來自於《瘋狂Android講義》,要實現具體的功能,需要了解以下API: MediaPlayer 媒體播放器Visualizer 頻譜Equalizer 均衡器BassBoost 重低音控制器PresetReverb 預設音場控制器Paint 繪圖




package com.oyp.media;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.media.audiofx.PresetReverb;
import android.media.audiofx.Visualizer;
import android.os.Bundle;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
public class MediaPlayerTest extends Activity
{
// 定義播放聲音的MediaPlayer
private MediaPlayer mPlayer;
// 定義系統的頻譜
private Visualizer mVisualizer;
// 定義系統的均衡器
private Equalizer mEqualizer;
// 定義系統的重低音控制器
private BassBoost mBass;
// 定義系統的預設音場控制器
private PresetReverb mPresetReverb;
private LinearLayout layout;
private List reverbNames = new ArrayList();
private List reverbVals = new ArrayList();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//設置音頻流 - STREAM_MUSIC:音樂回放即媒體音量
setVolumeControlStream(AudioManager.STREAM_MUSIC);
layout = new LinearLayout(this);//代碼創建布局
layout.setOrientation(LinearLayout.VERTICAL);//設置為線性布局-上下排列
setContentView(layout);//將布局添加到 Activity
// 創建MediaPlayer對象,並添加音頻
// 音頻路徑為 res/raw/beautiful.mp3
mPlayer = MediaPlayer.create(this, R.raw.beautiful);
// 初始化示波器
setupVisualizer();
// 初始化均衡控制器
setupEqualizer();
// 初始化重低音控制器
setupBassBoost();
// 初始化預設音場控制器
setupPresetReverb();
// 開發播放音樂
mPlayer.start();
}
/**
* 初始化頻譜
*/
private void setupVisualizer()
{
// 創建MyVisualizerView組件,用於顯示波形圖
final MyVisualizerView mVisualizerView =
new MyVisualizerView(this);
mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
(int) (120f * getResources().getDisplayMetrics().density)));
// 將MyVisualizerView組件添加到layout容器中
layout.addView(mVisualizerView);
// 以MediaPlayer的AudioSessionId創建Visualizer
// 相當於設置Visualizer負責顯示該MediaPlayer的音頻數據
mVisualizer = new Visualizer(mPlayer.getAudioSessionId());
//設置需要轉換的音樂內容長度,專業的說這就是采樣,該采樣值一般為2的指數倍,如64,128,256,512,1024。
mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
// 為mVisualizer設置監聽器
/*
* Visualizer.setDataCaptureListener(OnDataCaptureListener listener, int rate, boolean waveform, boolean fft
*
* listener,表監聽函數,匿名內部類實現該接口,該接口需要實現兩個函數
rate, 表示采樣的周期,即隔多久采樣一次,聯系前文就是隔多久采樣128個數據
iswave,是波形信號
isfft,是FFT信號,表示是獲取波形信號還是頻域信號
*/
mVisualizer.setDataCaptureListener(
new Visualizer.OnDataCaptureListener()
{
//這個回調應該采集的是快速傅裡葉變換有關的數據
@Override
public void onFftDataCapture(Visualizer visualizer,
byte[] fft, int samplingRate)
{
}
//這個回調應該采集的是波形數據
@Override
public void onWaveFormDataCapture(Visualizer visualizer,
byte[] waveform, int samplingRate)
{
// 用waveform波形數據更新mVisualizerView組件
mVisualizerView.updateVisualizer(waveform);
}
}, Visualizer.getMaxCaptureRate() / 2, true, false);
mVisualizer.setEnabled(true);
}
/**
* 初始化均衡控制器
*/
private void setupEqualizer()
{
// 以MediaPlayer的AudioSessionId創建Equalizer
// 相當於設置Equalizer負責控制該MediaPlayer
mEqualizer = new Equalizer(0, mPlayer.getAudioSessionId());
// 啟用均衡控制效果
mEqualizer.setEnabled(true);
TextView eqTitle = new TextView(this);
eqTitle.setText(均衡器:);
layout.addView(eqTitle);
// 獲取均衡控制器支持最小值和最大值
final short minEQLevel = mEqualizer.getBandLevelRange()[0];//第一個下標為最低的限度范圍
short maxEQLevel = mEqualizer.getBandLevelRange()[1]; // 第二個下標為最高的限度范圍
// 獲取均衡控制器支持的所有頻率
short brands = mEqualizer.getNumberOfBands();
for (short i = 0; i < brands; i++)
{
TextView eqTextView = new TextView(this);
// 創建一個TextView,用於顯示頻率
eqTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
eqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
// 設置該均衡控制器的頻率
eqTextView.setText((mEqualizer.getCenterFreq(i) / 1000)
+ Hz);
layout.addView(eqTextView);
// 創建一個水平排列組件的LinearLayout
LinearLayout tmpLayout = new LinearLayout(this);
tmpLayout.setOrientation(LinearLayout.HORIZONTAL);
// 創建顯示均衡控制器最小值的TextView
TextView minDbTextView = new TextView(this);
minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// 顯示均衡控制器的最小值
minDbTextView.setText((minEQLevel / 100) + dB);
// 創建顯示均衡控制器最大值的TextView
TextView maxDbTextView = new TextView(this);
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// 顯示均衡控制器的最大值
maxDbTextView.setText((maxEQLevel / 100) + dB);
LinearLayout.LayoutParams layoutParams = new
LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.weight = 1;
// 定義SeekBar做為調整工具
SeekBar bar = new SeekBar(this);
bar.setLayoutParams(layoutParams);
bar.setMax(maxEQLevel - minEQLevel);
bar.setProgress(mEqualizer.getBandLevel(i));
final short brand = i;
// 為SeekBar的拖動事件設置事件監聽器
bar.setOnSeekBarChangeListener(new SeekBar
.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar,
int progress, boolean fromUser)
{
// 設置該頻率的均衡值
mEqualizer.setBandLevel(brand,
(short) (progress + minEQLevel));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
// 使用水平排列組件的LinearLayout“盛裝”3個組件
tmpLayout.addView(minDbTextView);
tmpLayout.addView(bar);
tmpLayout.addView(maxDbTextView);
// 將水平排列組件的LinearLayout添加到myLayout容器中
layout.addView(tmpLayout);
}
}
/**
* 初始化重低音控制器
*/
private void setupBassBoost()
{
// 以MediaPlayer的AudioSessionId創建BassBoost
// 相當於設置BassBoost負責控制該MediaPlayer
mBass = new BassBoost(0, mPlayer.getAudioSessionId());
// 設置啟用重低音效果
mBass.setEnabled(true);
TextView bbTitle = new TextView(this);
bbTitle.setText(重低音:);
layout.addView(bbTitle);
// 使用SeekBar做為重低音的調整工具
SeekBar bar = new SeekBar(this);
// 重低音的范圍為0~1000
bar.setMax(1000);
bar.setProgress(0);
// 為SeekBar的拖動事件設置事件監聽器
bar.setOnSeekBarChangeListener(new SeekBar
.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar
, int progress, boolean fromUser)
{
// 設置重低音的強度
mBass.setStrength((short) progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
layout.addView(bar);
}
/**
* 初始化預設音場控制器
*/
private void setupPresetReverb()
{
// 以MediaPlayer的AudioSessionId創建PresetReverb
// 相當於設置PresetReverb負責控制該MediaPlayer
mPresetReverb = new PresetReverb(0,
mPlayer.getAudioSessionId());
// 設置啟用預設音場控制
mPresetReverb.setEnabled(true);
TextView prTitle = new TextView(this);
prTitle.setText(音場);
layout.addView(prTitle);
// 獲取系統支持的所有預設音場
for (short i = 0; i < mEqualizer.getNumberOfPresets(); i++)
{
reverbNames.add(i);
reverbVals.add(mEqualizer.getPresetName(i));
}
// 使用Spinner做為音場選擇工具
Spinner sp = new Spinner(this);
sp.setAdapter(new ArrayAdapter(MediaPlayerTest.this,
android.R.layout.simple_spinner_item, reverbVals));
// 為Spinner的列表項選中事件設置監聽器
sp.setOnItemSelectedListener(new Spinner
.OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView arg0
, View arg1, int arg2, long arg3)
{
// 設定音場
mPresetReverb.setPreset(reverbNames.get(arg2));
}
@Override
public void onNothingSelected(AdapterView arg0)
{
}
});
layout.addView(sp);
}
@Override
protected void onPause()
{
super.onPause();
if (isFinishing() && mPlayer != null)
{
// 釋放所有對象
mVisualizer.release();
mEqualizer.release();
mPresetReverb.release();
mBass.release();
mPlayer.release();
mPlayer = null;
}
}
/**
* 根據Visualizer傳來的數據動態繪制波形效果,分別為:
* 塊狀波形、柱狀波形、曲線波形
*/
private static class MyVisualizerView extends View
{
// bytes數組保存了波形抽樣點的值
private byte[] bytes;
private float[] points;
private Paint paint = new Paint();
private Rect rect = new Rect();
private byte type = 0;
public MyVisualizerView(Context context)
{
super(context);
bytes = null;
// 設置畫筆的屬性
paint.setStrokeWidth(1f);
paint.setAntiAlias(true);//抗鋸齒
paint.setColor(Color.YELLOW);//畫筆顏色
paint.setStyle(Style.FILL);
}
public void updateVisualizer(byte[] ftt)
{
bytes = ftt;
// 通知該組件重繪自己。
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent me)
{
// 當用戶觸碰該組件時,切換波形類型
if(me.getAction() != MotionEvent.ACTION_DOWN)
{
return false;
}
type ++;
if(type >= 3)
{
type = 0;
}
return true;
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (bytes == null)
{
return;
}
// 繪制白色背景
canvas.drawColor(Color.WHITE);
// 使用rect對象記錄該組件的寬度和高度
rect.set(0,0,getWidth(),getHeight());
switch(type)
{
// -------繪制塊狀的波形圖-------
case 0:
for (int i = 0; i < bytes.length - 1; i++)
{
float left = getWidth() * i / (bytes.length - 1);
// 根據波形值計算該矩形的高度
float top = rect.height()-(byte)(bytes[i+1]+128)
* rect.height() / 128;
float right = left + 1;
float bottom = rect.height();
canvas.drawRect(left, top, right, bottom, paint);
}
break;
// -------繪制柱狀的波形圖(每隔18個抽樣點繪制一個矩形)-------
case 1:
for (int i = 0; i < bytes.length - 1; i += 18)
{
float left = rect.width()*i/(bytes.length - 1);
// 根據波形值計算該矩形的高度
float top = rect.height()-(byte)(bytes[i+1]+128)
* rect.height() / 128;
float right = left + 6;
float bottom = rect.height();
canvas.drawRect(left, top, right, bottom, paint);
}
break;
// -------繪制曲線波形圖-------
case 2:
// 如果point數組還未初始化
if (points == null || points.length < bytes.length * 4)
{
points = new float[bytes.length * 4];
}
for (int i = 0; i < bytes.length - 1; i++)
{
// 計算第i個點的x坐標
points[i * 4] = rect.width()*i/(bytes.length - 1);
// 根據bytes[i]的值(波形點的值)計算第i個點的y坐標
points[i * 4 + 1] = (rect.height() / 2)
+ ((byte) (bytes[i] + 128)) * 128
/ (rect.height() / 2);
// 計算第i+1個點的x坐標
points[i * 4 + 2] = rect.width() * (i + 1)
/ (bytes.length - 1);
// 根據bytes[i+1]的值(波形點的值)計算第i+1個點的y坐標
points[i * 4 + 3] = (rect.height() / 2)
+ ((byte) (bytes[i + 1] + 128)) * 128
/ (rect.height() / 2);
}
// 繪制波形曲線
canvas.drawLines(points, paint);
break;
}
}
}
}
java.lang.RuntimeException: Cannot initialize Visualizer engine, error: -4
Android 仿網易新聞客戶端分類排序功能
先來看看網易新聞客戶端以及自己實現的效果圖,效果當然還是網易的好gridviewsort.gif如何實現拖拽一個Item用WindowManager添加一個ImageVi
Android編程獲取GPS數據的方法詳解
本文實例講述了Android編程獲取GPS數據的方法。分享給大家供大家參考,具體如下:GPS是Android系統中重要的組成部分,通過它可以衍生出眾多的與位置相關的應用。
Android學習系列(二)布局管理器之線性布局及其自定義實現
LinearLayout是Android控件中的線性布局控件,它包含的子控件將以橫向(HORIZONTAL)或豎向(VERTICAL)的方式排
Android學習JNI,使用C調用JAVA語言
本節學習使用C語言調用JAVA語言。在生活中比如我們某些底層的硬件必須使用C語言去編寫,當C語言返回的某些數值顯示在界面上時,就比如使用JNI。這樣可以將C返回的值顯示在