Android Wear计时器开发

记得在2013年12月的时候,有系列文章是介绍怎么开发一个智能手表的App,让用户可以在足球比赛中记录停表时间。随着Android Wear的问世,在可穿戴设备中开发一款这样的App确实是个很不错的想法,但是按照目前对于Android Wear的架构了解来说,似乎有些困难。所以本系列文章我们就重写这个应用,带领大家进入Android Wear的世界。

本文不会长篇大论地讲解我们要开发的这款App的用途,因为我们在之前的系列文章已经深入了解过了。这么说吧,这是一个计时类应用,在比赛开始的时候开始执行,在比赛的过程中可以暂停(停表),然后45分钟过去后会有震动提醒,然后比赛进行45分钟后也会有提醒。

在开始之前,很有必要先看看我们为什么要重写这个App而不是直接上代码。智能手表使用的是一个修改版的Android1.6的系统,所以它的架构很像一个运行Android1.6的手机,所以我们的App基于一个Activity,我们所有的工作都运行在这个Activity上。在开始学习智能手表开发之前,我们必须很清楚地知道,我们之前的设计在Android Wear上并不适用,尽管它也是支持Activity,但是在Android Wear上工作方式是不同的。在手机或者平板上,如果一个Activity从sleep状态回到唤醒状态,Activity会被重新唤醒,但是在Wear上却不是这样。一段时间过去后Wear设备会进入sleep,但是在设备唤醒后,处于sleep状态的Activity却不会再被唤醒了。

首先这个问题使我非常惊讶,我一直很想知道Activity有了这个限制后,还能开发实用的App吗?后来才发现这个问题完全是多虑的,我渐渐地发现,要开发一个实用的App也很简单——我们只需要转变我们的软件设计模式,使它更符合Android Wear的体系结构,而不是当做一个手机来看。

这里我们需要考虑的最基本的问题是,这个计时应用程序需要基于一个一直运行的服务来记录时间。但是基于长运行的服务不是一个好的方案,因为它会耗电。这里我们提到的记录时间这个关键词,也就是说,我们并不需要真的实现一个长运行的服务,只要在用户需要看的时候我们可以更新消息显示就行。在大部分的时间里,其实用户只需要了解大概过去了多长时间,只有在比赛暂停或者中场快结束的时候才需要显示更详细的信息。所以在大部分的时间里,我们只需要显示精确到分钟即可,然后在用户需要的时候才精确到秒。

我们要实现这个方法的基本方法就是使用AlarmManager每分钟触发一次更新通知事件,去更新分钟显示。这个通知事件还包括显示精确到秒的Activity,但是只有在用户滑动屏幕的时候才会显示整个通知。通过这种方式我们可以在必须显示的时候才去更新消息,所以对大部分设备来说,每分钟更新一次消息显示比一直运行一个服务更加省电。

下图显示充分证明了这点,首先我们需要打开通知,这样就可以得到精确到秒的显示了。

然而,在有信息显示或者设备休眠的时候,我们只需要显示精确到分钟就可以了。

有一件事情需要说明一下,就是这个App的名字已经改变了。之前在在I‘m Watch的版本上叫做“Footy Timer”,现在改为“Match Timer”。因为在使用语音启动App的时候,Google的声音识别对“Footy”这个词很不敏感,我们用“ok Google,start Footy Timer”这个命令不能启动应用,而使用“ok Google,start Match Timer”就可以使用。

最后,很抱歉这篇文章没有代码,但是本系列文章会稍微有些变动。以前本人会在每篇文章末尾附上文章相关的代码段,这个请放心,之后的文章还是会这样的,因为这个是一个功能完善的App,而不是系列技术文章,所以在接下来的文章会包含一些代码示例和注释,在本系列文章完结的时候会附上整个项目的源码。

Match Timer 可以在Google Play上找到:https://play.google.com/store/apps/details?id=com.stylingandroid.matchtimer

上面我们解释了为什么要在Android Wear重写这个计时器app(因为之前已经在“I‘m Watch”里面开发过了),下面我们就来看看代码。

我们以这个app的一个核心类开始,这个类负责控制计时器的状态。这个类包含了4个long类型的变量:第一个代表计时器开始的时间;第二个代表计时器停止的时间(在运行中的话,它就是0);第三个代表计时器停表的时间(如果当前没有停表,那它也是0),第四个代表总共停表的时长。通过这四个变量我们就可以维持计时器的状态了,还可以通过计算得到我们需要展示的其他信息。这个类的基本功能就是都是为了操作这些变量,即维持计时器的这些状态。

public final class MatchTimer {
.
.
.
public static final int MINUTE_MILLIS = 60000;

private long start;
private long currentStoppage;
private long totalStoppages;
private long end;
.
.
.
public long getElapsed() {
  if (isRunning()) {
    return System.currentTimeMillis() - start;
  }
  if (end > 0) {
    return end - start;
  }
  return 0;
}

public boolean isRunning() {
  return start > 0 && end == 0;
}

public boolean isPaused() {
  return currentStoppage > 0;
}

public int getElapsedMinutes() {
  return (int) ((System.currentTimeMillis() - start) / MINUTE_MILLIS);
}

public long getTotalStoppages() {
  long now = System.currentTimeMillis();
  if (isPaused()) {
    return totalStoppages + (now - currentStoppage);
  }
  return totalStoppages;
}

public long getPlayed() {
  return getElapsed() - getTotalStoppages();
}

public long getStartTime() {
  return start;
}
.
.
.
}

这些都是基本的java代码,就不费时间讲了。下面的函数更高级一些,可以操作计时器的状态。

public final class MatchTimer {
.
.
.
public void start() {
  if (end > 0) {
    start = System.currentTimeMillis() - (end - start);
    end = 0;
  } else {
    start = System.currentTimeMillis();
  }
  save();
}

public void stop() {
  if (isPaused()) {
    resume();
  }
  end = System.currentTimeMillis();
  save();
}

public void pause() {
  currentStoppage = System.currentTimeMillis();
  save();
}

public void resume() {
  totalStoppages += System.currentTimeMillis() - currentStoppage;
  currentStoppage = 0L;
  save();
}

public void reset() {
  resetWithoutSave();
  save();
}

private void resetWithoutSave() {
  start = 0L;
  currentStoppage = 0L;
  totalStoppages = 0L;
  end = 0L;
}
}

这些还是基本的Java代码,也可以不用讲了。只有save()方法我们还没有见到,这是在类的最后写的,这个函数才值得的我们讲讲。

前一篇文章我们讨论了关于唤醒机制的问题,我们不需要去维持一个长连接或者后台服务,只需要维持这几个计时器的状态就可以了。我们使用SharedPreference来实现:

 public final class MatchTimer implements SharedPreferences.OnSharedPreferenceChangeListener {
  private static final String KEY_START = "com.stylingandroid.matchtimer.KEY_START";
  private static final String KEY_CURRENT_STOPPAGE = "com.stylingandroid.matchtimer.KEY_CURRENT_STOPPAGE";
  private static final String KEY_TOTAL_STOPPAGES = "com.stylingandroid.matchtimer.KEY_TOTAL_STOPPAGES";
  private static final String KEY_END = "com.stylingandroid.matchtimer.KEY_END";
  private static final String PREFERENCES = "MatchTimer";

  private final SharedPreferences preferences;

  public static MatchTimer newInstance(Context context) {
    SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
    long start = preferences.getLong(KEY_START, 0);
    long currentStoppage = preferences.getLong(KEY_CURRENT_STOPPAGE, 0);
    long totalStoppages = preferences.getLong(KEY_TOTAL_STOPPAGES, 0);
    long end = preferences.getLong(KEY_END, 0);
    return new MatchTimer(preferences, start, currentStoppage, totalStoppages, end);
  }

  private MatchTimer(SharedPreferences preferences, long start, long currentStoppage, long totalStoppages, long end) {
    this.preferences = preferences;
    this.start = start;
    this.currentStoppage = currentStoppage;
    this.totalStoppages = totalStoppages;
    this.end = end;
  }

  public void save() {
    preferences.edit()
        .putLong(KEY_START, start)
        .putLong(KEY_CURRENT_STOPPAGE, currentStoppage)
        .putLong(KEY_TOTAL_STOPPAGES, totalStoppages)
        .putLong(KEY_END, end)
        .apply();
  }

  public void registerForUpdates() {
    preferences.registerOnSharedPreferenceChangeListener(this);
  }

  public void unregisterForUpdates() {
    preferences.unregisterOnSharedPreferenceChangeListener(this);
  }

  @Override
  public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    long value = sharedPreferences.getLong(key, 0L);
    if (key.equals(KEY_START)) {
      start = value;
    } else if (key.equals(KEY_END)) {
      end = value;
    } else if (key.equals(KEY_CURRENT_STOPPAGE)) {
      currentStoppage = value;
    } else if (key.equals(KEY_TOTAL_STOPPAGES)) {
      totalStoppages = value;
    }
  }
  .
  .
  .
}

我们需要的就是newInstance()方法从SharedPreference中构造一个MatchTimer实例,我们还需要save()方法,可以帮我们把当前的计时器状态保存到SharedPreference中。

最后我们要说明的是,如果某一部分持有MatchTimer对象的引用,但是其他对象已经改变了计时器的状态,就可能会发生异常(见下一篇文章)。所以我们还需要提供一些方法去注册和注销MatchTImer的实例,在Sharedpreference的值改变时去接收计时器状态的变化。

现在我们已经定义了一个基本的计时器了,下一篇文章我们会介绍怎么保持计时器的状态以及在需要的时候去唤醒这些状态。

Match Timer 可以在Google Play上下载:Match Timer.

在本系列前几篇文章中,我们介绍了Android Wear计时器app,对设计思路和app的结构进行了分析。本文将讲解如何定时唤醒程序提醒用户。

对于为什么不用后台服务的方式一直运行,我们已经进行了解释——这种方式非常耗电。因此,我们必须要有一个定时唤醒机制。我们可以使用AlarmManager来实现这个机制,定时执行一个Intent,然后通知BroadcastReceiver。之所以选择BroadcastReceiver而不用IntentService,是因为我们要运行的任务是轻量级的而且生命周期非常短暂。使用BroadcastReceiver可以避免每次执行任务的时候都经历Service的整个生命周期。因此,对于我们这种轻量级的任务来说非常合适——我们执行的任务都在毫秒级。

BroadcastReceiver的核心在于onReceiver方法,我们需要在这里安排各种事件响应。

public class MatchTimerReceiver extends BroadcastReceiver {
public static final int MINUTE_MILLIS = 60000;
private static final long DURATION = 45 * MINUTE_MILLIS;

private static final Intent UPDATE_INTENT = new Intent(ACTION_UPDATE);
private static final Intent ELAPSED_ALARM = new Intent(ACTION_ELAPSED_ALARM);
private static final Intent FULL_TIME_ALARM = new Intent(ACTION_FULL_TIME_ALARM);

private static final int REQUEST_UPDATE = 1;
private static final int REQUEST_ELAPSED = 2;
private static final int REQUEST_FULL_TIME = 3;

public static void setUpdate(Context context) {
  context.sendBroadcast(UPDATE_INTENT);
}
.
.
.
private void reset(MatchTimer timer) {
  timer.reset();
}

private void resume(Context context, MatchTimer timer) {
  timer.resume();
  long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
  if (playedEnd > System.currentTimeMillis()) {
    setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
  }
}

private void pause(Context context, MatchTimer timer) {
  timer.pause();
  cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
  long elapsedEnd = timer.getStartTime() + DURATION;
  if (!isAlarmSet(context, REQUEST_ELAPSED, ELAPSED_ALARM) && elapsedEnd > System.currentTimeMillis()) {
    setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
  }
}

private void stop(Context context, MatchTimer timer) {
  timer.stop();
  cancelAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
  cancelAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM);
  cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
}

private void start(Context context, MatchTimer timer) {
  timer.start();
  long elapsedEnd = timer.getStartTime() + DURATION;
  setRepeatingAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
  if (timer.getTotalStoppages() > 0 && !timer.isPaused()) {
    long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
    if (playedEnd > System.currentTimeMillis()) {
      setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
    }
    if (elapsedEnd > System.currentTimeMillis()) {
      setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
    }
  } else {
    if (elapsedEnd > System.currentTimeMillis()) {
      setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, elapsedEnd);
    }
  }
}
.
.
.
}

代码还是非常直观易于理解的。首先实例化一个MatchTimer对象(从SharedPreference中读取数据),然后分别传给对应的事件处理Handler。之后等待动作发生,最后更新Notification。

这里会处理8个事件动作,其中5个负责控制计时器的状态(START、STOP、PAUSE、RESUME、RESET);一个负责更新Notification,剩下两个负责到45分钟唤醒后震动提示。

我们先从这几个控制状态开始:

public class MatchTimerReceiver extends BroadcastReceiver {
public static final int MINUTE_MILLIS = 60000;
private static final long DURATION = 45 * MINUTE_MILLIS;

private static final Intent UPDATE_INTENT = new Intent(ACTION_UPDATE);
private static final Intent ELAPSED_ALARM = new Intent(ACTION_ELAPSED_ALARM);
private static final Intent FULL_TIME_ALARM = new Intent(ACTION_FULL_TIME_ALARM);

private static final int REQUEST_UPDATE = 1;
private static final int REQUEST_ELAPSED = 2;
private static final int REQUEST_FULL_TIME = 3;

public static void setUpdate(Context context) {
  context.sendBroadcast(UPDATE_INTENT);
}
.
.
.
private void reset(MatchTimer timer) {
  timer.reset();
}

private void resume(Context context, MatchTimer timer) {
  timer.resume();
  long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
  if (playedEnd > System.currentTimeMillis()) {
    setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
  }
}

private void pause(Context context, MatchTimer timer) {
  timer.pause();
  cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
  long elapsedEnd = timer.getStartTime() + DURATION;
  if (!isAlarmSet(context, REQUEST_ELAPSED, ELAPSED_ALARM) && elapsedEnd > System.currentTimeMillis()) {
    setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
  }
}

private void stop(Context context, MatchTimer timer) {
  timer.stop();
  cancelAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
  cancelAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM);
  cancelAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM);
}

private void start(Context context, MatchTimer timer) {
  timer.start();
  long elapsedEnd = timer.getStartTime() + DURATION;
  setRepeatingAlarm(context, REQUEST_UPDATE, UPDATE_INTENT);
  if (timer.getTotalStoppages() > 0 && !timer.isPaused()) {
    long playedEnd = timer.getStartTime() + timer.getTotalStoppages() + DURATION;
    if (playedEnd > System.currentTimeMillis()) {
      setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, playedEnd);
    }
    if (elapsedEnd > System.currentTimeMillis()) {
      setAlarm(context, REQUEST_ELAPSED, ELAPSED_ALARM, elapsedEnd);
    }
  } else {
    if (elapsedEnd > System.currentTimeMillis()) {
      setAlarm(context, REQUEST_FULL_TIME, FULL_TIME_ALARM, elapsedEnd);
    }
  }
}
.
.
.
}

这些方法主要有两个功能:首先设置MatchTimer的状态,然后设置时间提醒的闹铃,改变参数就可以播放闹铃。这个功能还可以封装成一个工具方法,叫setUpdate()。这样外部也可以触发计时器的更新。

我们使用标准AlarmManager的方法来设置闹铃:

public class MatchTimerReceiver extends BroadcastReceiver {
.
.
.
public static final int MINUTE_MILLIS = 60000;
.
.
.

private void setRepeatingAlarm(Context context, int requestCode, Intent intent) {
  AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
  PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
  alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), MINUTE_MILLIS, pendingIntent);
}

private boolean isAlarmSet(Context context, int requestCode, Intent intent) {
  return PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_NO_CREATE) != null;
}

private void setAlarm(Context context, int requestCode, Intent intent, long time) {
  AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
  PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
  alarmManager.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}

private void cancelAlarm(Context context, int requestCode, Intent intent) {
  PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_NO_CREATE);
  if (pendingIntent != null) {
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    alarmManager.cancel(pendingIntent);
    pendingIntent.cancel();
  }
}
.
.
.
}

这里值得讨论的是setRepeatingAlarm()这个方法。因为在Wear在实现方式上有点不一样。我们会在Start事件中每秒钟触发一次闹铃更新Notification动作,所以这里需要记录具体已经过去了多少分钟。正常来说我们会每隔60秒触发一次这个动作,但是在Wear上不能这么做。原因是——当设备在唤醒着的时候可以这样做,但是如果设备进入睡眠状态就需要重新计算下一分钟的边界值。这就需要异步更新部件,然后设备只需要每分钟唤醒一次。一分钟结束后在计时器需要更新状态的时候触发操作。

对于我们的计时器应用来说,显示的分钟数会比实际时间少1分钟。但是显示分钟并不要求非常实时(但显示秒数时需要非常精确),所以我们可以这样操作:

完整的alarm Handler是这样使用振动服务的:

public class MatchTimerReceiver extends BroadcastReceiver {
.
.
.
private static final long[] ELAPSED_PATTERN = {0, 500, 250, 500, 250, 500};
private static final long[] FULL_TIME_PATTERN = {0, 1000, 500, 1000, 500, 1000};

private void elapsedAlarm(Context context) {
  Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
  vibrator.vibrate(ELAPSED_PATTERN, -1);
}

private void fullTimeAlarm(Context context) {
  Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
  vibrator.vibrate(FULL_TIME_PATTERN, -1);
}
.
.
.
}

最后,我们通过这个方法来构造Notification然后呈现给用户:

public class MatchTimerReceiver extends BroadcastReceiver {
public static final int NOTIFICATION_ID = 1;
.
.
.
private void updateNotification(Context context, MatchTimer timer) {
  NotificationBuilder builder = new NotificationBuilder(context, timer);
  Notification notification = builder.buildNotification();
  NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
  notificationManager.notify(NOTIFICATION_ID, notification);
}
}

Notification是Wear计时器的一个重要的部分,这里还需要一个自定义类来构造这些Notification通知。下一篇文章我们会讲如何在计时器app中使用Notification。

Match Timer可以在Google Play上下载:Match Timer

时间: 2024-07-30 13:52:45

Android Wear计时器开发的相关文章

Android Wear Eclipse开发环境搭建

本文介绍如何在Eclipse中搭建Android Wear的开发环境. 切记,这一切并非你想的那么简单 下面详细说明操作步骤,保证你可以正常工作. 打开你的"Android SDK Manager"升级需要的SDK,将SDK Tools升级到23.02以及Android 4.4W下的所有项,主要一定要升级Extra下的"Google Repository",建议你把所有能升级的全部升级. 升级完SDK后,我们创建一个Android Wear的模拟器,参考的参数配置如

Android Wear(手表)开发 - 学习指南

版权声明:欢迎自由转载-非商用-非衍生-保持署名.作者:Benhero,博客地址:http://www.cnblogs.com/benhero/ Android Wear开发 - 学习指南 http://www.cnblogs.com/benhero/p/4273800.html 前言 本篇文章是本人对这这一阶段Android Wear的开发总结,主要是对之前写的关于Android Wear方面技术的梳理,便于新人更好地交流学习. Android Wear究竟是什么? Android Wear和

IDEA搭建Android wear开发环境,Android wear,I'm comming!

随着google发布了android wear这个东西,然后又有了三星的gear,LG的G watch以及moto 360,苹果由发布了apple watch,未来可能在智能手表行业又有一场战争.当然这只是笔者的个人观点,仅供参考. 作为开发者,当然关心的是只能手表的开发了,所以我们来搭建一下android wear的开发环境吧! 搭建android wear开发环境,我们需要以下的软件Intellij 13.1.3,android-sdk 23.0.02. 首先需要下载安装好android-s

Android Wear 开发入门

大家好,我是陆嘉杰,我是一名Android开发者.我想和大家进行一些技术交流,希望越来越多的人能和我成为好朋友. 大家都知道,智能手表是下一个开发的风口,而这方面的技术又属于前沿,所以和大家分享下Android Wear的开发流程. 首先,我推荐大家使用Android Studio来进行Wear的开发,这也是谷歌推荐的,本次讲授过程也将以Android Studio作为开发集成环境进行. 下面我们来创建Android Wear项目. 请注意,Android Wear项目中同时包含mobile和w

想做Android Wear开发?你得先搞明白这四件事

手环和手表的腕上穿戴之争,随着Apple Watch发布和Android Wear不断完善而告一段落.尽管续航上略有缺陷,但手表以其类似手机可扩展的生态环境赢得了众多巨头的支持. Google曾透露,Android Wear发布三周左右应用数就超过了Google Glass,并将有数以千计的app不断加入.Apple Watch发布的该月内,雷锋网驻硅谷的记者发现已有公司开始招聘相关开发者. 国外的开发者生态一向积极,国内虽明面上动静不大,但实际各家也已经都在暗自开动.鉴于Apple Watch

如何开发Android Wear应用程序

Android Wear是连接安卓手机和可穿戴产品的一个平台.自从今年上半年发布以来,Android Wear获得了大量关注,既有来自消费者的关注,也有来自开发商的关注,后者希望自己的应用程序已经准备好让用户使用一种新的方式进行信息交互. 这篇文章将简要介绍Android Wear,然后介绍关于开发商的平台. Android Wear旨在为用户在对的时间提供数量合适的信息量.根据这一主题,谷歌已经发布了设计原则以帮助开发商集中思考Android Wear应用程序.我们将对此进行简要介绍,同时也将

Android Wear之android穿戴式设备应用开发平台

Android Wear于2014年03月19日公布,并有Moto 360和LG watch两款产品. 眼下源代码还没有开放.可是开发人员能够下载它的Image及相应的开发SDK,这样开发人员通过模拟器能够进行前期开发. 事实上,Android Wear包括两个部分,一部分是执行在穿戴式设备上的操作系统,一部分是给手持设备(手机.平板)程序使用的SDK,该SDK的主要目的是为可穿戴设备上应用开发提供了參考及规范.以引导用户开发出可同小屏幕设备协作操作的应用程序.这里使用"协作操作"是由

在Android Wear开发中使用蓝牙调试同时操作手机与手表设备

在开发Android Wear应用过程中需要对手表和手机进行同时操作,可以通过蓝牙同时对手机和手表进行操作. 1 打开手表和手机的调试设置 打开手机的usb调试 打开手表设置的开发者选项,选中Debug over Bluetooth   如果是首次使用手表调试,需要在Setting中找到About,单击7次打开开发者选项 2 连接手表到开发工具 在手机端打开Android Wear App,进入Setting,选中Debugging over Bluetooth,会发现当前状态是 <span s

Android 开发新方向 Android Wear ——概述

2014 谷歌 I/O大会正式公布的Android Wear 开发理念,从而能够更系统的提供开发人员使用Android接口开发便携式可穿戴设备,以智能手表为例,通过Android提供的接口,能够方便的将仅仅能手机与仅仅能手表进行关联,而且同步操作. 后面的文章将依次介绍几种相关的开发方式,如通知的方式.app的方式以及数据同步的方式. Android Wear 开发入门--怎样创建一个手机与可穿戴设备关联的通知(Notification) (未完) 开发Android Wear相关应用受到开发设