Hầu hết thiết bị chạy Android đều có các cảm biến tích hợp để đo chuyển động, hướng, và nhiều điều kiện môi trường. Những cảm biến này có khả năng cung cấp dữ liệu thô với độ chính xác và độ chính xác, đồng thời hữu ích nếu bạn muốn theo dõi chuyển động ba chiều của thiết bị hoặc định vị hoặc bạn muốn theo dõi các thay đổi trong môi trường xung quanh gần thiết bị. Ví dụ: một trò chơi có thể theo dõi các chỉ số đo từ cảm biến trọng lực của thiết bị để suy ra các cử chỉ phức tạp của người dùng và chuyển động, chẳng hạn như nghiêng, lắc, xoay hoặc lắc. Tương tự, ứng dụng thời tiết có thể sử dụng cảm biến nhiệt độ và cảm biến độ ẩm của thiết bị để tính toán và báo cáo điểm sương hoặc hành trình có thể sử dụng cảm biến trường địa từ và gia tốc kế để báo cáo một la bàn đầu ra.
Hãy tham khảo các tài nguyên liên quan sau:
Nền tảng Android hỗ trợ 3 loại cảm biến chính:
- Cảm biến chuyển động
Các cảm biến này đo lực gia tốc và lực quay dọc theo ba trục. Chiến dịch này danh mục bao gồm gia tốc kế, cảm biến trọng lực, con quay hồi chuyển và vectơ quay các cảm biến.
- Cảm biến môi trường
Các cảm biến này đo lường nhiều thông số môi trường, chẳng hạn như nhiệt độ không khí xung quanh và áp suất, độ chiếu sáng và độ ẩm. Danh mục này bao gồm khí áp kế, quang kế và nhiệt kế.
- Cảm biến vị trí
Các cảm biến này đo vị trí thực của một thiết bị. Danh mục này bao gồm cảm biến hướng và từ kế.
Bạn có thể truy cập các cảm biến có sẵn trên thiết bị và thu thập dữ liệu cảm biến thô bằng cách sử dụng khung cảm biến. Khung cảm biến cung cấp một số lớp và giao diện giúp bạn thực hiện nhiều nhiệm vụ liên quan đến cảm biến. Ví dụ: bạn có thể sử dụng khung cảm biến để làm những việc sau:
- Xác định loại cảm biến có sẵn trên thiết bị.
- Xác định khả năng của một cảm biến riêng lẻ, chẳng hạn như phạm vi tối đa, nhà sản xuất, công suất các yêu cầu và cách giải quyết.
- Thu thập dữ liệu cảm biến thô và xác định tốc độ tối thiểu mà bạn thu được dữ liệu cảm biến.
- Đăng ký và huỷ đăng ký trình nghe sự kiện cảm biến để giám sát các thay đổi của cảm biến.
Chủ đề này cung cấp thông tin tổng quan về các cảm biến có trên nền tảng Android. Tài liệu này cũng giới thiệu về khung cảm biến.
Giới thiệu về Cảm biến
Khung cảm biến Android cho phép bạn sử dụng nhiều loại cảm biến. Một vài cảm biến trong số này là dựa trên phần cứng và một số dựa trên phần mềm. Cảm biến dựa trên phần cứng là các thành phần vật lý được tạo nên vào điện thoại di động hoặc thiết bị máy tính bảng. Các dịch vụ này lấy dữ liệu bằng cách trực tiếp đo lường tính chất, chẳng hạn như gia tốc, cường độ trường địa từ hoặc sự thay đổi góc. Dựa trên phần mềm cảm biến không phải là thiết bị vật lý, mặc dù chúng bắt chước cảm biến dựa trên phần cứng. Cảm biến dựa trên phần mềm lấy dữ liệu từ một hoặc nhiều cảm biến dựa trên phần cứng và đôi khi được gọi là cảm biến ảo hoặc cảm biến tổng hợp. Cảm biến gia tốc tuyến tính và cảm biến trọng lực là các ví dụ về các cảm biến dựa trên phần mềm. Bảng 1 tóm tắt các cảm biến được Android hỗ trợ chủ.
Rất ít thiết bị chạy Android có đủ các loại cảm biến. Ví dụ: hầu hết điện thoại di động và máy tính bảng có gia tốc kế và từ kế, nhưng ít thiết bị hơn khí áp kế hoặc nhiệt kế. Ngoài ra, một thiết bị có thể có nhiều cảm biến thuộc cùng một loại. Cho ví dụ: một thiết bị có thể có hai cảm biến trọng lực, mỗi cảm biến có phạm vi khác nhau.
Bảng 1. Các loại cảm biến được nền tảng Android hỗ trợ.
Cảm biến | Loại | Mô tả | Cách dùng phổ biến |
---|---|---|---|
TYPE_ACCELEROMETER |
Phần cứng | Đo lực gia tốc tính bằng m/s2 tác dụng lên một thiết bị trên cả ba trục vật lý (x, y và z), bao gồm cả lực hấp dẫn. | Phát hiện chuyển động (lắc, nghiêng, v.v.). |
TYPE_AMBIENT_TEMPERATURE |
Phần cứng | Đo nhiệt độ phòng xung quanh bằng độ C (°C). Xem ghi chú bên dưới. | Đang theo dõi nhiệt độ không khí. |
TYPE_GRAVITY |
Phần mềm hoặc phần cứng | Đo lực hấp dẫn tính bằng m/s2 tác dụng lên một thiết bị trên tất cả ba trục vật lý (x, y, z). | Phát hiện chuyển động (lắc, nghiêng, v.v.). |
TYPE_GYROSCOPE |
Phần cứng | Đo tốc độ quay của thiết bị tính bằng Rad/s xung quanh mỗi thiết bị trục vật lý (x, y và z). | Phát hiện hướng xoay (quay, rẽ, v.v.). |
TYPE_LIGHT |
Phần cứng | Đo mức ánh sáng xung quanh (độ chiếu sáng) theo đơn vị lx. | Kiểm soát độ sáng màn hình. |
TYPE_LINEAR_ACCELERATION |
Phần mềm hoặc phần cứng | Đo lực gia tốc tính bằng m/s2 là đã áp dụng cho một thiết bị trên cả ba trục vật lý (x, y và z), không bao gồm lực hấp dẫn. | Giám sát gia tốc dọc theo một trục. |
TYPE_MAGNETIC_FIELD |
Phần cứng | Đo trường địa từ xung quanh cho cả ba trục vật lý (x, y, z) trong μT. | Tạo la bàn. |
TYPE_ORIENTATION |
Phần mềm | Đo độ quay của thiết bị quanh cả ba trục vật lý (x, y, z).
Kể từ API cấp 3, bạn có thể lấy ma trận độ nghiêng và ma trận xoay cho
một thiết bị bằng cách sử dụng cảm biến trọng lực và cảm biến trường địa từ cùng với
getRotationMatrix()
. |
Đang xác định vị trí thiết bị. |
TYPE_PRESSURE |
Phần cứng | Đo áp suất không khí xung quanh bằng hPa hoặc mbar. | Theo dõi sự thay đổi áp suất không khí. |
TYPE_PROXIMITY |
Phần cứng | Đo độ gần của một vật tính bằng cm so với màn hình xem của thiết bị. Cảm biến này thường được dùng để xác định xem điện thoại di động có đang được cầm đến tai của một người. | Vị trí của điện thoại trong cuộc gọi. |
TYPE_RELATIVE_HUMIDITY |
Phần cứng | Đo độ ẩm tương đối của môi trường xung quanh bằng phần trăm (%). | Theo dõi điểm sương, độ ẩm tuyệt đối và tương đối. |
TYPE_ROTATION_VECTOR |
Phần mềm hoặc phần cứng | Đo hướng của một thiết bị bằng cách cung cấp ba phần tử của màn hình thiết bị vectơ xoay. | Phát hiện chuyển động và phát hiện chế độ xoay. |
TYPE_TEMPERATURE |
Phần cứng | Đo nhiệt độ của thiết bị bằng độ C (°C). Cảm biến này
cách triển khai khác nhau giữa các thiết bị và
cảm biến này đã được thay thế bằng cảm biến TYPE_AMBIENT_TEMPERATURE ở
API cấp 14 |
Bạn đang theo dõi nhiệt độ. |
Khung cảm biến
Bạn có thể truy cập các cảm biến này và thu thập dữ liệu cảm biến thô bằng cách sử dụng khung cảm biến Android.
Khung cảm biến là một phần của gói android.hardware
và bao gồm những phần sau
lớp và giao diện:
SensorManager
- Bạn có thể dùng lớp này để tạo một thực thể của dịch vụ cảm biến. Lớp này cung cấp nhiều phương thức để truy cập và liệt kê cảm biến, đăng ký và huỷ đăng ký sự kiện cảm biến người nghe cũng như thu thập thông tin về hướng. Lớp này cũng cung cấp một số hằng số cảm biến dùng để báo cáo độ chính xác của cảm biến, thiết lập tốc độ thu thập dữ liệu và hiệu chỉnh cảm biến.
Sensor
- Bạn có thể dùng lớp này để tạo một thực thể của một cảm biến cụ thể. Lớp này cung cấp nhiều các phương thức giúp bạn xác định khả năng của cảm biến.
SensorEvent
- Hệ thống sử dụng lớp này để tạo một đối tượng sự kiện cảm biến, đối tượng này cung cấp thông tin về một sự kiện của cảm biến. Đối tượng sự kiện cảm biến bao gồm các thông tin sau: dữ liệu cảm biến thô, loại cảm biến đã tạo ra sự kiện, độ chính xác của dữ liệu và dấu thời gian cho sự kiện.
SensorEventListener
- Bạn có thể sử dụng giao diện này để tạo hai phương thức gọi lại để nhận thông báo (cảm biến sự kiện) khi giá trị cảm biến thay đổi hoặc khi độ chính xác của cảm biến thay đổi.
Trong một ứng dụng thông thường, bạn sẽ dùng các API liên quan đến cảm biến này để thực hiện 2 tác vụ cơ bản:
- Xác định các cảm biến và chức năng của cảm biến
Việc xác định các cảm biến và chức năng của cảm biến trong thời gian chạy sẽ rất hữu ích nếu ứng dụng của bạn dựa trên một số loại cảm biến hoặc chức năng cụ thể. Ví dụ: bạn nên xác định tất cả các cảm biến có trên một thiết bị và tắt mọi tính năng của ứng dụng dựa vào các cảm biến không có. Tương tự, bạn có thể muốn xác định tất cả các cảm biến của một loại nhất định, để bạn có thể chọn cách triển khai cảm biến có hiệu suất tối ưu cho ứng dụng của bạn.
- Theo dõi các sự kiện cảm biến
Theo dõi sự kiện cảm biến là cách bạn thu thập dữ liệu cảm biến thô. Một sự kiện cảm biến xảy ra mỗi lần một cảm biến phát hiện sự thay đổi trong các tham số mà cảm biến đang đo. Một sự kiện cảm biến sẽ cung cấp cho bạn với bốn thông tin: tên của cảm biến đã kích hoạt sự kiện, dấu thời gian cho sự kiện, độ chính xác của sự kiện và dữ liệu cảm biến thô đã kích hoạt sự kiện.
Khả năng sử dụng cảm biến
Mặc dù khả năng sử dụng của cảm biến thay đổi tuỳ theo thiết bị, nhưng cũng có thể khác nhau giữa các thiết bị Android của Google. Điều này là do các cảm biến Android đã được ra mắt trong quá trình các bản phát hành nền tảng. Ví dụ: nhiều cảm biến đã được giới thiệu trong Android 1.5 (API cấp 3), nhưng một số chưa được triển khai và không được sử dụng cho đến Android 2.3 (API cấp 9). Tương tự, một số cảm biến đã được giới thiệu trong Android 2.3 (API cấp 9) và Android 4.0 (API cấp 14). Hai cảm biến đã ngừng hoạt động và được thay thế bằng những cảm biến mới hơn, tốt hơn.
Bảng 2 tóm tắt khả năng sử dụng của từng cảm biến trên cơ sở từng nền tảng. Chỉ bốn được liệt kê vì đó là các nền tảng liên quan đến việc thay đổi cảm biến. Các cảm biến được liệt kê là không dùng nữa vẫn có sẵn trên các nền tảng tiếp theo (miễn là cảm biến có trên thiết bị). Điều này tuân thủ chính sách về khả năng tương thích chuyển tiếp của Android.
Bảng 2. Khả năng sử dụng cảm biến theo nền tảng.
Cảm biến | Android 4.0 (API cấp 14) |
Android 2.3 (API cấp 9) |
Android 2.2 (API cấp 8) |
Android 1.5 (API cấp 3) |
---|---|---|---|---|
TYPE_ACCELEROMETER |
Có | Có | Có | Có |
TYPE_AMBIENT_TEMPERATURE |
Có | không áp dụng | không áp dụng | không áp dụng |
TYPE_GRAVITY |
Có | Có | không áp dụng | không áp dụng |
TYPE_GYROSCOPE |
Có | Có | không áp dụng1 | không áp dụng1 |
TYPE_LIGHT |
Có | Có | Có | Có |
TYPE_LINEAR_ACCELERATION |
Có | Có | không áp dụng | không áp dụng |
TYPE_MAGNETIC_FIELD |
Có | Có | Có | Có |
TYPE_ORIENTATION |
Có2 | Có2 | Có2 | Có |
TYPE_PRESSURE |
Có | Có | không áp dụng1 | không áp dụng1 |
TYPE_PROXIMITY |
Có | Có | Có | Có |
TYPE_RELATIVE_HUMIDITY |
Có | không áp dụng | không áp dụng | không áp dụng |
TYPE_ROTATION_VECTOR |
Có | Có | không áp dụng | không áp dụng |
TYPE_TEMPERATURE |
Có2 | Có | Có | Có |
1 Loại cảm biến này đã được thêm vào Android 1.5 (Cấp độ API) 3), nhưng nó không được sử dụng cho đến Android 2.3 (API cấp 9).
2 Cảm biến này sẵn sàng, nhưng đã được không dùng nữa.
Xác định cảm biến và chức năng của cảm biến
Khung cảm biến Android cung cấp một số phương pháp giúp bạn dễ dàng xác định tại thời gian chạy của cảm biến trên thiết bị. API này cũng cung cấp các phương thức cho phép bạn xác định khả năng của mỗi cảm biến, chẳng hạn như phạm vi tối đa, độ phân giải và công suất của cảm biến các yêu cầu liên quan.
Để xác định các cảm biến trên một thiết bị, trước tiên, bạn cần tham chiếu đến cảm biến
. Để thực hiện việc này, bạn hãy tạo một thực thể của lớp SensorManager
bằng cách
gọi phương thức getSystemService()
và truyền
trong đối số SENSOR_SERVICE
. Ví dụ:
Kotlin
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
Java
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Tiếp theo, bạn có thể tải danh sách mọi cảm biến trên thiết bị bằng cách gọi hàm
Phương thức getSensorList()
và sử dụng hằng số TYPE_ALL
. Ví dụ:
Kotlin
val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
Java
List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
Nếu muốn liệt kê tất cả các cảm biến thuộc một loại nhất định, bạn có thể sử dụng một hằng số khác thay vì
TYPE_ALL
chẳng hạn như TYPE_GYROSCOPE
,
TYPE_LINEAR_ACCELERATION
hoặc
TYPE_GRAVITY
.
Bạn cũng có thể xác định xem một loại cảm biến cụ thể có tồn tại trên thiết bị hay không bằng cách sử dụng phương thức getDefaultSensor()
và truyền vào loại
hằng số cho một cảm biến cụ thể. Nếu thiết bị có nhiều hơn một cảm biến thuộc cùng một loại, một trong
cảm biến phải được chỉ định làm cảm biến mặc định. Nếu cảm biến mặc định không tồn tại cho một cảm biến cụ thể
một loại cảm biến cụ thể, lệnh gọi phương thức sẽ trả về giá trị null, có nghĩa là thiết bị không có loại cảm biến này
cảm biến. Ví dụ: Mã sau đây kiểm tra xem có từ kế trên một thiết bị hay không:
Kotlin
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) { // Success! There's a magnetometer. } else { // Failure! No magnetometer. }
Java
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){ // Success! There's a magnetometer. } else { // Failure! No magnetometer. }
Lưu ý: Android không yêu cầu nhà sản xuất thiết bị phải tạo bất kỳ các loại cảm biến cụ thể vào thiết bị chạy Android của họ, vì vậy, thiết bị có thể có nhiều loại cấu hình cảm biến.
Ngoài việc liệt kê các cảm biến trên một thiết bị, bạn có thể sử dụng các phương thức công khai của
Lớp Sensor
để xác định các khả năng và đặc điểm của từng cá nhân
các cảm biến. Điều này rất hữu ích nếu bạn muốn ứng dụng của mình hoạt động khác đi dựa trên cảm biến hoặc
cảm biến hoạt động được trên thiết bị. Ví dụ: bạn có thể sử dụng getResolution()
và getMaximumRange()
để lấy độ phân giải và phạm vi đo lường tối đa của cảm biến. Bạn cũng có thể sử dụng
Phương thức getPower()
để lấy thông tin về các yêu cầu về nguồn điện của cảm biến.
Hai trong số các phương thức công khai đặc biệt hữu ích nếu bạn muốn tối ưu hoá ứng dụng cho
cảm biến của nhà sản xuất hoặc các phiên bản khác nhau của cảm biến. Ví dụ: nếu ứng dụng của bạn
cần theo dõi cử chỉ của người dùng, chẳng hạn như nghiêng và lắc, bạn có thể tạo một tập hợp lọc
các quy tắc và tối ưu hoá cho các thiết bị mới hơn có cảm biến trọng lực của một nhà cung cấp cụ thể và một quy tắc khác
bộ quy tắc và biện pháp tối ưu hoá lọc dữ liệu cho các thiết bị không có cảm biến trọng lực và có
chỉ có gia tốc kế. Mã mẫu sau đây cho bạn biết cách dùng các phương thức getVendor()
và getVersion()
để thực hiện
này. Trong mẫu này, chúng ta đang tìm kiếm một cảm biến trọng lực liệt kê Google LLC là nhà cung cấp và
có số phiên bản là 3. Nếu cảm biến cụ thể đó không có trên thiết bị, chúng tôi sẽ cố gắng sử dụng
gia tốc kế.
Kotlin
private lateinit var sensorManager: SensorManager private var mSensor: Sensor? = null ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) { val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY) // Use the version 3 gravity sensor. mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 } } if (mSensor == null) { // Use the accelerometer. mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) { sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) } else { // Sorry, there are no accelerometers on your device. // You can't play this game. null } }
Java
private SensorManager sensorManager; private Sensor mSensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mSensor = null; if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){ List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY); for(int i=0; i<gravSensors.size(); i++) { if ((gravSensors.get(i).getVendor().contains("Google LLC")) && (gravSensors.get(i).getVersion() == 3)){ // Use the version 3 gravity sensor. mSensor = gravSensors.get(i); } } } if (mSensor == null){ // Use the accelerometer. if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){ mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } else{ // Sorry, there are no accelerometers on your device. // You can't play this game. } }
Một phương thức hữu ích khác là phương thức getMinDelay()
,
Phương thức này trả về khoảng thời gian tối thiểu (tính bằng micrô giây) mà cảm biến có thể sử dụng để cảm nhận dữ liệu. Cảm biến bất kỳ
trả về một giá trị khác 0 cho getMinDelay()
là một phương thức truyền trực tuyến
cảm biến. Cảm biến truyền phát trực tiếp cảm biến dữ liệu theo định kỳ và được ra mắt trong Android 2.3 (API)
Cấp 9). Nếu một cảm biến trả về 0 khi bạn gọi phương thức getMinDelay()
, thì điều đó có nghĩa là
vì cảm biến chỉ báo cáo dữ liệu khi có sự thay đổi trong
các tham số mà nó đang cảm nhận.
Phương thức getMinDelay()
rất hữu ích vì nó cho phép
bạn xác định tỷ lệ tối đa
mà tại đó cảm biến có thể thu thập dữ liệu. Nếu một số tính năng nhất định trong ứng dụng của bạn yêu cầu dữ liệu cao
hoặc cảm biến truyền trực tuyến, bạn có thể
sử dụng phương pháp này để xác định xem cảm biến
đáp ứng các yêu cầu đó, rồi bật hoặc tắt các tính năng có liên quan trong ứng dụng của bạn
cho phù hợp.
Thận trọng: Tốc độ thu thập dữ liệu tối đa của cảm biến không phải nhất thiết phải là tốc độ khung cảm biến phân phối dữ liệu cảm biến đến ứng dụng của bạn. Chiến lược phát hành đĩa đơn khung cảm biến báo cáo dữ liệu thông qua các sự kiện cảm biến và một số yếu tố ảnh hưởng đến tốc độ ứng dụng của bạn nhận được các sự kiện cảm biến. Để biết thêm thông tin, hãy xem bài viết Giám sát sự kiện cảm biến.
Giám sát các sự kiện của cảm biến
Để theo dõi dữ liệu cảm biến thô, bạn cần triển khai hai phương thức gọi lại được hiển thị thông qua
giao diện SensorEventListener
: onAccuracyChanged()
và onSensorChanged()
. Hệ thống Android gọi
các phương thức này bất cứ khi nào những điều sau đây xảy ra:
- Độ chính xác của cảm biến thay đổi.
Trong trường hợp này, hệ thống sẽ gọi phương thức
onAccuracyChanged()
, cung cấp bạn tham chiếu đến đối tượngSensor
đã thay đổi và độ chính xác mới của cảm biến. Độ chính xác được biểu thị bằng một trong 4 hằng số trạng thái:SENSOR_STATUS_ACCURACY_LOW
,SENSOR_STATUS_ACCURACY_MEDIUM
,SENSOR_STATUS_ACCURACY_HIGH
, hoặcSENSOR_STATUS_UNRELIABLE
. - Cảm biến báo cáo một giá trị mới.
Trong trường hợp này, hệ thống sẽ gọi phương thức
onSensorChanged()
, cung cấp cho bạn đối tượngSensorEvent
. Đối tượngSensorEvent
chứa thông tin về dữ liệu cảm biến mới, bao gồm: độ chính xác của dữ liệu, cảm biến tạo ra dữ liệu, dấu thời gian tạo dữ liệu và dữ liệu mà cảm biến ghi lại.
Đoạn mã sau đây cho biết cách sử dụng phương thức onSensorChanged()
để theo dõi dữ liệu từ
cảm biến ánh sáng. Ví dụ này trình bày dữ liệu cảm biến thô trong một TextView
đó là
được xác định trong tệp main.xml là sensor_data
.
Kotlin
class SensorActivity : Activity(), SensorEventListener { private lateinit var sensorManager: SensorManager private var mLight: Sensor? = null public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) } override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) { // Do something here if sensor accuracy changes. } override fun onSensorChanged(event: SensorEvent) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. val lux = event.values[0] // Do something with this sensor value. } override fun onResume() { super.onResume() mLight?.also { light -> sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL) } } override fun onPause() { super.onPause() sensorManager.unregisterListener(this) } }
Java
public class SensorActivity extends Activity implements SensorEventListener { private SensorManager sensorManager; private Sensor mLight; @Override public final void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mLight = sensorManager.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(); sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } }
Trong ví dụ này, độ trễ dữ liệu mặc định (SENSOR_DELAY_NORMAL
) được chỉ định khi phương thức registerListener()
được gọi. Dữ liệu
độ trễ (hoặc tốc độ lấy mẫu) kiểm soát khoảng thời gian mà sự kiện cảm biến được gửi đến ứng dụng của bạn
thông qua phương thức gọi lại onSensorChanged()
. Mặc định
độ trễ dữ liệu là phù hợp để giám sát
thông thường sẽ thay đổi hướng màn hình và sử dụng độ trễ 200.000 micrô giây. Bạn có thể chỉ định
độ trễ dữ liệu, chẳng hạn như SENSOR_DELAY_GAME
(20.000 micrô giây
), SENSOR_DELAY_UI
(độ trễ 60.000 micrô giây) hoặc SENSOR_DELAY_FASTEST
(độ trễ 0 micrô giây). Kể từ Android 3.0 (API
Cấp 11), bạn cũng có thể chỉ định độ trễ dưới dạng một giá trị tuyệt đối (tính bằng micrô giây).
Độ trễ mà bạn chỉ định chỉ là độ trễ đề xuất. Hệ thống Android và các ứng dụng khác có thể thay đổi độ trễ này. Tốt nhất là bạn nên chỉ định độ trễ lớn nhất có thể vì hệ thống thường sử dụng độ trễ nhỏ hơn độ trễ mà bạn chỉ định (tức là bạn nên chọn tốc độ lấy mẫu chậm nhất mà vẫn đáp ứng được nhu cầu của ứng dụng). Sử dụng độ trễ lớn hơn tải thấp hơn cho bộ xử lý và do đó sử dụng ít năng lượng hơn.
Không có phương pháp công khai nào để xác định tốc độ mà khung cảm biến đang gửi các sự kiện cảm biến đến ứng dụng của bạn; Tuy nhiên, bạn có thể sử dụng dấu thời gian liên kết với sự kiện của cảm biến để tính tốc độ lấy mẫu qua một số sự kiện. Bạn không cần phải thay đổi tốc độ lấy mẫu (độ trễ) sau khi bạn đặt. Nếu vì lý do nào đó bạn cần thay đổi độ trễ, bạn sẽ phải huỷ đăng ký và đăng ký lại trình nghe cảm biến.
Một điều quan trọng cần lưu ý là ví dụ này sử dụng onResume()
và
Phương thức gọi lại onPause()
để đăng ký và huỷ đăng ký sự kiện cảm biến
trình nghe. Tốt nhất là bạn nên luôn tắt những cảm biến không cần thiết, đặc biệt là khi
bị tạm dừng. Nếu không, pin có thể bị tiêu hao chỉ sau vài giờ do một số cảm biến
có yêu cầu pin đáng kể và có thể nhanh tiêu hao pin. Hệ thống
sẽ không tự động tắt cảm biến khi màn hình tắt.
Xử lý nhiều cấu hình cảm biến
Android không chỉ định cấu hình cảm biến tiêu chuẩn cho thiết bị, tức là nhà sản xuất thiết bị có thể kết hợp bất kỳ cấu hình cảm biến nào họ muốn vào Thiết bị hỗ trợ Android. Do đó, thiết bị có thể có nhiều loại cảm biến thuộc nhiều cấu hình. Nếu ứng dụng của bạn dựa vào một loại cảm biến cụ thể, bạn phải đảm bảo rằng cảm biến sẽ xuất hiện trên một thiết bị để ứng dụng của bạn có thể chạy thành công.
Bạn có 2 lựa chọn để đảm bảo rằng một cảm biến nhất định có trên thiết bị:
- Phát hiện cảm biến trong thời gian chạy và bật hoặc tắt các tính năng của ứng dụng khi thích hợp.
- Sử dụng bộ lọc của Google Play để nhắm đến các thiết bị có cấu hình cảm biến cụ thể.
Mỗi lựa chọn sẽ được thảo luận trong những phần sau.
Phát hiện cảm biến trong thời gian chạy
Nếu ứng dụng của bạn sử dụng một loại cảm biến cụ thể, nhưng không dựa vào loại cảm biến đó, thì bạn có thể sử dụng khung cảm biến để phát hiện cảm biến trong thời gian chạy, sau đó tắt hoặc bật các tính năng của ứng dụng khi phù hợp. Ví dụ: ứng dụng chỉ đường có thể sử dụng cảm biến nhiệt độ, cảm biến áp suất, cảm biến GPS và cảm biến trường địa từ để hiển thị nhiệt độ, khí áp học áp lực, vị trí và góc phương vị la bàn. Nếu thiết bị không có cảm biến áp suất, bạn có thể sử dụng khung cảm biến để phát hiện khi không có cảm biến áp suất trong thời gian chạy, sau đó tắt phần giao diện người dùng của ứng dụng hiển thị áp lực. Ví dụ: các bước kiểm tra mã sau đây có cảm biến áp suất trên thiết bị hay không:
Kotlin
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) { // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. }
Java
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){ // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. }
Sử dụng bộ lọc của Google Play để nhắm đến các cấu hình cảm biến cụ thể
Nếu đang xuất bản ứng dụng của mình trên Google Play, bạn có thể sử dụng
Phần tử <uses-feature>
trong tệp kê khai của bạn để lọc ứng dụng khỏi các thiết bị không
có cấu hình cảm biến phù hợp cho ứng dụng của bạn. Chiến lược phát hành đĩa đơn
Phần tử <uses-feature>
có một số chỉ số mô tả phần cứng cho phép bạn lọc
dựa trên sự hiện diện của các cảm biến cụ thể. Bạn có thể liệt kê các cảm biến sau:
gia tốc kế, khí áp kế, la bàn (trường địa từ), con quay hồi chuyển, ánh sáng và độ gần. Chiến lược phát hành đĩa đơn
sau đây là ví dụ về một mục kê khai giúp lọc các ứng dụng không có gia tốc kế:
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
Nếu bạn thêm phần tử và đặc tả này vào tệp kê khai của ứng dụng, người dùng sẽ nhìn thấy trên Google Play chỉ khi thiết bị của họ có gia tốc kế.
Bạn chỉ nên đặt chỉ số mô tả thành android:required="true"
khi ứng dụng của bạn
hoàn toàn dựa vào một cảm biến cụ thể. Nếu ứng dụng của bạn sử dụng cảm biến cho một số chức năng, nhưng
vẫn chạy mà không có cảm biến, bạn nên liệt kê cảm biến trong <uses-feature>
nhưng đặt phần mô tả thành android:required="false"
. Điều này giúp đảm bảo rằng
thiết bị có thể cài đặt ứng dụng của bạn ngay cả khi không có cảm biến cụ thể đó. Đây cũng là một
phương pháp quản lý dự án hay nhất giúp bạn theo dõi các tính năng mà ứng dụng của bạn sử dụng.
Xin lưu ý rằng nếu ứng dụng của bạn sử dụng một cảm biến cụ thể nhưng vẫn chạy mà không cần cảm biến,
thì bạn nên phát hiện cảm biến trong thời gian chạy và tắt hoặc bật các tính năng của ứng dụng như
phù hợp.
Hệ thống toạ độ cảm biến
Nói chung, khung cảm biến sử dụng hệ thống toạ độ 3 trục tiêu chuẩn để biểu thị các giá trị dữ liệu. Đối với hầu hết các cảm biến, hệ toạ độ được xác định tương ứng với màn hình của thiết bị khi thiết bị được giữ theo hướng mặc định (xem hình 1). Khi thiết bị được giữ ở hướng mặc định, trục X nằm ngang và trỏ sang bên phải, trục Y là trục tung và chỉ lên trên và Z trục trỏ ra phía bên ngoài mặt màn hình. Trong hệ thống này, toạ độ phía sau màn hình có giá trị Z âm. Hệ toạ độ này được các cảm biến sau sử dụng:
![](https://developer.android.com/static/images/axis_device.png?authuser=9&hl=vi)
Hình 1. Hệ thống toạ độ (tương đối so với một thiết bị) mà Cảm biến sử dụng API.
- Tăng tốc cảm biến
- Gravity (Trọng lực) cảm biến
- Con quay hồi chuyển
- Tăng tốc tuyến tính cảm biến
- Trường địa từ cảm biến
Điểm quan trọng nhất cần hiểu về hệ toạ độ này là các trục không hoán đổi khi hướng màn hình của thiết bị thay đổi – tức là hệ toạ độ của cảm biến không bao giờ thay đổi khi thiết bị di chuyển. Hành vi này giống với hành vi của OpenGL hệ toạ độ.
Một điểm khác cần hiểu là ứng dụng của bạn không được giả định rằng hướng (mặc định) là hướng dọc. Hướng tự nhiên của nhiều thiết bị máy tính bảng là hướng ngang. và hệ toạ độ của cảm biến luôn dựa trên hướng tự nhiên của thiết bị.
Cuối cùng, nếu ứng dụng của bạn khớp dữ liệu cảm biến với màn hình trên màn hình, bạn cần sử dụng
Phương thức getRotation()
để xác định chế độ xoay màn hình, sau đó sử dụng phương thức
Phương thức remapCoordinateSystem()
để liên kết
toạ độ cảm biến thành toạ độ màn hình. Bạn cần thực hiện việc này ngay cả khi tệp kê khai chỉ định
màn hình chỉ hiển thị dọc.
Lưu ý: Một số cảm biến và phương pháp sử dụng hệ toạ độ
so với hệ quy chiếu của thế giới (trái ngược với hệ quy chiếu của thiết bị). Các
Các cảm biến và phương thức trả về dữ liệu thể hiện chuyển động của thiết bị hoặc vị trí của thiết bị tương ứng với
trái đất. Để biết thêm thông tin, hãy xem phương thức getOrientation()
, phương thức getRotationMatrix()
, Hướng
Cảm biến và Vectơ xoay
Cảm biến.
Giới hạn tốc độ cảm biến
Để bảo vệ thông tin có thể mang tính nhạy cảm về người dùng, nếu ứng dụng của bạn nhắm đến Android 12 (API cấp 31) trở lên, hệ thống sẽ đặt giới hạn về quá trình làm mới tốc độ dữ liệu từ một số cảm biến chuyển động và cảm biến vị trí. Dữ liệu này bao gồm những giá trị do thiết bị ghi lại gia tốc kế, con quay hồi chuyển, và trường địa từ cảm biến.
Giới hạn tốc độ làm mới phụ thuộc vào cách bạn truy cập vào dữ liệu cảm biến:
- Nếu bạn gọi hàm
registerListener()
để theo dõi sự kiện cảm biến, thì tốc độ lấy mẫu của cảm biến là giới hạn ở 200 Hz. Điều này đúng với tất cả các biến thể nạp chồng của thuộc tínhregisterListener()
. - Nếu bạn sử dụng
Lớp
SensorDirectChannel
, tốc độ lấy mẫu cảm biến được giới hạn ởRATE_NORMAL
, vốn thường vào khoảng 50 Hz.
Nếu ứng dụng của bạn cần thu thập dữ liệu cảm biến chuyển động ở tốc độ cao hơn, bạn phải
khai báo
HIGH_SAMPLING_RATE_SENSORS
như được minh hoạ trong đoạn mã sau đây. Ngược lại, nếu ứng dụng của bạn cố gắng
để thu thập dữ liệu cảm biến chuyển động ở tốc độ cao hơn mà không cần khai báo quyền này,
SecurityException
sẽ xảy ra.
AndroidManifest.xml
<manifest ...> <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/> <application ...> ... </application> </manifest>
Các phương pháp hay nhất để truy cập và sử dụng cảm biến
Khi bạn thiết kế việc triển khai cảm biến, hãy nhớ tuân theo các nguyên tắc được thảo luận trong phần này. Những nguyên tắc này là các phương pháp hay nhất được đề xuất cho bất cứ ai dùng cảm biến khung truy cập cảm biến và thu thập dữ liệu cảm biến.
Chỉ thu thập dữ liệu cảm biến ở nền trước
Trên thiết bị chạy Android 9 (API cấp 28) trở lên, ứng dụng chạy trong nền có các hạn chế sau:
- Cảm biến sử dụng liên tục chế độ báo cáo, chẳng hạn như gia tốc kế và con quay hồi chuyển, sẽ không nhận được các sự kiện.
- Cảm biến sử dụng khi thay đổi hoặc một lần chế độ báo cáo không nhận được sự kiện.
Với những hạn chế này, tốt nhất bạn nên phát hiện sự kiện cảm biến khi ứng dụng chạy ở nền trước hoặc là một phần của dịch vụ trên nền trước.
Huỷ đăng ký trình nghe cảm biến
Hãy nhớ huỷ đăng ký trình nghe của cảm biến khi bạn sử dụng xong cảm biến hoặc khi cảm biến
các lượt tạm dừng hoạt động. Nếu một trình nghe cảm biến đã được đăng ký và hoạt động của trình nghe đó bị tạm dừng, thì cảm biến sẽ
tiếp tục thu thập dữ liệu và sử dụng tài nguyên pin trừ phi bạn huỷ đăng ký cảm biến. Nội dung sau đây
mã cho biết cách sử dụng phương thức onPause()
để huỷ đăng ký một trình nghe:
Kotlin
private lateinit var sensorManager: SensorManager ... override fun onPause() { super.onPause() sensorManager.unregisterListener(this) }
Java
private SensorManager sensorManager; ... @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); }
Để biết thêm thông tin, hãy xem unregisterListener(SensorEventListener)
.
Kiểm thử bằng Trình mô phỏng Android
Trình mô phỏng Android bao gồm một tập hợp các tuỳ chọn điều khiển cảm biến ảo cho phép bạn để kiểm tra các cảm biến như gia tốc kế, nhiệt độ môi trường xung quanh, từ kế, độ gần, ánh sáng, v.v.
Trình mô phỏng sử dụng kết nối với một thiết bị Android đang chạy SdkControllerSensor . Lưu ý rằng ứng dụng này chỉ có trên các thiết bị chạy Android 4.0 (API) cấp 14) trở lên. (Nếu thiết bị đang chạy Android 4.0, thiết bị phải có Đã cài đặt bản sửa đổi 2.) Ứng dụng SdkControllerSensor theo dõi các thay đổi về các cảm biến trên thiết bị rồi truyền chúng đến trình mô phỏng. Trình mô phỏng là sau đó được biến đổi dựa trên các giá trị mới mà thiết bị nhận được từ các cảm biến trên thiết bị của bạn.
Bạn có thể xem mã nguồn cho ứng dụng SdkControllerSensor trong vị trí sau đây:
$ your-android-sdk-directory/tools/apps/SdkController
Để chuyển dữ liệu giữa thiết bị và trình mô phỏng, hãy làm theo các bước sau các bước:
- Kiểm tra để đảm bảo rằng USB tính năng gỡ lỗi trên thiết bị của bạn.
- Kết nối thiết bị với máy phát triển bằng cáp USB.
- Khởi động ứng dụng SdkControllerSensor trên thiết bị của bạn.
- Trong ứng dụng, hãy chọn cảm biến mà bạn muốn mô phỏng.
Chạy lệnh
adb
sau:- Khởi động trình mô phỏng. Bây giờ, bạn có thể áp dụng các phép biến đổi cho bằng cách di chuyển thiết bị.
$ adb forward tcp:1968 tcp:1968
Lưu ý: Nếu bạn thực hiện chuyển động đối với
thiết bị thực tế không biến đổi trình mô phỏng, hãy thử chạy
lại lệnh adb
từ bước 5.
Để biết thêm thông tin, hãy xem bài viết Android Hướng dẫn dành cho trình mô phỏng.
Không chặn phương thức onSensorChanged()
Dữ liệu cảm biến có thể thay đổi với tốc độ cao, tức là hệ thống có thể gọi phương thức onSensorChanged(SensorEvent)
khá thường xuyên. Phương pháp hay nhất là
nên thực hiện ít nhất có thể trong phương thức onSensorChanged(SensorEvent)
để bạn không chặn phương thức đó. Nếu
yêu cầu bạn phải thực hiện bất kỳ thao tác lọc hoặc giảm dữ liệu cảm biến nào, thì bạn nên thực hiện
hoạt động bên ngoài phương thức onSensorChanged(SensorEvent)
.
Tránh sử dụng các phương thức hoặc loại cảm biến không dùng nữa
Một số phương thức và hằng số không được dùng nữa.
Cụ thể, TYPE_ORIENTATION
loại cảm biến này không được dùng nữa. Để nhận dữ liệu về hướng, bạn nên sử dụng phương thức getOrientation()
. Tương tự,
Ngừng sử dụng loại cảm biến TYPE_TEMPERATURE
. Bạn nên dùng
loại cảm biến TYPE_AMBIENT_TEMPERATURE
trên thiết bị
đang chạy Android 4.0.
Kiểm tra cảm biến trước khi dùng
Hãy luôn kiểm tra để đảm bảo cảm biến tồn tại trên thiết bị trước khi tìm cách thu thập dữ liệu qua thiết bị đó. Không nên làm giả định rằng một cảm biến tồn tại đơn giản vì đó là cảm biến được sử dụng thường xuyên. Nhà sản xuất thiết bị không bắt buộc phải cung cấp bất kỳ cảm biến cụ thể nào trong thiết bị của họ.
Chọn độ trễ cảm biến một cách cẩn thận
Khi đăng ký cảm biến bằng phương thức registerListener()
, hãy nhớ chọn tốc độ phân phối phù hợp với
ứng dụng hoặc trường hợp sử dụng. Các cảm biến có thể cung cấp dữ liệu với tốc độ rất cao. Cho phép hệ thống gửi
dữ liệu bổ sung mà bạn không cần sẽ làm lãng phí tài nguyên hệ thống và tốn pin.