面向大众的移动技术: 轻轻一划!在 Android 中为手势编码

将 Android 移动应用程序中的按钮转换成滑动手势

移动用户通常思想不集中、非常繁忙、容易受人体工程学的约束,因此您需要相应地构建自己的移动应用程序 UI。Andrew Glover 讨论了区分移动应用程序和 Web 应用程序的关键因素,然后指导您创建一个移动应用程序 UI,使用滑动手势而非按键来进行导航。

Andrew Glover, CTO, App47

Andrew GloverAndrew Glover 是开发人员、作家、演讲家和企业家,酷爱行为驱动开发、持续集成和敏捷软件开发。他是 easyb 行为驱动开发 (BDD) 框架的创始人,还是三部图书的合著者:Continuous IntegrationGroovy in ActionJava Testing Patterns。您可以通过他的 博客 并在 Twitter 上关注他来掌握他的最新动态。



2013 年 5 月 30 日

构建移动应用程序和构建 Web 应用程序一样,要时刻牢记最终目标(和用户)。始终了解您的应用程序可以给用户带来哪些利益。您的应用程序将显示哪些类型的信息,拥有哪些功能,用户如何获取这些信息和功能?对移动应用程序的用户体验给予足够的关注有助于确保获得成功。

关于本系列

近年来,移动应用程序发布呈爆炸式增长,移动开发技术市场亦是如此。本系列是一个新系列,向那些熟悉编程但对移动技术较为陌生的开发人员介绍移动应用程序。先从使用 Java 代码为本机应用程序编码开始介绍,然后扩展工具包,使之包含 JVM 语言、脚本框架、HTML5/CSS/JavaScript、第三方工具等。本系列文章将带您逐步掌握这些必要技术,实际应对所有移动开发场景。

不同于面向桌面或 Web 应用程序的传统 GUI 开发,移动应用程序的规则是宁缺勿滥。当您决定设计一个应用程序界面时,可能想简单点,想容易点。大多数移动设备都很小(除非您面对的是 Samsung Note 4,这是我见过的最大移动电话,也称作 平板电脑)。小巧是其流行的一个重要原因,因为人们可以随身携带,随时使用。这导致关于移动应用程序的另一个重要发现,大多数用户使用移动设备时并不关注应用程序。

一些移动应用程序是专门为平板电脑而构建的,只是为了实现业务使用(比如医生访问病人记录)。大多数移动应用程序需要用户通过微型设备进行访问,坦白的说,用户也会做些其他事情。当我在线等待购买一些日用品时,可能会玩几局愤怒的小鸟。结束长途飞行下飞机后,可能会利用这段时间查收邮件。但是,如果只需要单击两下或者轻轻一划就能加载愤怒的小鸟或者邮件信息,我可能会继续使用移动应用程序。

将移动应用程序与传统 Web 和桌面应用程序真正区分开的另一个要素就是数量:对于每个 Web 应用程序来说,很容易获得 100 个移动应用程序。使用您的应用程序提供多个有价值的服务,确保这些应用程序容易使用且具有吸引力。如果您希望用户通过 RTM(参考用户手册)使用您的应用程序,那么您给用户制造了一个问题,这最终将成为您的问题。无论用户是访问病人记录的医生,还是在休息室玩 Cut-the-Rope 的人,这没有关系。如果您的应用程序只需几分钟才能安装好,那么用户可能会搜索应用程序商店,寻找一个需要更短时间的应用程序。

(Hello) Overheard Word

如果您阅读了本系列的 第一篇文章,您就会知道如何在 Eclipse 中构建 Android 开发环境,上一篇文章已经为 Android 4.2 配置了 Android SDK。您应该已经完成了第一个 Android 应用程序,经典的 Hello World。在本期文章中,您将继续设计一个更独特的应用程序。

我的示例应用程序 Overheard Word 旨在使学习新词汇并在上下文中使用新词汇变得更有趣、更简单,顺便说一下,这是我最大的两个爱好。在这个应用程序中,用户学习了几个单词后就可以进行测验。界面由一个显示界面和两个按钮组成。显示的是单词及其相应定义,而按钮是用于用户导航的。

Overheard Word 是一个有趣且简单的移动应用程序,适用于那些喜欢学习单词的人们(我的意思是可用词汇痴迷者 和单词行家 描述他们)。更重要的是,该示例可作为构建一个合法 Android 应用程序的示例,您可以将其部署到真正的 Android 设备中。

以应用程序为目标

在设计一个应用程序之前,我喜欢评估目标市场。在第 1 部分中构建的应用程序的目标是 Android 4.2 或者 API 版本 17。看看 Google 发布的最流行的 Android 版本。(参见图 1):

图 1. Android 分布,按版本号排列
屏幕截图显示了 Android 版本的分布情况

平板电脑和手机

图 1 中,平板电脑销量很可能是 Android 15 用户增加所引起的。不管是哪个供应商,多数平板电脑目前都运行 Android 4.x。除非您专门构建一个 Android 平台电脑应用程序,是否应将您的应用程序目标定为 Android API 9 和 10,这是目前移动设备的主流市场。

图 1 显示 Android 2.3.x(API 版本 9 和 10)目前仅占有大约一半的 Android 设备市场!如果所有 Android 设备的一半设备都在运行 Android 2.3.x,那么为这一市场进行开发不是很有意义吗?


开始一个新项目

在结束上一期文章时,我已经安装了 API 4.2。现在我想要安装 Android 2.3.3 (API 10) 。再次启动 Android SDK Manager 时,如 图 2 所示,您会看到有一些更新可以安装:

图 2. 一个本地 Android SDK 安装程序,仅有一个安装版本
Android SDK Manager 屏幕截图显示已经安装了 Android 4.2

如果您想要和我一起进行,请单击 Android 2.3.3 (API 10) 安装选项,保留管理员指定的推荐更新。

图 3. 安装 Android 2.3.3 (API 10)
Android SDK Manager 安装 Android 2.3.3 的屏幕截图

下载了新的 Android API 后,必须创建一个兼容模拟器或 Android Virtual Device (AVD)。在 Android SDK Manager 中选择 Tools 菜单,然后选中 Manage AVDs。务必创建一个目标为 API Level 10 的 AVD。

图 4. 创建一个 AVD
在 SDK Manager 中创模拟器或者 AVD 的屏幕截图

接着,创建一个 New Android Application 项目并为其命名。我的项目名称是 Overheard Word 应用程序。将该应用程序的目标设为 API 10,使其能够访问最多的设备。仔细查看 图 5 中的屏幕截图,您会注意到我也选择使用 API 10 进行编译。您可以使用一个更高的 Android 版本进行编译,但是我喜欢使用同一个 API 进行编程和编译。(如果使用最近发布的 API 进行编译,则必须注意,不能使用我应用程序中的任何特性,这可能导致兼容问题。)

图 5. 在 Eclipse 中创建一个新 Android 项目
在 Eclipse 中创建新 Android 项目的屏幕截图

当单击 Next 时,务必确定没有将您的应用程序保存为一个 Library Project。在下期文章中,将会继续为 Hello World 应用程序保留相同默认设置。可以在后期进行一些小的变动(比如,更改应用程序的图标文件)。

最后一步是为您的第一个 Activity 命名。我将我的 Activity 命名为 OverheardWord,而不是 Main,然后对布局也进行了类似的命名。如果您也使用 API 10 作为目标版本,最后对话框中会有几个 Navigation Type 选项。现在不用担心;在后续文章中,我会向您介绍如何创建一个导航菜单。对于该应用程序,将您的 Navigation Type 选项保留为 none

图 6. 创建一个默认 Activity
在 Eclipse 中创建一个默认 Activity 的屏幕截图

单击 Finish 创建一个项目,这个项目和 上次 创建的默认项目很像。


构建一个 Android UI

现在,您已经构建了一个简单 UI。你还记得吗?Android UI 最终是作为一个 XML 文档定义的,对此您可能比较熟悉。如果您从事的是传统 Java™ GUI 开发,那么您可能会记得布局工具,Android 也使用了布局工具。您可以使用 Android 的布局工具来定义(实际上建议)某个设备如何布局您的应用程序可视组件。布局样式包括:

  • Linear:其中组件以平行和垂直方式布局(类似于报纸专栏)
  • Relative:其中组件彼此相互隔开(小部件 2 位于小部件 1 的右边,等等)
  • Table:其中小部件按行或列展示

有很多布局工具可用,这只是个开始!

您可以使用一个布局工具来定义小部件,您会发现这是所有 GUI 中的常用组件。Android 平台提供了一些基础小部件,比如按钮、文本框、下拉列表,以及图片浏览器和滚轮之类较为复杂的小部件。

我觉得我的 Overheard Word UI 需要:

  • 三个文本字框(分别保存一个单词、发音和定义)
  • 两个按钮(一个选择新单词,一个进行测验)

定义布局

要将一个 Android UI 组合起来,第一步是定义其布局以及您想要在其中使用的小部件。在 清单 1 中,我首先定义了一个带有 3 个 TextViewsLinearLayout。接下来,我将创建一个子布局(另一个 LinearLayout)来保存两个 Button

清单 1. 在 Android 中定义一个 LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".OverheardWord" >

    <TextView
        android:id="@+id/word_study_word"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="10dp"
        android:layout_marginTop="60dp"
        android:textColor="@color/black"
        android:textSize="30sp" />

    <TextView
        android:id="@+id/word_study_part_of_speech"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:textColor="@color/black"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/word_study_definition"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="40dp"
        android:layout_marginRight="40dp"
        android:textColor="@color/black"
        android:textSize="18sp" />

    <LinearLayout
        android:id="@+id/widget62"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp" >

        <Button
            android:id="@+id/next_word"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@string/next_word" />

        <Button
            android:id="@+id/take_quiz"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="50dp"
            android:layout_marginTop="20dp"
            android:text="@string/take_quiz" />
    </LinearLayout>

</LinearLayout>

正如您从 清单 1 的 XML 中所看到的,每个小部件都有很多属性,这些属性最终会影响其外观。例如,每个按钮都有一个 text 元素,其字符串指向一个资源元素。该资源元素是在名为 strings.xml资源文件 中定义的,strings.xml 位于 res/values 目录下。清单 2 展示了 strings.xml 文件。

清单 2. 定义按钮颜色和标签的资源文件
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Overheard Word</string>

    <color name="white">#ffffff</color>
    <color name="black">#000000</color>

    <string name="next_word">Next word</string>
    <string name="take_quiz">Take quiz</string>

</resources>

如果想看看我的 UI 之前的样子,可以启动一个模拟器实例,在 Eclipse 中单击 Graphical Layout 即可,如 图 7 所示。

图 7. Eclipse 中运行的 Overheard Word
在 Eclipse 中运行的 Overheard Word 应用程序的屏幕截图

占位符文本

预览我的 UI,我被单词属性的空格弄的有点糊涂。不过这不是什么大问题:为了更真实的呈现文本显示,我在编写代码之前添加了一些样例文本。

首先,为每个小部件添加了一个 android:text 属性,就像为按钮标签添加属性那样。现在,占位符文本的添加已经完成,如下这样:

清单 3. 使用 android:text 创建一个占位符
<TextView
        android:id="@+id/word_study_part_of_speech"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:textColor="@color/black"
        android:textSize="18sp" 
        android:text="Part of Speech"/>

正如您在 清单 3 所看到的,我将样例文本("Part of Speech") 添加到了 word_study_part_of_speechTextView 中。通过增加文本大小、定义文本颜色以及将布局中的小部件居中,我更新了一些样式元素。对于 Android 应用程序中的定义来说,清单 3 中的属性比较常见;当构建更多应用程序时,就会熟悉和喜爱这些属性了。我直接在我的布局文件中定义了样例文本,没有在资源文件中定义它们,因为我的设计过程中的文本值是临时的。

当我从 Eclipse 中运行我的应用程序时,我就在想当用户启动应用程序时会看到什么:

图 8. AVD 中运行的 Overheard Word
在 AVD 中运行的 Overheard Word 应用程序的屏幕截图

UI 设计的某些方面目前还有一个小问题。您能猜到是什么问题吗?对,就是令人讨厌的按钮。它们是必需的吗?用户平常会单击移动应用程序上的按钮吗?用户可能通过左右滑动来查看新单词,或者通过向下滑动来进行测验。

删除按钮可清理 UI,使 Overheard Word 应用程序可以更好地满足大多数移动用户的期望。我可以很轻松地实现滑动行为,您很快就会看到。


在 Android 中为手势编码

我为 Overheard Word 应用程序定义了初始界面,并添加了一些行为。我将自己的传统 Java GUI 开发再次应用到 Android 上,首次在 Android 中使用监听器来响应事件。如果要保留两个按钮,我可能会使用 OnClickListener 将行为附加到按钮单击活动中,然后将它们附加到每个按钮小部件的 setOnClickListener 方法中。

匿名类

匿名类是在某个类的内部定义的类,但是没有名称:您可以在一个表达式中定义和实例化 匿名类。我发现匿名类既方便又好用,我编写了很多匿名类,特别是在编写用户界面行为时。

当我确定可以使用 OnClickListener 时,如果不止有一个小部件,那么我可能会使用多个类文件来结束这一切。我不喜欢杂乱无序,所以我选择使用匿名类的备用实现策略。

尽管滑动手势 是传统 GUI 编程中所没有的概念,但其实现类似于编写一个按钮单击。我启动了一个触摸监听器(它是底层 Android 平台的一部分),然后提供响应行为。为了检测手指滑动动作,我还计算了一个手势的开始结束 之间的差异,以及滑动姿势。(我发这是非常有用的,可以考虑这种情况:在迪卡尔坐标中,左右滑动位于 X 轴上,而上下滑动位于 Y 轴上。)

手势可能出现在界面的任何地方,如果将这类监听器附加到应用程序界面的任何组件上,就可以启动布局(这在 Android 中可以表示为 View)并包含最简单的按钮小部件。我使用 Android 的 SimpleOnGestureListener 创建我的初始手势实现,然后通过 onTouchListener 方法将其附加到 View 中。我可以通过将它附加到视图实例中来检测整个 界面上的手指滑动,而不仅仅是在其组件内部(比如小图片浏览器)中进行测试。

尽管可以这样做,但我必须编写一个可检测移动设备上手指活动的类。

SwipeDetector

按钮单击相对较为容易检测。底层操作系统通常提取按钮边界的坐标信息,因此可以跳过人工定义这一步。编写您的应用程序来识别和响应一个滑动动作有点复杂。Android 将其留给程序员来编写,虽然这个任务稍微有点复杂,但也为您提供了极大的灵活性。您可以和我一样选择检测单一滑动动作,也可以检测其他手指动作,比如游戏中有时会使用摩擦。

考虑移动性

您是否很好奇移动监听器是否仍然通过动作单击 来定义?我上次查看的时候,用户通常是按下 移动设备上的按钮,而不是像桌面上使用鼠标那样单击 按钮。既然是一名移动开发人员,就要考虑到可移动性,这意味着需要重新思考传统 Web 和桌面机制,比如按钮单击、开始菜单,甚至 GUI 向导。

编写手势滑动检测程序涉及到笛卡尔数学。也就是说,如果 X 轴上的开始坐标 减去结束坐标 大于预先定义的距离,那么您就可以假设用户将手指从应用程序界面右边滑到左边。在 Y 轴上使用了同样的方法来检测上下滑动。

很容易将这类逻辑抽象到某个进行数据运算的简单类中。SimpleOnGestureListener 有一个调用 onFling 的方法。onFling 方法提供了两个 MotionEvent 类型的参数(分别用于开始结束)来表示 X 轴上的速度,还提供了两个 float 参数来表示 Y 轴上的速度。因此,清单 4 中的 SwipeDetector清单 4 有 4 个方法来描绘一个滑动的全部活动:上、下、左、右。

清单 4. SwipeDetector
import android.view.MotionEvent;

public class SwipeDetector {

    private int swipe_distance;
    private int swipe_velocity;
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;

    public SwipeDetector(int distance, int velocity) {
        super();
        this.swipe_distance = distance;
        this.swipe_velocity = velocity;
    }

    public SwipeDetector() {
        super();
        this.swipe_distance = SWIPE_MIN_DISTANCE;
        this.swipe_velocity = SWIPE_THRESHOLD_VELOCITY;
    }

    public boolean isSwipeDown(MotionEvent e1, MotionEvent e2, float velocityY) {
        return isSwipe(e2.getY(), e1.getY(), velocityY);
    }

    public boolean isSwipeUp(MotionEvent e1, MotionEvent e2, float velocityY) {
        return isSwipe(e1.getY(), e2.getY(), velocityY);
    }

    public boolean isSwipeLeft(MotionEvent e1, MotionEvent e2, float velocityX) {
        return isSwipe(e1.getX(), e2.getX(), velocityX);
    }

    public boolean isSwipeRight(MotionEvent e1, MotionEvent e2, float velocityX) {
        return isSwipe(e2.getX(), e1.getX(), velocityX);
    }

    private boolean isSwipeDistance(float coordinateA, float coordinateB) {
        return (coordinateA - coordinateB) > this.swipe_distance;
    }

    private boolean isSwipeSpeed(float velocity) {
        return Math.abs(velocity) > this.swipe_velocity;
    }

    private boolean isSwipe(float coordinateA, float coordinateB, float velocity) {
        return isSwipeDistance(coordinateA, coordinateB)
                && isSwipeSpeed(velocity);
    }
}

现在,已经有一个便利的类可以告诉我手指是否滑动过,我可以将它嵌入到我的 UI 中。回忆一下第一次创建的默认活动,我将其命名为 OverheardWord。我保留了 Eclipse 提供的所有代码,但为了监听滑动并做出响应,还要添加一些新内容,我定义了 Android GestureDetector,它将执行一次 OnGestureListener 实现。非常感谢 Android 团队创建了一个便利的类,我可以通过一个称为 SimpleOnGestureListener 的匿名类来实现此操作,然后重写 onFling 方法。

UI 中的滑动检测

在 Activity 的 onCreate 方法中,最初使用 SimpleOnGestureListener 创建了一个 GestureDetector,这需要使用我的 SwipeDetector 类。

下一步是创建一个小对话框,当手指滑动时指定触发事件。这类小的、临时的对话框在这里称为 Toast。有时候 Toast 仅有一行代码。

清单 5. GestureDetector
private GestureDetector initGestureDetector() {
    return new GestureDetector(new SimpleOnGestureListener() {
        
        private SwipeDetector detector = new SwipeDetector();
        
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
               float velocityY) {
            try {
                if (detector.isSwipeDown(e1, e2, velocityY)) {
                    return false;
                } else if (detector.isSwipeUp(e1, e2, velocityY)) {
                    showToast("Up Swipe");
                }else if (detector.isSwipeLeft(e1, e2, velocityX)) {
                    showToast("Left Swipe");
                } else if (detector.isSwipeRight(e1, e2, velocityX)) {
                    showToast("Right Swipe");
                }
            } catch (Exception e) {} //for now, ignore
            return false;
        }
        
        private void showToast(String phrase){
            Toast.makeText(getApplicationContext(), phrase, Toast.LENGTH_SHORT).show();
        }
    });
}

现在,我们将创建一个计算用户手指滑动范围和速度的 initGestureDetector 方法。首先创建一个匿名 SimpleOnGestureListener 实例,并提供一个 onFling 方法的实现。请注意 onFling 方法是如何使用 SwipeDetector 的。例如,如果某个匹配项向上滑动,则会显示 Toast 来表示移动。

下一步是将这个滑动检测行为插入我的 UI 中。首先注册几个带有 View 实例的监听器。

清单 6. 在视图上注册滑动检测。
private GestureDetector gestureDetector;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_overheard_word);

    gestureDetector = initGestureDetector();

    View view = findViewById(R.id.LinearLayout1);

    view.setOnTouchListener(new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
        }
    });

    view.setOnClickListener(new OnClickListener() {
        public void onClick(View arg0) {
        }
    });
}

我在 onCreate 方法中通过其 Id 获得了 View 实例的一个句柄。多数 Java 开发人员都比较喜欢这个便捷的 Android-ism

通过 ID 方法找到视图

还记得我为 UI 定义 XML 时各个资源文件(比如 strings.xml)中相应的值吗?在我编译 Android 应用程序时,XML 将变成代码,提供给类 R 中的相应 Id。在执行进一步操作之前,应检查您项目的 gen 目录下的 R 类。

查看您的布局 XML 文件(您可能会想起我将我的 XML 文件命名为 activity_overheard_word.xml)。该 XML 文件中的每个小部件都有一个 id 属性。例如,为了简便起见,我的应用程序的布局 idandroid:id="@+id/LinearLayout1"LinearLayout1Id 名称由 Eclipse 自动生成,如果需要的话,可以更改该名称。重要的是这个 idLinearLayout1R 类中有一个相对应的属性,如 清单 7 所示。

清单 7. R 类中的小部件 ID
public static final class id {
    public static final int LinearLayout1=0x7f090000;
    public static final int action_settings=0x7f090004;
    public static final int word_study_definition=0x7f090003;
    public static final int word_study_part_of_speech=0x7f090002;
    public static final int word_study_word=0x7f090001;
}

通过将 XML 文件的内容及其相应 R 文件结合使用,可以在不需要解析 XML 的情况下引用这些小部件。因此,将会返回 Activity 的 onCreate 方法,我可以通过 View 小部件的 idR.id.LinearLayout1)来应用它。findViewById 方法是在扩展 Activity 时 Android 平台提供的。

手指一划,轻松搞定!

获得 View 实例之后,就可以通过 setOnTouchListener 附加我的 gestureDetector 实例。在 清单 6 中,另一个匿名类现在正在处理我的所有触摸行为。当用户触摸设备屏幕时,就会触发事件并根据 gestureDetector 进行操作。我还实现了一个 OnClickListener,并在 OnClickListener 方法中对其进行设置;但是在本例中匿名类没有任何行为。

有了这些,我就拥有了一个可以响应手指滑动的较为简单的接口。在本示例中,可以使用其中三个滑动手势:左、右和上。在您的 AVD 中试试这些代码。要模拟一个手指滑动,可以使用鼠标单击,然后向上、向下、向右拖拽。

现在,在真实的设备上运行这个正在开发的应用程序将会怎样?


部署一个开发

为了应对那些祸害毫无戒心的用户的病毒、木马程序和恶意软件的繁殖,Apple 和 Google 为运行在其设备上的第三方应用程序分别引入了代码签名。理论上,代码签名可以确保让有信誉的人来构建应用程序,确保在您安装应用程序之前没有人可以篡改它们。实际上,Google 和 Apple 签名代码的安全程度不一样。例如,我在签署我的 Android 应用程序时,可以声明我是一个信誉良好的国家银行。当我签署我的 iOS 或 Windows Phone 8 应用程序时就无法这样做。

在开发模式下,无需担心代码签名。事实上,Android 和 Eclipse 构建了带有开发人员密钥的二进制签名,而这个密钥是您所不知道的。因此,在开发模式下将某个应用程序放到设备上并不困难,最简单的方法是将您的 Andriod 设备插入计算机 USB 端口。

接下来,进入 Eclipse,右键单击您的项目并选择 Run As menu 选项,然后单击 Run Configurations。Eclipse 显示一个配置对话框,您可以在其中选择您的项目,然后单击 Target 选项卡,如 图 9 所示。

图 9. 选择一个用来运行您的应用程序的设备
在 Eclipse 中选择一个设备的屏幕截图

您可以选择 Always prompt to pick device(如果您希望有选择性)或者 Launch on all compatible devices/AVD's。如果选择了后者,可以像我那样选择 Active Devices 选项卡,然后单击 Run。假设您和我一起进行编码,片刻之后,一个漂亮的应用程序将呈现在您的设备上。将手指向左、向右、向上滑动,见证奇迹的时刻到了,这个简单的对话框会搞定一切。

安全设置

如果不能从 Email 或 Dropbox 加载您的应用程序,那么请进入设备设置界面,然后启动 Security Settings 下的 Unknown Sources。您可以使用该功能安装应用程序,包括您正在开发的应用程序,而不是 从 Google Play 进行安装。

另一个部署应用程序的方法是将其 .apk 文件通过邮件发给您,然后在您的 Android 设备上打开该文件,按照自动安装对话框的提示进行操作。您也可以将 .apk 文件上传到像 Dropbox 这样的服务中,然后在您的设备上打开 Dropbox 进行安装。应用程序的 .apk 文件在您项目的 bin 目录下,Eclipse 也在其中保存了相应的二进制文件。

记住,这些部署机制是用于开发测试的,并不是用于发布应用程序。要发布您的应用程序并从其中赚钱涉及到更多的步骤,我会在后续文章中进一步介绍。


结束语

设计一个移动应用程序意味着需要将一切想的简单一点、容易一些。本期文章您学习了如何编写一个移动应用程序来响应滑动手势,没有涉及桌面或 Web 用户的按钮单击。有时候,移动设备可能会从一两个便捷的按钮中获益。确保它们适合用户之目的,我不需要为我这个超级简单的应用程序 Overheard Word 设计按钮,对于大多数应用程序用户来说,我使用的这个手指上下滑动导航比较直观。

在本文中,我大致介绍了移动应用程序部署,并没有深入介绍测试,因为您还没有部署一个产品应用程序。多数用户不会安装没有信誉的应用程序,这就是许多成功的应用程序都通过中间机构(比如 Google Play、iTunes App Store 或 Amazon Appstore for Android)来发布的原因。在这篇文章中,我详细介绍了满足应用程序商店安全标准的流程,该流程只需要很少几步,比签署您的应用程序要简单得多。重要的是当您的应用程序被大经销商发布后,它会变成全世界 可用。

参考资料

学习

获得产品和技术

讨论

  • developerWorks 社区:探索由开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户进行交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology, Open source
ArticleID=931838
ArticleTitle=面向大众的移动技术: 轻轻一划!在 Android 中为手势编码
publish-date=05302013