編輯:關於Android編程
Android的傳感器開發
Android的常用傳感器
傳感器應用案例
Android的傳感器開發
1.1 開發傳感器應用
開發傳感器的步驟如下:
調用Context的getSystemService(Context.SENSOR_SERVICE)方法獲取SensorManager對象。
調用SensorManager的getDefaultSensor(int type)方法來獲取指定類型的傳感器。
一般在Activity的onResume()方法中調用SensorManager的registerListener()為指定傳感器注冊監聽器即可。程序可以通過實現監聽器即可獲取傳感器傳回來的數據。
SersorManager提供的注冊傳感器的方法為registerListener(SensorListener listener, Sensor sensor, int rate)該方法中三個參數說明如下:
listener:監聽傳感器事件的監聽器
sensor:傳感器對象
rate:指定獲取傳感器數據的頻率
rate可以獲取傳感器數據的頻率,支持如下幾個頻率值:
SENSOR_DELAY_FASTEST:最快,延遲最小。
SENSOR_DELAY_GAME:適合游戲的頻率。
SENSOR_DELAY_NORMAL:正常頻率
SENSOR_DELAY_UI:適合普通用戶界面的頻率。
例:加速度傳感器:
AccelerometerTest.java
public class AccelerometerTest extends Activity
implements SensorEventListener
{
// 定義系統的Sensor管理器
SensorManager sensorManager;
EditText etTxt1;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取程序界面上的文本框組件
etTxt1 = (EditText) findViewById(R.id.txt1);
// 獲取系統的傳感器管理服務
sensorManager = (SensorManager) getSystemService(
Context.SENSOR_SERVICE);
}
@Override
protected void onResume()
{
super.onResume();
// 為系統的加速度傳感器注冊監聽器
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
// 取消注冊
sensorManager.unregisterListener(this);
super.onStop();
}
// 以下是實現SensorEventListener接口必須實現的方法
// 當傳感器的值發生改變時回調該方法
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
StringBuilder sb = new StringBuilder();
sb.append(X方向上的加速度:);
sb.append(values[0]);
sb.append(
Y方向上的加速度:);
sb.append(values[1]);
sb.append(
Z方向上的加速度:);
sb.append(values[2]);
etTxt1.setText(sb.toString());
}
// 當傳感器精度改變時回調該方法。
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
需要指出的是,傳感器的坐標系統與屏幕坐標系統不同,傳感器坐標系統的X軸沿屏幕向右;Y軸則沿屏幕向上,Z軸在垂直屏幕向上。
當拿著手機橫向左右移動時,可能產生X軸上的加速度;拿著手機前後移動時,可能產生Y軸上的加速度;當拿著手機豎向上下移動時,可能產生Z軸上的加速度。
1.2 下載和安裝SensorSimulator
SensorSimulator是傳感器的模擬工具,安裝這個模擬工具之後,開發者就可以在Android模擬器上開發、調試傳感器應用。
SensorSimulator,由PC端程序和手機端程序組成,當兩端的程序運行並建立連接之後,用戶可以通過PC端的程序來改變手機的傳感數據。
下載和安裝SensorSimulator步驟如下:
登錄到http://code.google.com/p/openintents/wiki/SensorSimulator站點或FTP上,下載SensorSimulator的最新版本。
下載SensorSimulator工具後,下載完成後得到一個sensorsimulator-2.0-rc1.zip壓縮包。解壓該文件,得到如下文件結構。
安裝SensorSimulator的手機端程序。通過命令窗口進入到上面文件的bin目錄下,輸入如下命令來安裝SensorSimulatorSettings-2.0-rc1.apk文件。adb install SensorSimulatorSettings-2.0-rc1.apk
運行SensorSimulator的PC端程序,通過命令窗口進入到上面文件的bin目錄下,並在窗口內執行如下命令:java –jar sensorsimulator-2.0-rc1.jar。運行該程序出現如下界面。
運行SensorSimulator的手機端程序。
在SensorSimulator的手機端程序中填寫SensorSimulator的PC端程序的監聽IP地址、監聽端口。
切換到SensorSimulator的Testting Tab頁,單擊該Tab裡的Connect按鈕,SensorSimulator手機端和PC端連接。
1.3 利用SensorSimulator開發傳感器應用
通過使用SensorSimulator,接下來就可以在Android模擬器中開發、調試傳感器應用了。不過使用SensorSimulator開發傳感器應用與開發真實的傳感器應用略有區別。
Android應用必須通過引用外部JAR包的形式來引用SensorSimulator的lib目錄下的sensorsimulator-2.0-rc1.jar包。
在應用項目上右鍵單擊選擇“Build Path” à “Add External Archives…”,找到sensorsimulator-2.0-rc1.jar所在位置,將其添加到項目中。
應用程序編程使用SensorManagerSimulator代替了原有的SensorManager。
應用程序獲取SensorManagerSimulator之後,需要調用connectSimulator()方法連接模擬器。
應用程序編程時所用的Sensor、SensorEvent、 SensorEventListener等不再是Android提供的類,而是由SensorSimulator提供的類。
應用程序需要訪問網絡的權限。
例:利用傳感模擬工具開發加速度傳感器:
AccelSimulatorTest.java
import org.openintents.sensorsimulator.hardware.SensorManagerSimulator;
import org.openintents.sensorsimulator.hardware.Sensor;
import org.openintents.sensorsimulator.hardware.SensorEvent;
import org.openintents.sensorsimulator.hardware.SensorEventListener;
import android.app.Activity;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.EditText;
public class AccelSimulatorTest extends Activity
implements SensorEventListener
{
// 定義模擬器的Sensor管理器
private SensorManagerSimulator mSensorManager;
// 定義界面上的文本框組件
EditText etTxt1;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取程序界面的文本框組件
etTxt1 = (EditText) findViewById(R.id.txt1);
// 獲取傳感器模擬器的傳感器管理服務
mSensorManager = SensorManagerSimulator.getSystemService(
this, SENSOR_SERVICE);
// 連接傳感器模擬器
mSensorManager.connectSimulator();
}
@Override
protected void onResume()
{
super.onResume();
// 為系統的加速度傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onStop();
}
// 以下是實現SensorEventListener接口必須實現的方法
// 當傳感器的值發生改變時回調該方法
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
StringBuilder sb = new StringBuilder();
sb.append(X方向上的加速度:);
sb.append(values[0]);
sb.append(
Y方向上的加速度:);
sb.append(values[1]);
sb.append(
Z方向上的加速度:);
sb.append(values[2]);
etTxt1.setText(sb.toString());
}
@Override
// 當傳感器精度改變時回調該方法。
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
Android的常用傳感器
2.1加速度傳感器Accelerometer
加速度傳感器主要感應手機的運動,在注冊了傳感器監聽器後加速度傳感器主要捕獲3個參數values[0]、values[1]、values[2]。
values[0]:空間坐標系中x軸方向上的加速度減去重力加速度減去中立加速度在x軸上的分量。
values[1]:空間坐標系中x軸方向上的加速度減去重力加速度減去中立加速度在y軸上的分量。
values[2]:空間坐標系中x軸方向上的加速度減去重力加速度減去中立加速度在z軸上的分量。
上述3個數據的單位均為米每二次方秒。
距離說明:
當手機平放到桌面靜止時,加速度為重力加速度g,通過0減去-g(重力加速度g方向為z軸反方向,故為負值)得到values[2]為g。
如果把手機水平方向右推,此時手機x方向上的加速度為正,即values[0]為正。
當把手機以a米每二次方秒的加速度豎值向上舉時,values[2]的返回值為(a+g)米每二次方秒,通過a減去-g得到。
2.2 方向傳感器Orientation
方向傳感器主要感應手機方位的變化,其每次讀取的都是靜態的狀態值,在注冊了傳感器監聽器後方向傳感器主要捕獲3個參數values[0]、values[1]、values[2],關於三個角度的說明如下:
第一個角度:表示手機頂部朝向與正北方向的夾角。當手機繞著Z軸旋轉時,該角度值發生改變。
第二個角度:表示手機頂部或尾部翹起的角度,當手機繞著X軸傾斜時,該角度值發生變化。
第三個角度:表示手機左側或右側翹起的角度。當手機繞著Y軸傾斜時,該角度值發生變化。
2.3磁場傳感器Magnetic Field
磁場傳感器主要用於感應周圍的磁感應強度。即使周圍沒有任何直接的磁場,手機設備也始終會處於地球磁場中。隨著手機狀態設備擺放狀態的改變,周圍磁場在手機的X、Y、Z方向上的會發生改變。
磁場傳感器傳感器會返回三個數據,三個數據分別代表周圍磁場分解到X、Y、Z三個方向上的磁場分量。磁場數據的單位是微特斯拉(uT)。
2.4光傳感器Light
光傳感器用於感應周圍的光強,注冊監聽器後只捕獲一個參數:values[0]。該參數代表周圍的光照強度,單位為勒克斯(lux)。
2.5溫度傳感器Temperature
溫度傳感器用於獲取手機設備所處環境的溫度。溫度傳感器會返回一個數據,該數據代表手機設備周圍的溫度,單位是攝氏度。
2.6壓力傳感器 Pressure
壓力傳感器用於獲取手機設備所處環境的壓力的大小。壓力傳感器會返回一個數據,代表手機設備周圍的壓力大小。
例:傳感器應用:
SensorSimulatorTest.java
public class SensorSimulatorTest extends Activity
implements SensorEventListener
{
// // 定義真機的Sensor管理器
// private SensorManager mSensorManager;
// 定義模擬器的Sensor管理器
private SensorManagerSimulator mSensorManager;
EditText etOrientation;
EditText etMagnetic;
EditText etTemerature;
EditText etLight;
EditText etPressure;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取界面上的EditText組件
etOrientation = (EditText) findViewById(R.id.etOrientation);
etMagnetic = (EditText) findViewById(R.id.etMagnetic);
etTemerature = (EditText) findViewById(R.id.etTemerature);
etLight = (EditText) findViewById(R.id.etLight);
etPressure = (EditText) findViewById(R.id.etPressure);
// 獲取真機的傳感器管理服務
// mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// 獲取傳感器模擬器的傳感器管理服務
mSensorManager = SensorManagerSimulator.getSystemService(this,
SENSOR_SERVICE);
// 連接傳感器模擬器
mSensorManager.connectSimulator();
}
@Override
protected void onResume()
{
super.onResume();
// 為系統的方向傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
// 為系統的磁場傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_GAME);
// 為系統的溫度傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE),
SensorManager.SENSOR_DELAY_GAME);
// 為系統的光傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_GAME);
// 為系統的壓力傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
// 程序退出時取消注冊傳感器監聽器
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
protected void onPause()
{
// 程序暫停時取消注冊傳感器監聽器
mSensorManager.unregisterListener(this);
super.onPause();
}
// 以下是實現SensorEventListener接口必須實現的方法
@Override
// 當傳感器精度改變時回調該方法。
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
// // 真機上獲取觸發event的傳感器類型
// int sensorType = event.sensor.getType();
// 模擬器上獲取觸發event的傳感器類型
int sensorType = event.type;
StringBuilder sb = null;
// 判斷是哪個傳感器發生改變
switch (sensorType)
{
// 方向傳感器
case Sensor.TYPE_ORIENTATION:
sb = new StringBuilder();
sb.append(繞Z軸轉過的角度:);
sb.append(values[0]);
sb.append(
繞X軸轉過的角度:);
sb.append(values[1]);
sb.append(
繞Y軸轉過的角度:);
sb.append(values[2]);
etOrientation.setText(sb.toString());
break;
// 磁場傳感器
case Sensor.TYPE_MAGNETIC_FIELD:
sb = new StringBuilder();
sb.append(X方向上的角度:);
sb.append(values[0]);
sb.append(
Y方向上的角度:);
sb.append(values[1]);
sb.append(
Z方向上的角度:);
sb.append(values[2]);
etMagnetic.setText(sb.toString());
break;
// 溫度傳感器
case Sensor.TYPE_TEMPERATURE:
sb = new StringBuilder();
sb.append(當前溫度為:);
sb.append(values[0]);
etTemerature.setText(sb.toString());
break;
// 光傳感器
case Sensor.TYPE_LIGHT:
sb = new StringBuilder();
sb.append(當前光的強度為:);
sb.append(values[0]);
etLight.setText(sb.toString());
break;
// 壓力傳感器
case Sensor.TYPE_PRESSURE:
sb = new StringBuilder();
sb.append(當前壓力為:);
sb.append(values[0]);
etPressure.setText(sb.toString());
break;
}
}
}
傳感器應用案例
對傳感器的支持是Android系統的特性之一,通過使用傳感器可以開發出各種有趣的應用,我們通過方向傳感器來開發指南針。
開發指南針的思路比較簡單:程序先准備一張指南針圖片,該圖片上方向指針指向北方。接下來開發一個檢測方向的傳感器,程序檢測到手機頂部繞Z軸轉過多少度,讓指南針圖片反向轉過多少度即可。
該應用中只要在界面中添加一張圖片,並讓圖片總是反向轉過方向傳感器反回的第一個角度即可。
例:指南針:
Compass.java
public class Compass extends Activity
implements SensorEventListener
{
// 定義顯示指南針的圖片
ImageView znzImage;
// 記錄指南針圖片轉過的角度
float currentDegree = 0f;
// 定義模擬器的Sensor管理器
// private SensorManagerSimulator mSensorManager;
// 定義真機的Sensor管理器
SensorManager mSensorManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取界面中顯示指南針的圖片
znzImage = (ImageView) findViewById(R.id.znzImage);
// 獲取真機的傳感器管理服務
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// // 獲取傳感器模擬器的傳感器管理服務
// mSensorManager = SensorManagerSimulator.getSystemService(this,
// SENSOR_SERVICE);
// // 連接傳感器模擬器
// mSensorManager.connectSimulator();
}
@Override
protected void onResume()
{
super.onResume();
// 為系統的方向傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onStop()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onSensorChanged(SensorEvent event)
{
// 真機上獲取觸發event的傳感器類型
int sensorType = event.sensor.getType();
// // 模擬器上獲取觸發event的傳感器類型
// int sensorType = event.type;
switch (sensorType)
{
case Sensor.TYPE_ORIENTATION:
// 獲取繞Z軸轉過的角度。
float degree = event.values[0];
// 創建旋轉動畫(反向轉過degree度)
RotateAnimation ra = new RotateAnimation(currentDegree,
-degree, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
// 設置動畫的持續時間
ra.setDuration(200);
// 運行動畫
znzImage.startAnimation(ra);
currentDegree = -degree;
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
main.xml
例:水平儀:
Gradienter.java
public class Gradienter extends Activity implements SensorEventListener
{
// 定義水平儀的儀表盤
MyView show;
// 定義水平儀能處理的最大傾斜角,超過該角度,氣泡將直接在位於邊界。
int MAX_ANGLE = 30;
// // 定義真機的Sensor管理器
// SensorManager mSensorManager;
// 定義模擬器的Sensor管理器
SensorManagerSimulator mSensorManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 獲取水平儀的主組件
show = (MyView) findViewById(R.id.show);
// 獲取真機的傳感器管理服務
// mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// 獲取傳感器模擬器的傳感器管理服務
mSensorManager = SensorManagerSimulator.getSystemService(this,
SENSOR_SERVICE);
// 連接傳感器模擬器
mSensorManager.connectSimulator();
}
@Override
public void onResume()
{
super.onResume();
// 為系統的方向傳感器注冊監聽器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onStop()
{
// 取消注冊
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
// // 真機上獲取觸發event的傳感器類型
// int sensorType = event.sensor.getType();
// 模擬器上獲取觸發event的傳感器類型
int sensorType = event.type;
switch (sensorType)
{
case Sensor.TYPE_ORIENTATION:
// 獲取與Y軸的夾角
float yAngle = values[1];
// 獲取與Z軸的夾角
float zAngle = values[2];
// 氣泡位於中間時(水平儀完全水平),氣泡的X、Y座標
int x = (show.back.getWidth() - show.bubble.getWidth()) / 2;
int y = (show.back.getHeight() - show.bubble.getHeight()) / 2;
// 如果與Z軸的傾斜角還在最大角度之內
if (Math.abs(zAngle) <= MAX_ANGLE)
{
// 根據與Z軸的傾斜角度計算X座標的變化值(傾斜角度越大,X座標變化越大)
int deltaX = (int) ((show.back.getWidth() - show.bubble
.getWidth()) / 2 * zAngle / MAX_ANGLE);
x += deltaX;
}
// 如果與Z軸的傾斜角已經大於MAX_ANGLE,氣泡應到最左邊
else if (zAngle > MAX_ANGLE)
{
x = 0;
}
// 如果與Z軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊
else
{
x = show.back.getWidth() - show.bubble.getWidth();
}
// 如果與Y軸的傾斜角還在最大角度之內
if (Math.abs(yAngle) <= MAX_ANGLE)
{
// 根據與Y軸的傾斜角度計算Y座標的變化值(傾斜角度越大,Y座標變化越大)
int deltaY = (int) ((show.back.getHeight() - show.bubble
.getHeight()) / 2 * yAngle / MAX_ANGLE);
y += deltaY;
}
// 如果與Y軸的傾斜角已經大於MAX_ANGLE,氣泡應到最下邊
else if (yAngle > MAX_ANGLE)
{
y = show.back.getHeight() - show.bubble.getHeight();
}
// 如果與Y軸的傾斜角已經小於負的MAX_ANGLE,氣泡應到最右邊
else
{
y = 0;
}
// 如果計算出來的X、Y座標還位於水平儀的儀表盤內,更新水平儀的氣泡座標
if (isContain(x, y))
{
show.bubbleX = x;
show.bubbleY = y;
}
// 通知系統重回MyView組件
show.postInvalidate();
break;
}
}
// 計算x、y點的氣泡是否處於水平儀的儀表盤內
private boolean isContain(int x, int y)
{
// 計算氣泡的圓心座標X、Y
int bubbleCx = x + show.bubble.getWidth() / 2;
int bubbleCy = y + show.bubble.getWidth() / 2;
// 計算水平儀儀表盤的圓心座標X、Y
int backCx = show.back.getWidth() / 2;
int backCy = show.back.getWidth() / 2;
// 計算氣泡的圓心與水平儀儀表盤的圓心之間的距離。
double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)
+ (bubbleCy - backCy) * (bubbleCy - backCy));
// 若兩個圓心的距離小於它們的半徑差,即可認為處於該點的氣泡依然位於儀表盤內
if (distance < (show.back.getWidth() - show.bubble.getWidth()) / 2)
{
return true;
}
else
{
return false;
}
}
}
MyView.java
public class MyView extends View
{
// 定義水平儀儀表盤圖片
Bitmap back;
// 定義水平儀中的氣泡圖標
Bitmap bubble;
// 定義水平儀中氣泡 的X、Y座標
int bubbleX, bubbleY;
public MyView(Context context, AttributeSet attrs)
{
super(context, attrs);
// 加載水平儀圖片和氣泡圖片
back = BitmapFactory.decodeResource(getResources()
, R.drawable.back);
bubble = BitmapFactory
.decodeResource(getResources(), R.drawable.bubble);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// 繪制水平儀表盤圖片
canvas.drawBitmap(back, 0, 0, null);
// 根據氣泡座標繪制氣泡
canvas.drawBitmap(bubble, bubbleX, bubbleY, null);
}
}
<framelayout android:background="#fff" android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"></framelayout>
Android 破解視頻App去除廣告功能詳解及解決辦法總結
Android 破解視頻App去除廣告功能作為一個屌絲程序猿也有追劇的時候,但是當打開視頻app的時候,那些超長的廣告已經讓我這個屌絲無法忍受了,作為一個程序猿看視頻還要
Android自定義Animation實現View搖擺效果
使用自定義Animation,實現View的左右搖擺效果,如圖所示:代碼很簡單,直接上源碼activity_maini.xml布局文件:<?xml vers
Android評論功能的實現過程
目前,各種App的社區或者用戶曬照片、發說說的地方,都提供了評論功能,為了更好地學習,自己把這個功能實現了一下,做了個小的Demo。首先推薦一款實用的插件LayoutCr
android實現圖片驗證碼方法解析(自繪控件)
自繪控件的內容都是自己繪制出來的 大致流程如下:1.定義一個類繼承view 1.使用TypedArray初始化屬性集合 在