原文链接:http://www.suncitta.com/archives/141 

Android Things App 不像移动设备,有可视化的用户界面,Android Things App 一般是在系统启动后自动启动,通过驱动与已连接的硬件设备交互,当然你也可以为嵌入式设备连接一个屏幕或其他输出设备与用户交互。

接下来我们看如何开发一个 Android Things App。

工具

  • 软件:Android Studio 3.1 及以上版本。
  • 硬件:Android Things 支持的硬件设备,如NXP Pico i.MX7D 或 Raspberry Pi 3 Model B。当然需要装有 Android Things 系统。本人使用的是 Raspberry Pi 3B,另外要注意目前 Android Things 不支持最新的 Raspberry Pi 3B+。
开发Android Things应用
Raspberry Pi 3B

 

另外为了熟悉硬件交互,可选择连接一些简单硬件:

  • 面包板(用于跳线连接)
  • 按钮
  • 电阻(用于连接 LED 灯)
  • LED 灯
  • 跳线(公对母,公对公)

环境准备

  • SDK tools version > 25.0.3
  • SDK version > Android 8.1(Oreo), API 27

新建项目

Android Studio 新建项目时,Target Android Devices 页单独选择 Android Things,Target API level 选择 27 以上。可以将新建的空 Activity 命名为 HomeActivity。

Android Things 设备所使用的 API 并不包含在 Android SDK 中,所以新建的项目 wizard 会自动在 app module 的 build.gradle 添加库依赖:

   dependencies {
        ...
        compileOnly 'com.google.android.things:androidthings:+'
    }

同时 wizard 也会在 app 的 manifest 文件中添加 <uses-library>标签来使得 app 在运行时能预编译这个库。

定义主 Activity

<application>
    <uses-library android:name="com.google.android.things"/>
    <activity android:name=".HomeActivity">
        <!-- Launch activity as default from Android Studio -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>

        <!-- Launch activity automatically on boot, and re-launch if the app terminates. -->
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.HOME"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
</application>

包含两个 intent-filter,第一个 LAUNCHER intent 是为了开发过程中 Android Studio 运行部署时能从这个 Activity 启动。第二个 HOME, DEFAULT 是为了设备在启动后能直接运行该 APP(因为一般一个设备上主要功能也是由这一个 APP 完成的)。

连接硬件设备

相关硬件连接方法见图

开发Android Things应用

与外围设备交互

跟连接的外围设备有了交互,才体现出 Android Things 的强大。

所有与外围设备的管理和交互都可以通过 PeripheralManager 来执行。

首先通过 PeripheralManager.getGpioList 来获取所有可用的 GPIO 接口。

import com.google.android.things.pio.PeripheralManager;
...

public class HomeActivity extends Activity {
    private static final String TAG = "HomeActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        PeripheralManager manager = PeripheralManager.getInstance();
        Log.d(TAG, "Available GPIO: " + manager.getGpioList());
    }
}

另外可以监听 GPIO 的高低电平事件

  1. PeripheralManager 打开一个连接了按钮的 GPIO 端口
  2. 将端口设置为 DIRECTION_IN
  3. 将触发回调的状态转换设置为 Gpio.EDGE_FALLING
  4. 注册 GpioCallback 来监听边缘触发事件
  5. 回调中返回 true 来继续接收未来的触发事件
  6. 当不再使用 GPIO 连接时,需要关掉连接资源
import com.google.android.things.pio.PeripheralManager;
import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.GpioCallback;
...

public class ButtonActivity extends Activity {
    private static final String TAG = "ButtonActivity";
    private static final String BUTTON_PIN_NAME = ...; // GPIO port wired to the button

    private Gpio buttonGpio;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        PeripheralManager manager = PeripheralManager.getInstance();
        try {
            // Step 1. Create GPIO connection.
            buttonGpio = manager.openGpio(BUTTON_PIN_NAME);
            // Step 2. Configure as an input.
            buttonGpio.setDirection(Gpio.DIRECTION_IN);
            // Step 3. Enable edge trigger events.
            buttonGpio.setEdgeTriggerType(Gpio.EDGE_FALLING);
            // Step 4. Register an event callback.
            buttonGpio.registerGpioCallback(mCallback);
        } catch (IOException e) {
            Log.e(TAG, "Error on PeripheralIO API", e);
        }
    }

    // Step 4. Register an event callback.
    private GpioCallback mCallback = new GpioCallback() {
        @Override
        public boolean onGpioEdge(Gpio gpio) {
            Log.i(TAG, "GPIO changed, button pressed");

            // Step 5. Return true to keep callback active.
            return true;
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // Step 6. Close the resource
        if (buttonGpio != null) {
            buttonGpio.unregisterGpioCallback(mCallback);
            try {
                buttonGpio.close();
            } catch (IOException e) {
                Log.e(TAG, "Error on PeripheralIO API", e);
            }
        }
    }
}
  1. 接下来我们来点亮一个 LED 吧
  2. 使用 PeripheralManager 来打开连接 LED 的 GPIO 端口
  3. 将端口设置为 DIRECTION_OUT_INITIALLY_LOW,即初始输出状态为低电平
  4. 每次触发都把 LED 的 GPIO 设置为与之前相反的状态,
  5. 通过 Handler 来调度,在一段时间后重新触发 LED 的 GPIO,让 LED 状态与之前一次相反,反复则 LED 闪动。
import com.google.android.things.pio.PeripheralManager;
import com.google.android.things.pio.Gpio;
...

public class BlinkActivity extends Activity {
    private static final String TAG = "BlinkActivity";
    private static final int INTERVAL_BETWEEN_BLINKS_MS = 1000;
    private static final String LED_PIN_NAME = ...; // GPIO port wired to the LED

    private Handler mHandler = new Handler();

    private Gpio ledGpio;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Step 1. Create GPIO connection.
        PeripheralManager manager = PeripheralManager.getInstance();
        try {
            ledGpio = manager.openGpio(LED_PIN_NAME);
            // Step 2. Configure as an output.
            ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);

            // Step 4. Repeat using a handler.
            mHandler.post(blinkRunnable);
        } catch (IOException e) {
            Log.e(TAG, "Error on PeripheralIO API", e);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // Step 4. Remove handler events on close.
        mHandler.removeCallbacks(blinkRunnable);

        // Step 5. Close the resource.
        if (ledGpio != null) {
            try {
                ledGpio.close();
            } catch (IOException e) {
                Log.e(TAG, "Error on PeripheralIO API", e);
            }
        }
    }

    private Runnable blinkRunnable = new Runnable() {
        @Override
        public void run() {
            // Exit if the GPIO is already closed
            if (ledGpio == null) {
                return;
            }

            try {
                // Step 3. Toggle the LED state
                ledGpio.setValue(!ledGpio.getValue());

                // Step 4. Schedule another event after delay.
                mHandler.postDelayed(blinkRunnable, INTERVAL_BETWEEN_BLINKS_MS);
            } catch (IOException e) {
                Log.e(TAG, "Error on PeripheralIO API", e);
            }
        }
    };
}

使用驱动来与外围设备交互

开发过程中可以使用Android Things 驱动库 来加快进度,这个驱动库是由 Android Things 开发者贡献的,实现针对不同硬件的快速控制或状态读取。例如使用温度感应器驱动,能方便的读取当前温度,而不用再去通过传感器说明书进行数据转换。

相关文章:

  • 2021-05-21
  • 2021-11-21
  • 2021-04-08
  • 2022-01-14
  • 2021-08-02
  • 2021-07-18
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-08-24
  • 2021-11-29
  • 2021-07-28
  • 2021-08-24
  • 2022-12-23
  • 2022-01-16
  • 2021-09-28
相关资源
相似解决方案