多媒體編程
圖片處理
加載大圖片
- Android 模擬器默認爲每個應用分配的堆內存空間是16M
- 當加載大圖片時,加載圖片需要的內存空間不是按圖片的大小來算的,而是按像素點的多少來算的
- 圖片加載到內存中需要把每一個像素都加載到內存中,容易造成OOM(OutOfMemoryError) 內存溢出致命錯誤
採用縮放方式加載圖片
public void click(View v) {
//創建一個位圖工廠的配置參數
BitmapFactory.Options options = new Options();
//解碼器不去真正的解析位圖 但是還能夠獲取圖片的寬和高信息
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
//[2]獲取圖片的寬和高信息
int imgWidth = options.outWidth;
int imgHeight = options.outHeight;
System.out.println("圖片的寬和高:"+imgWidth+"----"+imgHeight);
//[3]計算縮放縮放比
int scale = 1;
int scaleX = imgWidth/width;
int scaleY = imgHeight/height;
if (scaleX>=scaleY && scaleX>scale) {
scale = scaleX;
}
if (scaleY > scaleX && scaleY>scale) {
scale = scaleY;
}
System.out.println("縮放比==:"+scale);
//[4]安裝縮放比進行顯示 生物學 丁磊
options.inSampleSize = scale;
//[5]安裝縮放比 進行解析位圖
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
//[6]把bitmap顯示iv上
iv.setImageBitmap(bitmap);
}
創建一個原圖的副本
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//顯示原圖
ImageView iv_src = (ImageView) findViewById(R.id.iv_src);
//顯示副本
ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy);
//[1]先把tomcat.png 圖片轉換成bitmap 顯示到iv_src
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat);
//[1.1]操作圖片
// srcBitmap.setPixel(20, 30, Color.RED);
iv_src.setImageBitmap(srcBitmap);
//[2]創建原圖的副本
//[2.1]創建一個模板 相當於 創建了一個大小和原圖一樣的 空白的白紙
Bitmap copybiBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//[2.2]想作畫需要一個畫筆
Paint paint = new Paint();
//[2.3]創建一個畫布 把白紙鋪到畫布上
Canvas canvas = new Canvas(copybiBitmap);
//[2.4]開始作畫
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
//[2.5]操作畫出來的小貓圖片
for (int i = 0; i < 20; i++) {
copybiBitmap.setPixel(20+i, 30, Color.RED);
}
//[3]把copybimap顯示到iv_copy上
iv_copy.setImageBitmap(copybiBitmap);
}
}
圖片操作API
- 圖片的特效包括,圖形的縮放、鏡面、倒影、旋轉、位移等。圖片的特效是將原圖的圖形矩陣乘以一個特效矩陣,形成一個新的圖形矩陣來實現
- Matrix 維護了一個3*3 的矩陣去更改像素點的座標
旋轉,縮放,平移,鏡面,倒影
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//顯示原圖
ImageView iv_src = (ImageView) findViewById(R.id.iv_src);
//顯示副本
ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy);
//[1]先把tomcat.png 圖片轉換成bitmap 顯示到iv_src
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat);
//[1.1]操作圖片
// srcBitmap.setPixel(20, 30, Color.RED);
iv_src.setImageBitmap(srcBitmap);
//[2]創建原圖的副本
//[2.1]創建一個模板 相當於 創建了一個大小和原圖一樣的 空白的白紙
Bitmap copybiBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//[2.2]想作畫需要一個畫筆
Paint paint = new Paint();
//[2.3]創建一個畫布 把白紙鋪到畫布上
Canvas canvas = new Canvas(copybiBitmap);
//[2.4]開始作畫
Matrix matrix = new Matrix();
//[2.5]對圖片進行旋轉
//matrix.setRotate(20, srcBitmap.getWidth()/2, srcBitmap.getHeight()/2);
//[2.5]對圖片進行縮放
// matrix.setScale(0.5f, 0.5f);
//[2.6]對圖片進行平移
// matrix.setTranslate(30, 0);
//[2.7]鏡面效果 如果2個方法一起用
// matrix.setScale(-1.0f, 1);
//post是在上一次修改的基礎上進行再次修改 set 每次操作都是最新的 會覆蓋上次的操作
// matrix.postTranslate(srcBitmap.getWidth(), 0);
//[2,7]倒影效果
matrix.setScale(1.0f, -1);
//post是在上一次修改的基礎上進行再次修改 set 每次操作都是最新的 會覆蓋上次的操作
matrix.postTranslate(0, srcBitmap.getHeight());
canvas.drawBitmap(srcBitmap,matrix , paint);
//[3]把copybimap顯示到iv_copy上
iv_copy.setImageBitmap(copybiBitmap);
}
}
模擬畫圖功能
原理:
Android 中只有View 纔可以捕獲到用戶觸摸的事件
ImageView 控件可以設置一個觸摸事件的監聽器來監聽觸摸事件,重寫OnTouchListener 的onTouch 方法,結合Canvas 類,即可實現隨手塗鴉的畫板功能
TIPS:
onTouch 方法的返回值默認是false 的,必須設置爲true,否則觸摸事件將不會被處理
觸摸事件:
MotionEvent.ACTION_DOWN 按下
MotionEvent.ACTION_MOVE 移動
MotionEvent.ACTION_UP 擡起
代碼
public class MainActivity extends Activity {
private Bitmap srcBitmap;
private ImageView iv;
private Bitmap copyBitmap;
private Paint paint;
private Canvas canvas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 用來顯示我們畫的內容
iv = (ImageView) findViewById(R.id.iv);
// [1]獲取原圖 bg
srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
// [2]獲取原圖的副本 相當於是一個空白 的白紙
copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(),
srcBitmap.getHeight(), srcBitmap.getConfig());
// 創建畫筆
paint = new Paint();
// 創建一個畫布
canvas = new Canvas(copyBitmap);
// 開始作畫
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
// canvas.drawLine(20, 30, 50, 80, paint);
iv.setImageBitmap(copyBitmap);
// [3]給iv設置一個觸摸事件
iv.setOnTouchListener(new OnTouchListener() {
int startX = 0;
int startY = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
// 獲取當前事件類型
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: // 按下
System.out.println("摸view");
// 獲取開始位置 (劃線)
startX = (int) event.getX();
startY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:// 移動
System.out.println("移動");
// 獲取結束位置
int stopX = (int) event.getX();
int stopY = (int) event.getY();
// [不停的畫線]
canvas.drawLine(startX, startY, stopX, stopY, paint);
// 在次顯示到iv上
iv.setImageBitmap(copyBitmap);
// 更新一下開始座標和結束座標
startX = stopX;
startY = stopY;
break;
case MotionEvent.ACTION_UP:// 擡起
System.out.println("擡起");
break;
}
// True if the listener has consumed the event, false otherwise
return true; // true 監聽器處理完事件了
}
});
}
// 點擊按鈕 改變畫筆的顏色
public void click1(View v) {
paint.setColor(Color.RED);
}
// 點擊按鈕 對畫筆加粗
public void click2(View v) {
paint.setStrokeWidth(15);
}
// 點擊按鈕 對畫筆加粗
public void click3(View v) {
/**
* format 保存圖片的格式
* quality 保存圖片的質量
* SystemClock.uptimeMillis() 這個是當前手機的開機時間
*/
try {
File file = new File(Environment.getExternalStorageDirectory().getPath(),SystemClock.uptimeMillis()+".png");
FileOutputStream fos = new FileOutputStream(file);
copyBitmap.compress(CompressFormat.PNG, 100, fos);
//發送一條廣播 欺騙系統圖庫的應用
Intent intent = new Intent();
//設置action
intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
//發送一條廣播
sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
撕衣服案例
原理:
一張圖片有衣服,一張圖片沒有衣服。
沒有衣服的圖片放置在下面,有衣服的圖片放置在上面,
爲在上面的ImageView 設置觸摸的事件,
當手指觸摸到圖片上時,將手指觸摸的點周邊的上層圖片的像素點設置爲透明的,就會出現一個撕衣服的效果。
代碼
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//用來顯示 操作後的圖片
final ImageView iv = (ImageView) findViewById(R.id.iv);
//[1]獲取要操作圖片 原圖
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pre19);
//[2]創建一個副本 相當於有一個和原圖大小的白紙
final Bitmap alterBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//創建畫筆
Paint paint = new Paint();
//創建畫布 把白紙鋪到畫布上
Canvas canvas = new Canvas(alterBitmap);
//開始作畫
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
iv.setImageBitmap(alterBitmap);
//[3]給vi設置一個觸摸事件
iv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//[4]具體判斷一下觸摸事件
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE://移動事件
for (int i = -7; i < 7; i++) { //增加X軸座標
for (int j = -7; j < 7; j++) {
//增加Y軸座標
//爲了良好的用戶體驗 撕一個圓
if (Math.sqrt(i*i+j*j)<7) {
try {
alterBitmap.setPixel((int)event.getX()+i, (int)event.getY()+j, Color.TRANSPARENT);
} catch (Exception e) {
}
}
}
}
//更新一下iv
iv.setImageBitmap(alterBitmap);
break;
}
return true;
}
});
}
}
音頻播放
MediaPlayer
流程圖
該播放器同時只能播放一個音樂文件,文件大小並沒有限制
SoundPool
SoundPool 和其他聲音播放類相比,其特點是可以自行設置聲音的品質、音量、播放比率等參數。並且它可以同時管理多個音頻流,每個流都有獨自的ID,對某個音頻流的管理都是通過ID 進行的。
應用場景
- 程序中有些很短小音頻需要經常播放,例如:遊戲音效
- 如果使用MediaPlayer 每次加載音頻、播放、再釋放,這樣很費事
- 我們可以使用音頻池一次性加載多個音頻,需要哪個就直接播放
- SoundPool 最大隻能申請1M 的內存空間,這就意味着我們只能用一些很短的聲音片段
- SoundPool 提供了pause 和stop 方法,把緩衝區裏的數據播放完纔會停下來,也許會多播放一秒鐘
使用步驟
創建SoundPool 實例, 第一個參數用於指定最大可以加載聲音個數
SoundPool soundPool=new SoundPool(3,AudioManager.STREAM_MUSIC, 0);
加載不同的聲音文件,生成各自的聲音id
int shoot1ID = soundPool.load(this, R.raw.shoot1, 1);
int shoot2ID = soundPool.load(this, R.raw.shoot2, 1);
int shoot3ID = soundPool.load(this, R.raw.shoot3, 1);
根據load 方法獲取的id 播放對應的聲音
soundPool.play(shoot1ID, 1, 1, 1, 0, 1);
soundPool.play(shoot2ID, 1, 1, 1, 0, 1);
soundPool.play(shoot3ID, 1, 1, 1, 0, 1);
模擬實現音頻播放器
TIPS:
播放網絡音樂應使用異步播放,設置一個準備完成的監聽
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//點擊按鈕 播放一個音頻文件
public void click(View v) {
//[1]初始化mediaplayer
final MediaPlayer mediaPlayer = new MediaPlayer();
//[2]設置要播放的資源位置 path 可以是網絡 路徑 也可是本地路徑
try {
mediaPlayer.setDataSource("http://192.168.11.86:8080/xpg.mp3");
//[3]準備播放
mediaPlayer.prepareAsync();
//[3.1]設置一個準備完成的監聽
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//[4]開始播放
mediaPlayer.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
模擬播放器代碼
public class MainActivity extends Activity implements OnSeekBarChangeListener {
private EditText et_path;
private SeekBar sb;
private TextView tv_time;
private MediaPlayer player;
private int duration;
private boolean isUpdateBar;
// 播放器的幾個狀態
private static final int PLAYING = 1;// 播放狀態
private static final int PAUSING = 2;// 暫停狀態
private static final int STOPPING = 3;// 停止狀態
private int CURRENT = 0;// 當前狀態
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化界面控件
et_path = (EditText) findViewById(R.id.et_path);
sb = (SeekBar) findViewById(R.id.sb);
// 給SeekBar 綁定滑動事件
sb.setOnSeekBarChangeListener(this);
tv_time = (TextView) findViewById(R.id.tv_time);
}
// 播放音樂
public void play(View view) {
if (player != null) {
if (CURRENT == PLAYING) {
return;
} else if (CURRENT == PAUSING) {
player.start();
CURRENT = PLAYING;
updateSeekBar();
return;
} else if (CURRENT == STOPPING) {
player.reset();
player.release();
}
}
try {
// 創建一個播放器對象
player = new MediaPlayer();
// 獲取音樂路徑
String path = et_path.getText().toString();
// 給播放器設置音樂路徑
player.setDataSource(path);
// 設置音樂格式
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
// 準備
player.prepare();
// 獲取音樂最大長度(毫秒單位)
duration = player.getDuration();
// 給SeekBar 設置最大值
sb.setMax(duration);
// 格式化輸出音樂長度
String lastString = formatTime(duration);
tv_time.setText("00:00/" + lastString);
// 音樂開始播放
player.start();
// 更新SeekBar
updateSeekBar();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "音樂播放失敗" + e, 0).show();
}
}
// 暫停
public void pause(View view) {
if (player != null && CURRENT == PLAYING) {
player.pause();
stopSeekBar();
CURRENT = PAUSING;
}
}
// 停止播放
public void stop(View view) {
if (player != null) {
if (CURRENT == PLAYING || CURRENT == PAUSING) {
player.stop();
stopSeekBar();
sb.setProgress(0);
tv_time.setText("00:00/" + formatTime(duration));
CURRENT = STOPPING;
}
}
}
// 重新播放
public void replay(View view) {
if (player != null) {
stopSeekBar();
CURRENT = STOPPING;
play(view);
}
}
// 停止SeekBar 更新
private void stopSeekBar() {
isUpdateBar = false;
}
// 更新SeekBar
private void updateSeekBar() {
isUpdateBar = true;
new Thread(new Runnable() {
@Override
public void run() {
while (isUpdateBar) {
// 每秒更新一次
SystemClock.sleep(1000);
if (player != null && CURRENT == PLAYING) {
sb.setProgress(player.getCurrentPosition());
// 在主線程中運行如下代碼更新EditText
runOnUiThread(new Runnable() {
@Override
public void run() {
String current = formatTime(player
.getCurrentPosition());
String durationString = formatTime(duration);
tv_time.setText(current + "/" + durationString);
}
});
}
}
}
}).start();
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (player != null) {
player.seekTo(progress);
}
}
// 開始拖動SeekBar 時停止更新SeekBar
public void onStartTrackingTouch(SeekBar seekBar) {
stopSeekBar();
}
// 停止拖動SeekBar 的時候將音樂定位到相應位置
public void onStopTrackingTouch(SeekBar seekBar) {
if (player != null) {
player.seekTo(seekBar.getProgress());
updateSeekBar();
}
}
// 工具函數格式化播放時間
private String formatTime(int current) {
int second = current / 1000;
int minute = second / 60;
second = second - minute * 60;
StringBuilder sb = new StringBuilder();
sb.append(minute > 10 ? minute + "" : "0" + minute);
sb.append(":");
sb.append(second > 10 ? second : "0" + second);
return sb.toString();
}
}
視頻播放
使用MediaPlayer+SurfaceView 播放視頻
代碼
public class MainActivity extends Activity {
private MediaPlayer mediaPlayer;
private int currentPosition; //當前視頻播放的位置
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[0]找到控件用來顯示播放視頻的內容
final SurfaceView sfv = (SurfaceView) findViewById(R.id.sfv);
//獲取holder 對象 用來維護視頻播放的內容
SurfaceHolder holder = sfv.getHolder();
//[0.1]添加holder 生命週期 方法
holder.addCallback(new Callback() {
//當surface view 銷燬
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("surfaceDestroyed");
//停止播放視頻
if (mediaPlayer!=null && mediaPlayer.isPlaying()) {
//獲取到當前播放視頻的位置
currentPosition = mediaPlayer.getCurrentPosition();
mediaPlayer.stop();
}
}
//這個方法執行了 說明sufaceView準備好了
@Override
public void surfaceCreated(SurfaceHolder holder) {
//[1]初始化mediaplayer
System.out.println("surfaceCreated");
mediaPlayer = new MediaPlayer();
//[2]設置要播放的資源位置 path 可以是網絡 路徑 也可是本地路徑
try {
mediaPlayer.setDataSource("http://192.168.11.86:8080/cc.MP4");
//[3]準備播放
mediaPlayer.prepareAsync();
//[3.0]設置顯示給sfv sufraceholder 是用來維護視頻播放的內容
mediaPlayer.setDisplay(holder);
//[3.1]設置一個準備完成的監聽
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//[4]開始播放
mediaPlayer.start();
//[5]繼續上次的位置繼續播放
mediaPlayer.seekTo(currentPosition);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
});
}
}
使用vitamio控件播放
控件清單文件初始化配置
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.itheima.videoView.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 一定要在清單文件初始化InitActivity -->
<activity android:name="io.vov.vitamio.activity.InitActivity"></activity>
</application>
使用全命名的標籤
<io.vov.vitamio.widget.VideoView
android:id="@+id/vv"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
代碼
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 插件vitamio框架檢查是否可用
if (!LibsChecker.checkVitamioLibs(this)) {
return;
}
final VideoView vv = (VideoView) findViewById(R.id.vv);
vv.setVideoPath("http://192.168.11.86:8080/aa.avi");
vv.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
vv.start();
}
});
//設置video的控制器
vv.setMediaController(new MediaController(this));
}
}
攝像頭
調用系統攝像頭進行拍照和攝像,只需知道系統攝像頭的action 和category 就可以調用系統攝像頭。
Camera 類的action 和category
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
VideoCamera 類的action 和category
<intent-filter>
<action android:name="android.media.action.VIDEO_CAMERA" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
TIPS
由於希望在調用拍照或攝像功能後回到當前應用的界面,且得知拍照或攝像的結果如何,是否成功,所以在開啓Activity 時不能使用startActivity 方法,而是使用startActivityForResult 方法開啓Activity,並重寫onActivityResult方法處理回傳的數據。
代碼示例
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//點擊按鈕進行照相
public void click1(View v){
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory().getPath(),"haha.png");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 保存圖片的位置
// start the image capture Intent
startActivityForResult(intent, 1);
}
//點擊按鈕進行錄像
public void click2(View v){
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
File file = new File(Environment.getExternalStorageDirectory().getPath(),"heheh.MP4");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 保存圖片的位置
// start the image capture Intent
startActivityForResult(intent, 2);
}
//當開啓的Activity關閉的時候調用
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("哈哈哈");
super.onActivityResult(requestCode, resultCode, data);
}
}
傳感器
Android 手機中內置了很多傳感器,其主要類型有:方向、加速度(重力)、光線、磁場、距離(臨近性)、溫度等
- 方向傳感器Sensor.TYPE_ORIENTATION
- 加速度(重力)傳感器Sensor.TYPE_ACCELEROMETER
- 光線傳感器Sensor.TYPE_LIGHT
- 磁場傳感器Sensor.TYPE_MAGNETIC_FIELD
- 距離(臨近性)傳感器Sensor.TYPE_PROXIMITY
- 溫度傳感器Sensor.TYPE_TEMPERATURE
獲取傳感器管理器SensorManager:
SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
通過傳感器管理器對象獲得指定類型的傳感器
Sensor sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
通過傳感器管理器對象獲得手機中所有的傳感器:
//獲取手機支持的所有傳感器
List<Sensor> sensorList = sm.getSensorList(Sensor.TYPE_ALL);
for (int i = 0; i < sensorList.size(); i++) {
Sensor sensor = sensorList.get(i);
// 獲取傳感器名稱
String name = sensor.getName();
// 獲取傳感器廠商
String vendor = sensor.getVendor();
// 獲取傳感器版本號
int version = sensor.getVersion();
}
使用傳感器管理器對象註冊傳感器來使一個傳感器工作
/*
* 註冊一個傳感器 第二個參數Sensor 是具體某個傳感器對象 第三個參數是設定傳感器採樣頻率
*/
sm.registerListener(new SensorEventListener() {
// 當傳感器值改變時觸發該函數
@Override
public void onSensorChanged(SensorEvent event) {
Toast.makeText(MainActivity.this, "" + event.accuracy, 0)
.show();
}
// 當傳感器精確度更改是觸發該函數
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Toast.makeText(MainActivity.this, "" + accuracy, 1).show();
}
}, sensor, SensorManager.SENSOR_DELAY_NORMAL);
- listener :傳感器事件監聽器
- sensor :要被註冊的傳感器對象
- rate :採樣率,分爲最快、遊戲、普通、用戶界面幾種當應用程序請求特定的採樣率時,其實只是對傳感器子系統的一個建議,不保證特定的採樣率可用。
採樣率的四種類型詳解:
最快: SensorManager.SENSOR_DELAY_FASTEST
最低延遲,一般不是特別敏感的處理不推薦使用,該種模式可能造成手機電力大量消耗,由於傳遞的爲原始數據,算法不處理好將會影響遊戲邏輯和UI 的性能
遊戲: SensorManager.SENSOR_DELAY_GAME
遊戲延遲,一般絕大多數的實時性較高的遊戲都使用該級別
普通: SensorManager.SENSOR_DELAY_NORMAL
標準延遲,對於一般的益智類或EASY 級別的遊戲可以使用,但過低的採樣率可能對一些賽車類遊戲有跳幀現象
用戶界面: SensorManager.SENSOR_DELAY_UI
一般對於屏幕方向自動旋轉使用,相對節省電能和邏輯處理,一般遊戲開發中我們不使用
案例手機防盜
當手機從衣服兜裏被掏出時,手機響鈴報警
原理:
使用距離傳感器,當距離從0 變爲1 時,使用MediaPlayer 播放聲音文件報警
繼承SensorEventListener 並覆寫抽象方法
public void onSensorChanged(SensorEvent event) {
// 獲取距離傳感器的值
float value = event.values[0];
if (value > 0) {
try {
// 如果距離大於0 則播放音樂
player.start();
} catch (Exception e) {
e.printStackTrace();
}
} else {
// 如果距離等於0 暫停音樂
player.pause();
}
}