android wear那些事--使你的应用可见

Keeping Your App Visible

一些可穿戴应用在可见的情况下对使用者是非常有用的.比如跑步可以看跑的距离用的时间,或者记录一些食品列表这样在市场买东西的时候很方便.使你的应用可见对穿戴式设备的电池电量有影响,因此在添加这个特性到你的应用上时需要慎重考虑.

这里写图片描述

运行android 5.1或者更高版本的穿戴式设备允许应用保持在前台,同时节省电池电量.在低功耗环境模式时穿戴式设备可以控制屏幕上显示的内容.在环境和交互模式下的应用也被称为永远在线的应用.

在可穿戴应用中开启环境模式


对于新的或者已经存在的工程,你可以升级开发工程配置使你的可穿戴式应用支持环境模式.当你完成这个配置之后,继承WearableActivity这个类,它提供了使你的应用支持环境模式的所有方法.

配置开发工程

为了在你的应用中支持环境模式,需要升级SDK,并配置你的开发工程.

  • 升级SDK到android 5.1或者更高的版本,它提供了使activity支持环境模式的API.关于如何更新SDK,可以看Adding SDK Packages
  • 创建新的工程或者修改工程目标到android 5.1或者更高.即在清单文件中将targetSdkVersion设置为22或者更高
  • 在清单文件中将minSdkVersion设置为20或者更高,
  • build.gradle中添加或者更新依赖
dependencies {
    ...
    compile 'com.google.android.support:wearable:1.2.0'
    provided 'com.google.android.wearable:wearable:1.0.0'
}

注意provided依赖可以保证在运行时加载类支持环境模式同时在编译时也支持.

  • 在清单文件中添加分享库条目
<application>
  <uses-library android:name="com.google.android.wearable"
                android:required="false" />
  ...
</application>
<uses-permission android:name="android.permission.WAKE_LOCK" />

创建支持环境模式的activity

为了确保你的activity支持环境模式,使用WearableActivity这个类和相关方法.

1.创建自己的activity继承WearableActivity

2.在你的onCreate()方法中调用setAmbientEnabled()方法

public class MainActivity extends WearableActivity {

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

    setAmbientEnabled();
    ...
}

处理模式之间的转换

当穿戴式设备展示时用户在一段时间内没有交互,或者用户用手盖住设备屏幕,系统应该切换activity的环境模式.在应用切换模式之后,更新UI减少电池消耗.你应该使用黑背景和较小的白图形和文字.为了从交互模式切换到环境模式减少用户的反应,尽量保持和原来模式下相同的放置.

注意:当你的应用运行在没有物理按钮的设备上时,控制你的应用不会切换模式.否则它会使应用退出显示HOME页面.这个行为可以保证用户能优雅的退出应用.但是当屏幕超时时,这些设备仍然进入环境模式.

注意:在环境模式,交互元素是禁用的比如按钮.如何在永远生存的应用中设计用户交互可以参考App Structure for Android Wear

当activity切换到环境模式时,系统会调用onEnterAmbient()在你的activity中.下面的代码展示在切换到环境模式后如何将文本设为为白色和禁用抗锯齿.

@Override
public void onEnterAmbient(Bundle ambientDetails) {
    super.onEnterAmbient(ambientDetails);

    mStateTextView.setTextColor(Color.WHITE);
    mStateTextView.getPaint().setAntiAlias(false);
}

当用户敲击屏幕或者举起他们的手臂时,将会切换到交互模式.此时系统调用onExitAmbient()方法.下面的代码展示修改文本为绿色同时使抗锯齿可用.

@Override
public void onExitAmbient() {
    super.onExitAmbient();

    mStateTextView.setTextColor(Color.GREEN);
    mStateTextView.getPaint().setAntiAlias(true);
}

在环境模式下更新内容


环境模式允许使用用户的信息更新屏幕,但是需要小心的平衡更新.你应该慎重考虑重写onUpdateAmbient()方法在环境模式每分钟更新一次.如果你的应用要求更频繁的更新,请考虑电池电量和频繁更新两者的权衡.为了省电,更新不能超过10s一次这个频率.实际中你应该更少的更新你的应用.

每分钟更新一次

为了保持电池电量大多数穿戴式应用在环境模式都不应该频繁的更新屏幕.推荐在这个模式下每分钟更新一次.系统提供一个回调方法onUpdateAmbient(),在这个推荐的频率下更新屏幕.

@Override
public void onUpdateAmbient() {
    super.onUpdateAmbient();

    // Update the content
}

更加频繁的更新

对于需要更加频繁更新的应用,比如健身,计时.使用AlarmManager这个类的对象去唤醒进程完成更加频繁的更新屏幕.

  • 准备一个alarm管理器
  • 设置更新频率
  • 如果当前是环境模式或者当切换到环境模式时调度下一次更新
  • 当切换到交互模式或者activity停止时取消alarm

alarm 管理器可以被创建一个实例当他们被触发的时候.为了防止这种情况,确保你的activity在清单文件中声明了android:launchMode="singleInstance"这个参数.

准备alarm管理器

alarm管理器启动更新屏幕的隐式意图并且调度下一次更新.下面的代码展示了如何声明一个alarm管理器.

private AlarmManager mAmbientStateAlarmManager;
private PendingIntent mAmbientStatePendingIntent;

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

    setAmbientEnabled();

    mAmbientStateAlarmManager =
        (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent ambientStateIntent =
        new Intent(getApplicationContext(), MainActivity.class);

    mAmbientStatePendingIntent = PendingIntent.getActivity(
        getApplicationContext(),
        0,
        ambientStateIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);
    ...
}

当alarm被触发就会启动一个隐式意图,更新屏幕并调度下一次更新通过重写onNewIntent()这个方法.

@Override
public void onNewIntent(Intent intent) {
    super.onNewIntent(intent);

    setIntent(intent);

    // Described in the following section
    refreshDisplayAndSetNextUpdate();
}

更新屏幕并切调度更新数据

在这个示例activity中alarm管理器每20s触发一次.当定时器计时,alarm触发更新屏幕的意图同时设置下一次更新的延迟.

下面的代码展示了如何在屏幕上更新信息以及如何设置下一次更新.

// Milliseconds between waking processor/screen for updates
private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20);

private void refreshDisplayAndSetNextUpdate() {

    if (isAmbient()) {
        // Implement data retrieval and update the screen for ambient mode
    } else {
        // Implement data retrieval and update the screen for interactive mode
    }

    long timeMs = System.currentTimeMillis();

    // Schedule a new alarm
    if (isAmbient()) {
        // Calculate the next trigger time
        long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS);
        long triggerTimeMs = timeMs + delayMs;

        mAmbientStateAlarmManager.setExact(
            AlarmManager.RTC_WAKEUP,
            triggerTimeMs,
            mAmbientStatePendingIntent);

    } else {
        // Calculate the next trigger time for interactive mode
    }
}

调度下一次触发更新

通过重写onEnterAmbient()onUpdateAmbient()这两个方法当activity在进入环境模式或者activity已经是环境模式调度下次更新屏幕的报警器.

@Override
public void onEnterAmbient(Bundle ambientDetails) {
    super.onEnterAmbient(ambientDetails);

    refreshDisplayAndSetNextUpdate();
}

@Override
public void onUpdateAmbient() {
    super.onUpdateAmbient();

    refreshDisplayAndSetNextUpdate();
}

注意:在这个例子中当屏幕需要更新是refreshDisplayAndSetNextUpdate()这个方法就会被调用.更多的例子可以参考AlwaysOn

取消定时器

当切换回道交互模式,在onExitAmbient()这个方法里取消定时器.

@Override
public void onExitAmbient() {
    super.onExitAmbient();

    mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent);
}

当用户退出或者停止你的这个activity的时候需要在onDestroy()这个方法里取消定时器.

@Override
public void onDestroy() {
    mAmbientStateAlarmManager.cancel(mAmbientStatePendingIntent);
    super.onDestroy();
}

保持向后兼容


Activities that support ambient mode automatically fall back to normal activities on Wear devices that are on Android versions prior to 5.1 (API level 22). No special app code is required to support devices on these versions of Android. When the device switches to ambient mode, the device returns to the home screen and exits your activity.

如果你的应用不应在5.1之前的android版本安装或者更新,在清单文件中设置如下配置.

<uses-library android:name="com.google.android.wearable" android:required="true" />

推荐阅读更多精彩内容