編輯:關於Android編程
本文將介紹Android設備中的傳感器。
大部分Android設備內置了大量的傳感器,比較常見的有測量位移的、感應方向的、感應周圍環境變化的 等等。這些傳感器都能反饋高精度的原始數據、而且可以監測設備在三個方向上的位移和周圍環境的變化 等。比如,在一款天氣應用程序中可以使用溫度傳感器和濕度傳感器得到周圍環境的變化;在一款旅游應用程序中可以使用地磁傳感器和加速器設定指南針的方向。
Android設備提供三種類型的傳感器:
運動傳感器(Motion sensors):這類傳感器可以監測設備在三個坐標軸所在方向上的加速力和旋轉力( measure acceleration forces and rotational forces along three axes)。主要有:加速計(accelerometers)、重力傳感器(gravity sensors)、陀螺儀( gyroscopes)和旋轉向量傳感器( rotational vector sensors)等。
環境傳感器(Environmental sensors):這類傳感器可以監測設備所在的環境參數,如溫度、氣壓、亮度、濕度 等(measure various environmental parameters, such as ambient air temperature and pressure, illumination, and humidity)。主要有:氣壓計(barometers)、光度計(photometers)、溫度計(thermometers)等。
位置傳感器(Position sensors):這類傳感器可以監測設備所在物理位置。如方向傳感器和磁力儀(orientation sensors and magnetometers)。
使用Android中的API可以輕松獲取各類傳感器所檢測的原始數據。例如,您可以通過這些API做以下事:
當前設備中所包含的傳感器數量和類別;
每一個傳感器的參數。如可測量的最大值、生產商、所需功率、測量精確度 等( maximum range, manufacturer, power requirements, and resolution)。
從傳感器中獲取數據的間隔(頻率)。
當傳感器的狀態發生變化時,可以通過注冊監聽器的方式監聽。
從底層驅動劃分,傳感器還可以分為硬件驅動型和軟件驅動型。硬件驅動的傳感器(Hardware-based sensors)是內嵌於Android設備中的實實在在的物理部件。這些物理部件通過自身可以檢測周圍的環境屬性,並輸出測量數據,如加速度、地磁場強、角度變化 等。盡管由軟驅動的傳感器(Software-based sensors)看起來與硬件驅動的傳感器高度相似,但前者並不是物理部件。軟件驅動的傳感器提供的數據通常是由若干個不同類型的硬件驅動的傳感器的輸出結果經過計算合成的,所以有時也將它們稱作虛擬傳感器或者合成傳感器( virtual sensors or synthetic sensors)。線性加速器和重力傳感器就屬於軟驅動傳感器。下面的表格對Android各類傳感器作了簡要介紹。
在一個設備中,同一種類型的傳感器,可能有多個。比方說,一個設備中含有兩個重力傳感器,每個傳感器用於測量不同的范圍。
您可以通過Android傳感器框架獲取這些傳感器實例以及返回的監測參數。這面介紹的這些類或是接口,都在android.hardware包中。
SensorManager:您可以通過這個類獲取傳感器服務的實例。該類提供了獲取不同種類傳感器實例的方式、綁定和解除綁定監聽傳感器的方式、以及獲取設備朝向參數的方式(This class provides various methods for accessing and listing sensors, registering and unregistering sensor event listeners, and acquiring orientation information)。該類還提供了若干靜態常量,用於控制傳感器的監測精度和返回數據的頻率,以及校准方式(This class also provides several sensor constants that are used to report sensor accuracy, set data acquisition rates, and calibrate sensors)。
Sensor:通過該類可以獲取指定的傳感器實例。 通過這個實例,您可以調用大量方法來操作傳感器。
SensorEvent:通過這個類,可以創建一個傳感器事件的實例,該實例包含了這些信息:傳感器的原始數據、生成的傳感器事件的類型、數據的精度、事件的時間戳( the raw sensor data, the type of sensor that generated the event, the accuracy of the data, and the timestamp for the event)。
SensorEventListener:這個回調接口包含兩個方法,當傳感器監測的參數或精度發生變化時,這兩個方法用於接收傳感器事件返回的通知。
一般在應用中使用以上API的典型方式為:
確定傳感器的類型以及傳感器的功能(Identifying sensors and sensor capabilities):如果在您的應用程序中,某個功能需要通過特定傳感器的特定功能來實現,那麼檢測設備中的傳感器並尋找合適的類型並使用其特定功能就顯得很有必要。
監測傳感器事件(Monitor sensor events):監測傳感器事件,即如何獲取傳感器的原始數據。當監測數據發生變化時,傳感器事件都會回傳最新的數據。這些數據包含四部分:觸發事件的傳感器的名字、事件的時間戳、事件的精確度、出發事件的原始數據( the name of the sensor that triggered the event, the timestamp for the event, the accuracy of the event, and the raw sensor data that triggered the event)。
不同的設備、不同的Android版本都具有不同的傳感器。下面的這些傳感器是在Android 4.0及以上版本中可用的傳感器(有些已被廢棄但仍然可用):
TYPE_ACCELEROMETER;
TYPE_AMBIENT_TEMPERATURE;
TYPE_GRAVITY;
TYPE_GYROSCOPE;
TYPE_LIGHT;
TYPE_LINEAR_ACCELERATION;
TYPE_MAGNETIC_FIELD;
TYPE_ORIENTATION(已被廢棄但仍然可用);
TYPE_PRESSURE;
TYPE_PROXIMITY;
TYPE_RELATIVE_HUMIDITY;
TYPE_ROTATION_VECTOR;
TYPE_TEMPERATURE(已被廢棄但仍然可用)。
獲取SensorManager實例的方式如下:
private SensorManager mSensorManager; ... mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
獲取當前設備中所有的傳感器列表的方式如下:
ListdeviceSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
若您需要獲取某一種特定類型的所有傳感器列表,那麼需要將TYPE_ALL常量替換為:
Sensor.TYPE_GYROSCOPE:這表示您需要獲取所有具備陀螺儀功能的傳感器列表;
Sensor.TYPE_LINEAR_ACCELERATION:這表示您需要獲取所有具備線性加速器功能的傳感器列表;
Sensor.TYPE_GRAVITY:這表示您需要獲取所有具備重力儀功能的傳感器列表;
您還可以調用getDefaultSensor()方法來判斷設備中是否具有指定類型的傳感器,若具有至少一個,那麼方法將不返回空,否則將返回空,方式如下:
private SensorManager mSensorManager; ... mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){ // 設備中至少內置了一個磁力計 } else { // 設備中沒有內置磁力計 }
除此之外,通過調用Sersor類中公有方法,您還可以為指定的傳感器設置參數以決定其屬性。比如,調用getResolution()和getMaximumRange()方法可以分別獲取傳感器的回傳原始數據的頻率和測量范圍。調用getPower()方法可以獲取傳感器工作的額定功率。
通過調用Sensor類的getVendor()和getVersion()方法,可以獲取設備中指定生產廠商和指定版本的傳感器。假如您需要監測用戶對設備的傾斜或搖動手勢( tilt and shake),那麼您需要使用重力儀,下面的例子演示了“在設備的所有重力儀中,獲取生產廠商為Google Inc.、版本為3的重力儀傳感器。如果設備中沒有滿足該條件的傳感器,那麼就是用加速器代替,若加速器也沒有,那麼監測用戶手勢的功能將無法實現。
private SensorManager mSensorManager; private Sensor mSensor; ... mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mSensor = null; if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){ List<sensor> gravSensors = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY); for(int i=0; i<gravsensors.size(); i++)="" {="" if="" ((gravsensors.get(i).getvendor().contains("google="" inc."))="" &&="" (gravsensors.get(i).getversion()="=" 3)){="" use="" the="" version="" 3="" gravity="" sensor.="" msensor="gravSensors.get(i);" }="" (msensor="=" null){="" accelerometer.="" (msensormanager.getdefaultsensor(sensor.type_accelerometer)="" !="null){" else{="" sorry,="" there="" are="" no="" accelerometers="" on="" your="" device.="" you="" can't="" play="" this="" game.="" }
還有一些實用方法:getMinDelay()返回一個整數,單位是微秒(microseconds),表示傳感器回傳原始數據的間隔,若返回的值不是0,表示這是一個流傳感器( streaming sensor),流傳感器說的是:不論傳感器回傳的原始監測數據有沒有變化,傳感器均按照這個間隔回傳數據。相反若getMinDelay()返回0,表示不是流傳感器,非流傳感器表示只有監測的數據發生變化時,傳感器才回傳數據。
為了監聽傳感器回傳的原始數據,您需要實現SensorEventListener接口中的兩個回調方法:onAccuracyChanged() 和 onSensorChanged()。當下列事件發生時,系統會回調這兩個方法:
當傳感器的精度發生變化時(A sensor’s accuracy changes):在這種情況下,onAccuracyChanged()被回調,並回傳一個Sensor類對象的引用,以調整傳感器的精度。精度分為四個等級:SENSOR_STATUS_ACCURACY_LOW、SENSOR_STATUS_ACCURACY_MEDIUM、SENSOR_STATUS_ACCURACY_HIGH、SENSOR_STATUS_UNRELIABLE。
傳感器回傳了新的原始數據時(A sensor reports a new value):這時,onSensorChanged()被回調。並回傳一個SensorEvent 類對象的引用,該對象包含了最新的原始數據,它包括:數據的精度、產生數據的傳感器、數據產生的時間戳、新的數據 等( the accuracy of the data, the sensor that generated the data, the timestamp at which the data was generated, and the new data that the sensor recorded)。
下面演示了監聽光照傳感器的原始數據,並將數據顯示在TextView上:
public class SensorActivity extends Activity implements SensorEventListener { private SensorManager mSensorManager; private Sensor mLight; @Override public final void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); } @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) { // Do something here if sensor accuracy changes. } @Override public final void onSensorChanged(SensorEvent event) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. float lux = event.values[0]; // Do something with this sensor value. } @Override protected void onResume() { super.onResume(); mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(this); } }
其中registerListener()方法的第三個參數表示指定傳感器回傳數據的頻率,SENSOR_DELAY_NORMAL表示回傳數據的頻率是200,000微秒( 0.2秒);其他的常量還有SENSOR_DELAY_GAME,表示間隔20,000微秒( 0.02秒);SENSOR_DELAY_UI,表示間隔60,000 微秒(0.06秒);SENSOR_DELAY_FASTEST,表示最快。
在Mainfest.xml中配置
在
Android中傳感器的坐標系如下圖所示: vc/yysfK+sbBtcSjrNKyvs3Kx8u1o6y0y8qxedbhysfK+s/ytcSjrLb4xr2w5bXnxNS1xMSsyM+3vc/yyse64cbBtcSjrLTLyrF51uHSssrHyvrWsc/yyc+1xKOotLnWsdPav+2x36OpoaM8L3A+PGhyPjxoMiBpZD0="使用傳感器的注意事項best-practices-for-accessing-and-using-sensors">使用傳感器的注意事項(Best Practices for Accessing and Using Sensors)
private SensorManager mSensorManager; ... @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(this); }
不要在模擬器上測試傳感器(Don’t test your code on the emulator);
不要在onSensorChanged()方法中做大量操作(Don’t block the onSensorChanged() method):onSensorChanged()方法需要以較高的頻率不斷回傳數據,所以不要阻塞該方法;
避免使用廢棄的方法和常量(Avoid using deprecated methods or sensor types):TYPE_ORIENTATION這種類型的傳感器已被廢棄,欲獲取方向,應調用getOrientation()方法;同樣,TYPE_TEMPERATURE常量已被廢棄,您應當使用TYPE_AMBIENT_TEMPERATURE常量替代。
在使用傳感器之前一定要核實(Verify sensors before you use them):任何傳感器都不是現成提供好的,需要您自己實例化;
謹慎設定傳感器數據的回傳頻率 (Choose sensor delays carefully):當頻率較高時,比較耗電。
在網絡加載數據的時候通常需要很多時間,這個時候程序裡面經常需要寫一個提示正在加載數據的彈窗,這篇文章用兩種方式實現帶動畫效果的Dialog:幀動畫實現和GIF動態圖實現,
Android圖表庫MPAndroidChart(十三)——簡約的底部柱狀圖。我們繼續上一講,今天還是說下柱狀圖,這個圖的話應該是用的比較多的,所
今天在逛安智的時候看到一個軟件,我對注冊碼驗證的程序比較感興趣哈,- -那個帖子的軟件是通過爆破法實現破解的,之前我在這個帖子講過http://www.52pojie.c
一.Eclipse Heap分析內存洩露Android開發中避免不了碰到內存洩露問題,這裡先大概講下內存洩露的基本概念:內存洩露官方的解釋是是用動態存儲分配函數動態開辟的