- Android傳感器開發與智能設備案例實戰
- 朱元波
- 3732字
- 2019-01-05 01:08:06
第6章 Android傳感器系統概覽
在Android系統中提供的主要傳感器有加速度、磁場、方向、陀螺儀、光線、壓力、溫度和接近等傳感器。傳感器系統會主動對上層報告傳感器精度和數據的變化,并且提供了設置傳感器精度的接口,這些接口可以在Java應用和Java框架中使用。本章將詳細講解在Android系統中使用傳感器技術開發智能設備應用程序的基本流程,為讀者步入本書后面知識的學習打下堅實的基礎。
6.1 Android設備的傳感器系統
本書在前面第5章中,已經詳細講解了Android傳感器系統的基本架構。本節將詳細講解調用傳感器API接口,在Android智能設備中開發應用程序的方法。
6.1.1 包含的傳感器
在安裝Android SDK后,依次打開安裝目錄中下面的幫助文件。
android SDK/sdk/docs/reference/android/hardware/Sensor.html
在此文件中列出了Android傳感器系統所包含的所有傳感器類型,如圖6-1所示。

▲圖6-1 Android傳感器系統的類型
另外,也可以直接在線登錄http://developer.android.com/reference/android/hardware/Sensor.html來查看。由此可見,在當前最新(作者寫稿時最新)版本Android 4.4中一共提供了18種傳感器API接口。各個類型的具體說明如下所示。
(1)TYPE_ACCELEROMETER:加速度傳感器,單位是m/s2,測量應用于設備x、y、z軸上的加速度,又叫作G-sensor。
(2)TYPE_AMBIENT_TEMPERATURE:溫度傳感器,單位是℃,能夠測量并返回當前的溫度。
(3)TYPE_GRAVITY:重力傳感器,單位是m/s2,用于測量設備x、y、z軸上的重力,也叫作GV-sensor,地球上的數值是9.8 m/s2。
(4)TYPE_GYROSCOPE:陀螺儀傳感器,單位是rad/s2,能夠測量設備x、y、z三軸的角加速度數據。
(5)TYPE_LIGHT:光線感應傳感器,單位是lx,能夠檢測周圍的光線強度,在手機系統中主要用于調節LCD亮度。
(6)TYPE_LINEAR_ACCELERATION:線性加速度傳感器,單位是m/s2,能夠獲取加速度傳感器去除重力的影響得到的數據。
(7)TYPE_MAGNETIC_FIELD:磁場傳感器,單位是μT(微特斯拉),能夠測量設備周圍3個物理軸(x, y, z)的磁場。
(8)TYPE_ORIENTATION:方向傳感器,用于測量設備圍繞3個物理軸(x, y, z)的旋轉角度,在新版本中已經使用SensorManager.getOrientation()替代。
(9)TYPE_PRESSURE:氣壓傳感器,單位是hPa(百帕斯卡),能夠返回當前環境下的壓強。
(10)TYPE_PROXIMITY:距離傳感器,單位是cm,能夠測量某個對象到屏幕的距離。可以在打電話時判斷人耳到電話屏幕距離,以關閉屏幕而達到省電功能。
(11)TYPE_RELATIVE_HUMIDITY:濕度傳感器,能夠測量周圍環境的相對濕度。
(12)TYPE_ROTATION_VECTOR:旋轉向量傳感器,旋轉矢量代表設備的方向,是一個將坐標軸和角度混合計算得到的數據。
(13)TYPE_TEMPERATURE:溫度傳感器,在新版本中被TYPE_AMBIENT_TEMPERATURE替換。
(14)TYPE_ALL:返回所有的傳感器類型。
(15)TYPE_GAME_ROTATION_VECTOR:除了不能使用地磁場之外,和TYPE_ROTATION_VECTOR的功能完全相同。
(16)TYPE_GYROSCOPE_UNCALIBRATED:提供了能夠讓應用調整傳感器的原始值,定義了一個描述未校準陀螺儀的傳感器類型。
(17)TYPE_MAGNETIC_FIELD_UNCALIBRATED:和TYPE_GYROSCOPE_UNCALIBRATED相似,也提供了能夠讓應用調整傳感器的原始值,定義了一個描述未校準陀螺儀的傳感器類型。
(18)TYPE_SIGNIFICANT_MOTION:運動觸發傳感器,應用程序不需要為這種傳感器觸發任何喚醒鎖。能夠檢測當前設備是否運動,并發送檢測結果。
6.1.2 檢測當前設備支持的傳感器
在接下來的實例中,將演示在Android設備中檢測當前設備支持傳感器類型的方法。本實例的功能是檢測當前設備支持的傳感器類型,具體實現流程如下所示。

布局文件main.xml的具體實現代碼如下所示。
<linearlayout android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <textview android:layout_height="wrap_content" android:layout_width="fill_parent" android:text="" android:id="@+id/TextView01" > </textview> </linearlayout>
主程序文件MainActivity.java的具體實現代碼如下所示。
public class MainActivity extends Activity { /** Called when the activity is first created. */ @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //準備顯示信息的UI組建 final TextView tx1 = (TextView) findViewById(R.id.TextView01); //從系統服務中獲得傳感器管理器 SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE); //從傳感器管理器中獲得全部的傳感器列表 List<Sensor> allSensors = sm.getSensorList(Sensor.TYPE_ALL); //顯示有多少個傳感器 tx1.setText("經檢測該手機有" + allSensors.size() + "個傳感器,它們分別是:\n"); //顯示每個傳感器的具體信息 for (Sensor s : allSensors) { String tempString = "\n" + " 設備名稱:" + s.getName() + "\n" + " 設 備版本:"+s.getVersion()+"\n"+" 供應商:"+s.getVendor()+"\n"; switch (s.getType()) { case Sensor.TYPE_ACCELEROMETER: tx1.setText(tx1.getText().toString() + s.getType() + " 加速 度傳感器accelerometer" + tempString); break; case Sensor.TYPE_GYROSCOPE: tx1.setText(tx1.getText().toString() + s.getType() + " 陀螺 儀傳感器gyroscope" + tempString); break; case Sensor.TYPE_LIGHT: tx1.setText(tx1.getText().toString() + s.getType() + " 光線 感應傳感器light" + tempString); break; case Sensor.TYPE_MAGNETIC_FIELD: tx1.setText(tx1.getText().toString() + s.getType() + " 電磁 場傳感器magnetic field" + tempString); break; case Sensor.TYPE_ORIENTATION: tx1.setText(tx1.getText().toString() + s.getType() + " 方向 傳感器orientation" + tempString); break; case Sensor.TYPE_PRESSURE: tx1.setText(tx1.getText().toString() + s.getType() + " 壓力 傳感器pressure" + tempString); break; case Sensor.TYPE_PROXIMITY: tx1.setText(tx1.getText().toString() + s.getType() + " 距離 傳感器proximity" + tempString); break; case Sensor.TYPE_AMBIENT_TEMPERATURE : tx1.setText(tx1.getText().toString() + s.getType() + " 溫度 傳感器temperature" + tempString); break; default: tx1.setText(tx1.getText().toString() + s.getType() + " 未知 傳感器" + tempString); break; } } } }
上述實例代碼需要在真機中運行,執行后將會列表顯示當前設備所支持的傳感器類型。如圖6-2所示。

▲圖6-2 執行效果
6.2 使用SensorSimulator
在進行和傳感器相關的開發工作時,使用SensorSimulator可以提高開發效率。SensorSimulator是一個開源免費的傳感器小型工具,通過該工具可以在模擬器中調試傳感器的應用。搭建SensorSimulator開發環境的基本流程如下所示。
(1)下載SensorSimulator,讀者可從http://code.google.com/p/openintents/wiki/SensorSimulator網站找到該工具的下載鏈接。這里下載的是sensorsimulator-1.1.1.zip版本,如圖6-3所示。

▲圖6-3 下載sensorsimulator-1.1.1.zip
(2)將下載好的SensorSimulator解壓到本地根目錄,例如C盤的根目錄。
(3)向模擬器安裝SensorSimulatorSettings-1.1.1.apk。首先在操作系統中依次選擇“開始”|“運行”,進入“運行”對話框。
(4)在“運行”對話框輸入“cmd”進入cmd命令行,之后通過cd命令將當前目錄導航到SensorSimulatorSettings-1.1.1.apk目錄下,然后輸入下列命令向模擬器安裝該apk。
adb install SensorSimulatorSettings-1.1.1.apk
如圖6-4所示。在此需要注意的是,安裝apk時,一定要保證模擬器正在運行才可以,安裝成功后會輸出“Success”提示。

▲圖6-4 安裝apk
接下來開始配置應用程序,假設要在項目“jiaSCH”中使用SensorSimulator,則配置流程如下所示。
(1)在Eclipse中打開項目“jiaSCH”,然后為該項目添加JAR包,使其能夠使用SensorSimulator工具的類和方法。添加方法非常簡單,在Eclipse的Package Explorer中找到該項目的文件夾“jiaSCH”,然后右鍵單擊該文件夾并選擇“Properties”選項,彈出圖6-5所示的“Properties for jiaS”窗口。

▲圖6-5 “Properties for jiaS”窗口
(2)選擇左面的“Java Build Path”選項,然后單擊“Libraries”選項卡,如圖6-6所示。

▲圖6-6 “Libraries”選項卡
(3)單擊“Add External JARs”按鈕,在彈出的“JAR Selection”對話框中找到Sensorsimulator安裝目錄下的sensorsimulator-lib-1.1.1.jar,并將其添加到該項目中,如圖6-7所示。

▲圖6-7 添加需要的JAR包
(4)開始啟動sensorsimulator.jar,并對手機模擬器上的SensorSimulator進行必要的配置。首先在“C:\sensorsimulator-1.1.1\bin”目錄下找到sensorsimulator.jar并啟動,運行后的界面如圖6-8所示。

▲圖6-8 傳感器的模擬器
(5)接下來開始進行手機模擬器和SensorSimulator的連接配置工作,運行手機模擬器上安裝好的SensorSimulatorSettings.apk,如圖6-9所示。

▲圖6-9 運行手機模擬器上的SensorSimulatorSettings-1.1.1.apk
(6)在圖6-9中輸入SensorSimulator啟動時顯示的IP地址和端口號,單擊屏幕右上角的“Testing”按鈕后轉到測試連接界面。如圖6-10所示。

▲圖6-10 測試連接界面
(7)單擊屏幕上的“Connect”按鈕進入下一界面,如圖6-11所示。在此界面中可以選擇需要監聽的傳感器,如果能夠從傳感器中讀取到數據,說明SensorSimulator與手機模擬器連接成功,就可以測試自己開發的應用程序了。

▲圖6-11 連接界面
到此為止,使用Eclipse結合SensorSimulator配置傳感器應用程序的基本流程介紹完畢。
6.3 查看傳感器的相關信息
在接下來的實例中,將演示在Android智能設備中查看傳感器數據的方法。

本實例的功能是查看設備中傳感器的基本信息,本實例源碼來源于:
https://github.com/gast-lib/gast-lib
讀者可以自行登錄下載。本實例的具體實現流程如下所示。
(1)編寫用戶交互界面SensorListActivity,實現了兩個用戶界面交互。其中主界面sensor_main.xml用于列表顯示系統中的傳感器,功能和前面的實例6-1類似。文件sensor_main.xml的主要實現代碼如下所示。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <fragment android:id="@+id/frag_sensor_select" android:layout_width="fill_parent" android:layout_height="fill_parent" class="root.gast.playground.sensor.SensorSelectorFragment" /> <fragment android:id="@+id/frag_sensor_view" android:layout_width="fill_parent" android:layout_height="fill_parent" class="root.gast.playground.sensor.SensorDisplayFragment" /> </LinearLayout>
文件SensorListActivity.java的具體實現代碼如下所示。
public class SensorListActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sensor_main); // wire up the fragments so selector // can call display SensorDisplayFragment sensorDisplay = (SensorDisplayFragment) getSupportFragmentManager() .findFragmentById(R.id.frag_sensor_view); SensorSelectorFragment sensorSelect = (SensorSelectorFragment) getSupportFragmentManager() .findFragmentById(R.id.frag_sensor_select); sensorSelect.setSensorDisplay(sensorDisplay); } }
通過上述代碼可知,傳感器類型列表顯示功能是通過調用文件SensorSelectorFragment.java實現的,具體實現代碼如下所示。
public class SensorSelectorFragment extends ListFragment { private static final String TAG = "SensorSelectorFragment"; private SensorDisplayFragment sensorDisplay; /** * connect with a display fragment to call later when user clicks a sensor * name, also setup the ListAdapter to show all the Sensors */ public void setSensorDisplay(SensorDisplayFragment sensorDisplay) { this.sensorDisplay = sensorDisplay; SensorManager sensorManager = (SensorManager) getActivity().getSystemService( Activity.SENSOR_SERVICE); List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL); this.setListAdapter(new SensorListAdapter(getActivity() .getApplicationContext(), android.R.layout.simple_list_item_1, sensors)); } /** * hide the list of sensors and show the sensor display fragment * add these changes to the backstack */ private void showSensorFragment(Sensor sensor) { sensorDisplay.displaySensor(sensor); FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); ft.hide(this); ft.show(sensorDisplay); ft.addToBackStack("Showing sensor: " + sensor.getName()); ft.commit(); } /** * list view adapter to show sensor names and respond to clicks. */ private class SensorListAdapter extends ArrayAdapter<Sensor> { public SensorListAdapter(Context context, int textViewResourceId, List<Sensor> sensors) { super(context, textViewResourceId, sensors); } /** * create a text view containing the sensor name */ @Override public View getView(final int position, View convertView, ViewGroup parent) { final Sensor selectedSensor = getItem(position); if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate( android.R.layout.simple_list_item_1, null); } ((TextView) convertView).setText(selectedSensor.getName()); convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (BuildConfig.DEBUG) { Log.d(TAG, "display sensor! " + selectedSensor.getName()); } showSensorFragment(selectedSensor); } }); return convertView; } } }
(2)再看第2個界面,當用戶在主界面選擇列表中的某一個傳感器時,會顯示這個傳感器的詳細信息。界面文件sensors_north_main.xml的主要實現代碼如下所示。
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <RadioGroup android:id="@+id/sensorRateSelector" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" > <RadioButton android:id="@+id/delayFastest" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_FASTEST" android:checked="false"/> <RadioButton android:id="@+id/delayGame" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_GAME" android:checked="false"/> <RadioButton android:id="@+id/delayNormal" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_NORMAL" android:checked="true"/> <RadioButton android:id="@+id/delayUi" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_UI" android:checked="false"/> </RadioGroup> <View android:id="@+id/seperator" style="@style/line_separator" android:layout_below="@id/sensorRateSelector" /> <TextView android:id="@+id/nameLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/seperator" android:layout_alignParentLeft="true" android:text="Name:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/nameLabel" android:layout_alignTop="@id/nameLabel" android:layout_alignBottom="@id/nameLabel" /> <TextView android:id="@+id/typeLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/nameLabel" android:layout_below="@id/nameLabel" android:text="Type:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/typeLabel" android:layout_alignTop="@id/typeLabel" android:layout_alignBottom="@id/typeLabel"/> <TextView android:id="@+id/maxRangeLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/nameLabel" android:layout_below="@id/typeLabel" android:text="Max Range:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/maxRange" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/maxRangeLabel" android:layout_alignTop="@id/maxRangeLabel" android:layout_alignBottom="@id/maxRangeLabel"/> <TextView android:id="@+id/minDelayLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/maxRangeLabel" android:layout_below="@id/maxRangeLabel" android:text="Min Delay:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/minDelay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/minDelayLabel" android:layout_alignTop="@id/minDelayLabel" android:layout_alignBottom="@id/minDelayLabel"/> <TextView android:id="@+id/powerLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/minDelayLabel" android:layout_below="@id/minDelayLabel" android:text="Power:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/power" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/powerLabel" android:layout_alignTop="@id/powerLabel" android:layout_alignBottom="@id/powerLabel" android:layout_marginRight="5dip"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/power" android:layout_alignTop="@id/power" android:layout_alignBottom="@id/power" android:text="mA"/> <TextView android:id="@+id/resolutionLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/powerLabel" android:layout_below="@id/powerLabel" android:text="Resolution:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/resolution" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/resolutionLabel" android:layout_alignTop="@id/resolutionLabel" android:layout_alignBottom="@id/resolutionLabel"/> <TextView android:id="@+id/vendorLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/resolutionLabel" android:layout_below="@id/resolutionLabel" android:text="Vendor:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/vendor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/vendorLabel" android:layout_alignTop="@id/vendorLabel" android:layout_alignBottom="@id/vendorLabel"/> <TextView android:id="@+id/versionLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/versionLabel" android:layout_alignLeft="@id/vendorLabel" android:layout_below="@id/vendorLabel" android:text="Version:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/version" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/versionLabel" android:layout_alignTop="@id/versionLabel" android:layout_alignBottom="@id/versionLabel"/> <TextView android:id="@+id/accuracyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/versionLabel" android:layout_below="@id/versionLabel" android:text="Accuracy:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/accuracy" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/accuracyLabel" android:layout_alignTop="@id/accuracyLabel" android:layout_alignBottom="@id/accuracyLabel"/> <! -- timestamp --> <TextView android:id="@+id/timestampLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/accuracyLabel" android:layout_below="@id/accuracyLabel" android:layout_marginRight="5dip" android:text="Timestamp:" /> <TextView android:id="@+id/timestamp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/timestampLabel" android:layout_alignTop="@id/timestampLabel" android:layout_alignBottom="@id/timestampLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <TextView android:id="@+id/timestampUnits" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/timestamp" android:layout_alignTop="@id/timestamp" android:layout_alignBottom="@id/timestamp" android:visibility="gone" android:text="(ns)" /> <TextView android:id="@+id/dataLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/accuracyLabel" android:layout_below="@id/timestampLabel" android:layout_marginRight="5dip" android:visibility="gone"/> <TextView android:id="@+id/dataUnits" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/dataLabel" android:layout_alignTop="@id/dataLabel" android:layout_alignBottom="@id/dataLabel" android:visibility="gone" /> <TextView android:id="@+id/singleValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/dataUnits" android:layout_alignTop="@id/dataUnits" android:layout_alignBottom="@id/dataUnits" android:visibility="gone" /> <! -- X axis --> <TextView android:id="@+id/xAxisLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/dataLabel" android:layout_below="@id/dataLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="@string/xAxisLabel" /> <TextView android:id="@+id/xAxis" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/xAxisLabel" android:layout_alignTop="@id/xAxisLabel" android:layout_alignBottom="@id/xAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <! -- Y axis --> <TextView android:id="@+id/yAxisLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/xAxisLabel" android:layout_below="@id/xAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="@string/yAxisLabel" /> <TextView android:id="@+id/yAxis" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/yAxisLabel" android:layout_alignTop="@id/yAxisLabel" android:layout_alignBottom="@id/yAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <! -- Z axis --> <TextView android:id="@+id/zAxisLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/yAxisLabel" android:layout_below="@id/yAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="@string/zAxisLabel" /> <TextView android:id="@+id/zAxis" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/zAxisLabel" android:layout_alignTop="@id/zAxisLabel" android:layout_alignBottom="@id/zAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <! -- cos value (for rotation vector only) --> <TextView android:id="@+id/cosLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/zAxisLabel" android:layout_below="@id/zAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="cos(\u0398/2):" /> <TextView android:id="@+id/cos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/cosLabel" android:layout_alignTop="@id/cosLabel" android:layout_alignBottom="@id/cosLabel" android:layout_marginRight="5dip" android:visibility="gone" /> </RelativeLayout>
某個傳感器的詳細信息功能是通過文件SensorDisplayFragment.java實現的,主要代碼如下所示。
public class SensorDisplayFragment extends Fragment implements SensorEventListener { private static final String TAG = "SensorDisplayFragment"; private static final String THETA = "\u0398"; private static final String ACCELERATION_UNITS = "m/s\u00B2"; private SensorManager sensorManager; private Sensor sensor; private TextView name; private TextView type; private TextView maxRange; private TextView minDelay; private TextView power; private TextView resolution; private TextView vendor; private TextView version; private TextView accuracy; private TextView timestampLabel; private TextView timestamp; private TextView timestampUnits; private TextView dataLabel; private TextView dataUnits; private TextView xAxis; private TextView xAxisLabel; private TextView yAxis; private TextView yAxisLabel; private TextView zAxis; private TextView zAxisLabel; private TextView singleValue; private TextView cosLabel; private TextView cos; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.sensor_view, null); sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE); name = (TextView) layout.findViewById(R.id.name); type = (TextView) layout.findViewById(R.id.type); maxRange = (TextView) layout.findViewById(R.id.maxRange); minDelay = (TextView) layout.findViewById(R.id.minDelay); power = (TextView) layout.findViewById(R.id.power); resolution = (TextView) layout.findViewById(R.id.resolution); vendor = (TextView) layout.findViewById(R.id.vendor); version = (TextView) layout.findViewById(R.id.version); accuracy = (TextView) layout.findViewById(R.id.accuracy); timestampLabel = (TextView) layout.findViewById(R.id.timestampLabel); timestamp = (TextView) layout.findViewById(R.id.timestamp); timestampUnits = (TextView) layout.findViewById(R.id.timestampUnits); dataLabel = (TextView) layout.findViewById(R.id.dataLabel); dataUnits = (TextView) layout.findViewById(R.id.dataUnits); xAxis = (TextView) layout.findViewById(R.id.xAxis); xAxisLabel = (TextView) layout.findViewById(R.id.xAxisLabel); yAxis = (TextView) layout.findViewById(R.id.yAxis); yAxisLabel = (TextView) layout.findViewById(R.id.yAxisLabel); zAxis = (TextView) layout.findViewById(R.id.zAxis); zAxisLabel = (TextView) layout.findViewById(R.id.zAxisLabel); singleValue = (TextView) layout.findViewById(R.id.singleValue); cosLabel = (TextView) layout.findViewById(R.id.cosLabel); cos = (TextView) layout.findViewById(R.id.cos); layout.findViewById(R.id.delayFastest).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_FASTEST); } }); layout.findViewById(R.id.delayGame).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_GAME); } }); layout.findViewById(R.id.delayNormal).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_NORMAL); } }); layout.findViewById(R.id.delayUi).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_UI); } }); return layout; } public void displaySensor(Sensor sensor) { if (BuildConfig.DEBUG) { Log.d(TAG, "display the sensor"); } this.sensor = sensor; name.setText(sensor.getName()); type.setText(String.valueOf(sensor.getType())); maxRange.setText(String.valueOf(sensor.getMaximumRange())); minDelay.setText(String.valueOf(sensor.getMinDelay())); power.setText(String.valueOf(sensor.getPower())); resolution.setText(String.valueOf(sensor.getResolution())); vendor.setText(String.valueOf(sensor.getVendor())); version.setText(String.valueOf(sensor.getVersion())); sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL); } /** * @see android.hardware.SensorEventListener#onAccuracyChanged(android.hardware. Sensor, int) */ @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { switch(accuracy) { case SensorManager.SENSOR_STATUS_ACCURACY_HIGH: this.accuracy.setText("SENSOR_STATUS_ACCURACY_HIGH"); break; case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM: this.accuracy.setText("SENSOR_STATUS_ACCURACY_MEDIUM"); break; case SensorManager.SENSOR_STATUS_ACCURACY_LOW: this.accuracy.setText("SENSOR_STATUS_ACCURACY_LOW"); break; case SensorManager.SENSOR_STATUS_UNRELIABLE: this.accuracy.setText("SENSOR_STATUS_UNRELIABLE"); break; } } /** * @see android.hardware.SensorEventListener#onSensorChanged(android.hardware. SensorEvent) */ @Override public void onSensorChanged(SensorEvent event) { onAccuracyChanged(event.sensor, event.accuracy); timestampLabel.setVisibility(View.VISIBLE); timestamp.setVisibility(View.VISIBLE); timestamp.setText(String.valueOf(event.timestamp)); timestampUnits.setVisibility(View.VISIBLE); switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: showEventData("Acceleration - gravity on axis", ACCELERATION_UNITS, event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_MAGNETIC_FIELD: showEventData("Abient Magnetic Field", "uT", event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_GYROSCOPE: showEventData("Angular speed around axis", "radians/sec", event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_LIGHT: showEventData("Ambient light", "lux", event.values[0]); break; case Sensor.TYPE_PRESSURE: showEventData("Atmospheric pressure", "hPa", event.values[0]); break; case Sensor.TYPE_PROXIMITY: showEventData("Distance", "cm", event.values[0]); break; case Sensor.TYPE_GRAVITY: showEventData("Gravity", ACCELERATION_UNITS, event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_LINEAR_ACCELERATION: showEventData("Acceleration (not including gravity)", ACCELERATION_UNITS, event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_ROTATION_VECTOR: showEventData("Rotation Vector", null, event.values[0], event.values[1], event.values[2]); xAxisLabel.setText("x*sin(" + THETA + "/2)"); yAxisLabel.setText("y*sin(" + THETA + "/2)"); zAxisLabel.setText("z*sin(" + THETA + "/2)"); if (event.values.length == 4) { cosLabel.setVisibility(View.VISIBLE); cos.setVisibility(View.VISIBLE); cos.setText(String.valueOf(event.values[3])); } break; case Sensor.TYPE_ORIENTATION: showEventData("Angle", "Degrees", event.values[0], event.values[1], event.values[2]); xAxisLabel.setText(R.string.azimuthLabel); yAxisLabel.setText(R.string.pitchLabel); zAxisLabel.setText(R.string.rollLabel); break; case Sensor.TYPE_RELATIVE_HUMIDITY: showEventData("Relatice ambient air humidity", "%", event.values[0]); break; case Sensor.TYPE_AMBIENT_TEMPERATURE: showEventData("Ambien temperature", "degree Celcius", event.values[0]); break; } } private void showEventData(String label, String units, float x, float y, float z) { dataLabel.setVisibility(View.VISIBLE); dataLabel.setText(label); if (units == null) { dataUnits.setVisibility(View.GONE); } else { dataUnits.setVisibility(View.VISIBLE); dataUnits.setText("(" + units + "):"); } singleValue.setVisibility(View.GONE); xAxisLabel.setVisibility(View.VISIBLE); xAxisLabel.setText(R.string.xAxisLabel); xAxis.setVisibility(View.VISIBLE); xAxis.setText(String.valueOf(x)); yAxisLabel.setVisibility(View.VISIBLE); yAxisLabel.setText(R.string.yAxisLabel); yAxis.setVisibility(View.VISIBLE); yAxis.setText(String.valueOf(y)); zAxisLabel.setVisibility(View.VISIBLE); zAxisLabel.setText(R.string.zAxisLabel); zAxis.setVisibility(View.VISIBLE); zAxis.setText(String.valueOf(z)); } private void showEventData(String label, String units, float value) { dataLabel.setVisibility(View.VISIBLE); dataLabel.setText(label); dataUnits.setVisibility(View.VISIBLE); dataUnits.setText("(" + units + "):"); singleValue.setVisibility(View.VISIBLE); singleValue.setText(String.valueOf(value)); xAxisLabel.setVisibility(View.GONE); xAxis.setVisibility(View.GONE); yAxisLabel.setVisibility(View.GONE); yAxis.setVisibility(View.GONE); zAxisLabel.setVisibility(View.GONE); zAxis.setVisibility(View.GONE); } /** * @see android.support.v4.app.Fragment#onHiddenChanged(boolean) */ @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (hidden) { if (BuildConfig.DEBUG) { Log.d(TAG, "Unregistering listener"); } sensorManager.unregisterListener(this); } } /** * @see android.support.v4.app.Fragment#onPause() */ @Override public void onPause() { super.onPause(); if (BuildConfig.DEBUG) { Log.d(TAG, "onPause"); Log.d(TAG, "Unregistering listener"); } sensorManager.unregisterListener(this); } }
到此為止,整個實例介紹完畢,執行后的效果如圖6-12所示。

▲圖6-12 執行效果
- Learning Single:page Web Application Development
- Python概率統計
- C#高級編程(第10版) C# 6 & .NET Core 1.0 (.NET開發經典名著)
- Spring Cloud Alibaba核心技術與實戰案例
- Java多線程編程實戰指南:設計模式篇(第2版)
- Learning ASP.NET Core 2.0
- Learn Programming in Python with Cody Jackson
- OpenCV with Python By Example
- Programming Microsoft Dynamics? NAV 2015
- 現代C:概念剖析和編程實踐
- Parallel Programming with Python
- 計算機輔助設計與繪圖技術(AutoCAD 2014教程)(第三版)
- ServiceDesk Plus 8.x Essentials
- INSTANT Eclipse Application Testing How-to
- 趣學Python游戲編程