Android Cheatsheet For Designers

转载一篇比较好的Android设计文章:Android Cheatsheet For Designers


Java Enum

常量

在JDK1.5 之前,我们定义常量都是: public static final …. 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。

public enum Color {
  RED, GREEN, YELLOW
}

switch

JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。

enum Signal {
    GREEN, YELLOW, RED
}

public class TrafficLight {
    Signal color = Signal.RED;

    public void change() {
        switch (color) {
        case RED:
            color = Signal.GREEN;
            break;
        case YELLOW:
            color = Signal.RED;
            break;
        case GREEN:
            color = Signal.YELLOW;
            break;
        }
    }
}

向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。

public enum Color {
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
    // 成员变量
    private String name;
    private int index;

    // 构造方法
    private Color(String name, int index) {
        this.name = name;
        this.index = index;
    }

    // 普通方法
    public static String getName(int index) {
        for (Color c : Color.values()) {
            if (c.getIndex() == index) {
                return c.name;
            }
        }
        return null;
    }

    // get set 方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

覆盖枚举的方法

下面给出一个toString()方法覆盖的例子。

public class Test {
    public enum Color {
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
        // 成员变量
        private String name;
        private int index;

        // 构造方法
        private Color(String name, int index) {
            this.name = name;
            this.index = index;
        }

        // 覆盖方法
        @Override
        public String toString() {
            return this.index + "_" + this.name;
        }
    }

    public static void main(String[] args) {
        System.out.println(Color.RED.toString());
    }
}

实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

public interface Behaviour {
    void print();

    String getInfo();
}

public enum Color implements Behaviour {
    RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
    // 成员变量
    private String name;
    private int index;

    // 构造方法
    private Color(String name, int index) {
        this.name = name;
        this.index = index;
    }

    // 接口方法

    @Override
    public String getInfo() {
        return this.name;
    }

    // 接口方法
    @Override
    public void print() {
        System.out.println(this.index + ":" + this.name);
    }
}

使用接口组织枚举

public interface Food {
    enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO
    }

    enum Dessert implements Food {
        FRUIT, CAKE, GELATO
    }
}

关于枚举集合的使用

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档

方法介绍

所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。

  • ordinal()

返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。

Color.RED.ordinal();  //返回结果:0
Color.BLUE.ordinal();  //返回结果:1
  • compareTo()

Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。(具体可见源代码)

Color.RED.compareTo(Color.BLUE);  //返回结果 -1
  • values()

静态方法,返回一个包含全部枚举值的数组。

Color[] colors=Color.values();
for(Color c:colors){
    System.out.print(c+","); 
}
//返回结果:RED,BLUE,BLACK YELLOW,GREEN,
  • toString()

返回枚举常量的名称。

Color c=Color.RED;
System.out.println(c);//返回结果: RED
  • valueOf()

这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。

Color.valueOf("BLUE");   //返回结果: Color.BLUE
  • equals()

比较两个枚举类对象的引用。

//JDK源代码:      
public final boolean equals(Object other) {  
    return this==other;  
}

Android Debug Tool -- pidcat

在Android开发的过程中我们会用Logcat来查看应用程序的log信息,而我们一般都是在Eclipse集成好的DDMS上直接使用,调试应用非常方便。但总觉得Logcat并不适合所有场景,Logcat比较适合开发过程中的调试,而且依赖Eclipse也比较重,如果不是开发效率的限制,个人还是更倾向于vim或者Sublime Text这种轻量的编辑器。还好发现了一个命令行环境下的调试工具pidcat。

pidcat其实就是一个python脚本,运行后可以很清晰在命令行下查看应用的log信息,不必依赖eclipse而且可以查看某一单个应用的log信息,运行前请先确保装了python,mac下是自带python的.

项目地址: https://github.com/stormzhang/pidcat

运行:

./pidcat.py com.boohee.one

下面是我机器上运行的截图


ActiveAndroid--Android轻量级ORM框架

最近在寻找下Android开发中好用的ORM框架,发现了ActiveAndroidORMLite, 相信懂Rails开发的一直都对ActiveRecord情有独钟,使用起来真是太方便了。ActiveAndroid听名字就知道就模仿ActiveRecord的一套框架,于是果断学习下。

介绍

ActiveAndroid算是一个轻量级的ORM框架,简单地通过如save()和delete()等方法来做到增删改查等操作。配置起来也还算简单。

下面是作者的原话:

ActiveAndroid is an active record style ORM (object relational mapper). What does that mean exactly? Well, ActiveAndroid allows you to save and retrieve SQLite database records without ever writing a single SQL statement. Each database record is wrapped neatly into a class with methods like save() and delete().

ActiveAndroid does so much more than this though. Accessing the database is a hassle, to say the least, in Android. ActiveAndroid takes care of all the setup and messy stuff, and all with just a few simple steps of configuration.

配置

在AndroidManifest.xml中我们需要添加这两个

  • AA_DB_NAME (这个name不能改,但是是可选的,如果不写的话 是默认的”Application.db”这个值)

  • AA_DB_VERSION (optional – defaults to 1)

<manifest ...>
    <application android:name="com.activeandroid.app.Application" ...>
        ...
        <meta-data android:name="AA_DB_NAME" android:value="your.db" />
       <meta-data android:name="AA_DB_VERSION" android:value="5" />
    </application>
</manifest>

这个application是必须指定的,但你也可以使用自己的Application,继承自com.activeandroid.app.Application

public class MyApplication extends com.activeandroid.app.Application {
    ...
}

如果你不想或者不能继承com.activeandroid.app.Application的话,那么就这样

public class MyApplication extends SomeLibraryApplication {
    @Override
    public void onCreate() {
        super.onCreate();
        ActiveAndroid.initialize(this);
    }
    @Override
    public void onTerminate() {
        super.onTerminate();
        ActiveAndroid.dispose();
    }
}

ActiveAndroid.initialize(this);做初始化工作,ActiveAndroid.dispose();做清理工作

创建数据库模型

我们使用@Table(name = "Items")来表示表,使用@Column(name = "Name")来表示列,ActiveAndroid会使用自增长的ID作为主键,然后按照注解描述,将类对应映射为数据库表。
@Table(name = "Items")
public class Item extends Model {
    @Column(name = "Name")
    public String name;
    @Column(name = "Category")
    public Category category;
        public Item(){
                super();
        }
        public Item(String name, Category category){
                super();
                this.name = name;
                this.category = category;
        }
}

依赖关系的数据库表

假如Item和Category是多对一的关系,那么我们可以这样子创建他们的类

@Table(name = "Items")
public class Item extends Model {
    @Column(name = "Name")
    public String name;
    @Column(name = "Category")
    public Category category;
}
@Table(name = "Categories")
public class Category extends Model {
    @Column(name = "Name")
    public String name;
    public List<Item> items() {
        return getMany(Item.class, "Category");
    }
}

保存和更新数据到数据库

单条插入

保存Category对象

Category restaurants = new Category();
restaurants.name = "Restaurants";
restaurants.save();

分配了一个category并且保存到数据库 Item item = new Item(); item.category = restaurants; item.name = “Outback Steakhouse”; item.save();

批量插入

如果你要批量插入数据,最好使用事务(transaction)。

ActiveAndroid.beginTransaction();
try {
    for (int i = 0; i < 100; i++) {
        Item item = new Item();
        item.name = "Example " + i;
        item.save();
    }
    ActiveAndroid.setTransactionSuccessful();
}
finally {
    ActiveAndroid.endTransaction();
}

使用事务的话只用了 40ms,不然的话需要4秒。

删除记录

我们有三种方式删除一条记录

Item item = Item.load(Item.class, 1);
item.delete();
Item.delete(Item.class, 1);
new Delete().from(Item.class).where("Id = ?", 1).execute();

很简单吧

查询数据库

作者将查询做的非常像SQLite的原生查询语句,几乎涵盖了所有的指令 com.activeandroid.query包下有以下类

  • Delete

  • From

  • Join

  • Select

  • Set

  • Update

我们举例说明吧

public static Item getRandom(Category category) {
    return new Select()
        .from(Item.class)
        .where("Category = ?", category.getId())
        .orderBy("RANDOM()")
        .executeSingle();
}

对应的sqlite查询语句就是 select * from Item where Category = ? order by RANDOM(), 当然还支持其他非常多的指令

  • limit

  • offset

  • as

  • desc/asc

  • inner/outer/cross join

  • group by

  • having 等等

数据库升级

如果想给现有的表增加或删除column,这个时候只需要把sql脚本放在/assets/migrations文件夹下,然后需要:

  1. 增加数据库版本,即增加配置文件下的application种的AA_DB_VERSION

  2. 在/assets/migrations文件夹下提供一个NewVersion.sql脚本

ActiveAndroid将会自动执行大于database-version的sql脚本文件

假设需要给Items表增加一个“colour”列,那么需要把AA_DB_VERSION增加到2,并且在/assets/migrations目录下提供一个2.sql的脚本文件,内容如下

ALTER TABLE Items ADD COLUMN Color INTEGER;

Android ActionBar Compact

介绍

自Action Bar设计概念在Android 3.0(API 11) 中被Google引入以后,在4.0版本之后更是被Google纳入设计规范中,从Google的各大App中都可以看到这种设计。

但Action Bar虽好,它出现之初Android官方版本的ActionBar 只支持Android 3.0 (API 11)及以后的系统版本。而由于Android众所周知的碎片化问题,当开发者试图在minSdkVersion小于11的系统上使用Action Bar时只好使用大名鼎鼎的JakeWharton发布的ActionBarSherlock

还好,在Google I/O 2013后,官方版本的兼容 Android 2.1(API 7)及其以后版本的ActionBarCompat终于发布了 (包含在Support Library v7 r18中)。原本使用ActionBarSherlock的一众应用们也开始了升级至ActionBarCompat的工作。这篇博客就来分享下如何使用ActionBarCompat实现Action Bar。

首先确认了开发环境中Android SDK已经安装了Support Library r18或以上,目前最新的是19, 接下来,开始实际建立一个ActionBar的开发实例。实现一个含有Action Bar Icon, Title, Action Item 以及Action Overflow的ActionBar Hello World应用。效果如下

Eclipse+Android ADT环境下:

1. Create a blank Android Project

创建一个空的Android项目,这里具体就不再赘述。

2. 将Support V7 appcompat Library添加至工程

a. 导入ActionBarCompat工程(这个工程是个Library)

ActionBarCompat的source code位置是:<Android SDK目录>/extras/android/support/v7/appcompat

这样我们就得到一个名叫android-support-v7-appcompat 的library project

b. 接着在自己新建的project点击右键->选择Properties->选择Android选项

点Add, 然后选择 android-support-v7-appcompat

点击OK 搞定。

3. Update Style Resources

刚才说了ActionBarCompat在使用中会调用一些资源文件,尤其是基于Theme.AppCompat的主题(Theme)用来规范Action Bar的显示。如果使用Action Bar的Activity没有使用基于Theme.AppCompat的主题,程序就不知道该如何配置Action Bar的显示,就会报错导致程序退出。

在AndroidManifest中讲Application的 android:theme属性设置为Theme.AppCompat系列Theme。

<application
    android:label="@string/app_name"
    android:icon="@drawable/ic_launcher"
    android:theme="@style/Theme.AppCompat.Light">

如果你在使用自定义的Theme,则该Theme的parent应设置为Theme.AppCompat系列Theme.

<!-- Application theme. -->
<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowBackground">@color/global_main_bg</item>
</style>

4. Extend ActionBarActivity

当要在Activity中使用ActionBar,并要求兼容Android 2.1~3.0之间的系统时,我们不能像往常那样extend Activity,而应extend ActionBarActivity(原因如上所属,Android 3.0以前的系统中Activity API里是没有ActionBar接口的 自然也就无法调用。为了向下兼容,必须使用ActionBarActivity)。

import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;

public class MainActivity extends ActionBarActivity {

    private ActionBar actionBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        actionBar=getSupportActionBar();
        //actionBar operation
        actionBar.setTitle("ActionBar");
        //....
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

你的project中会有一个默认的main.xml,为了向Action Bar中添加几个功能按钮(也就是Action Items),我们需要对menu/main.xml进行些修改:

  • 在root element中添加一个attribute

  • 添加新的item项

如下:

<menu
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="always" />
    <item android:id="@+id/action_search"
        android:title="@string/action_search"
        android:orderInCategory="1"
        android:icon="@drawable/action_search"
        app:showAsAction="always" />
</menu>

Action Items广泛使用的一些icon,你可以从Download the Action Bar Icon Pack下载到。

最后,如果需要在程序中对ActionBar进行操作,可以通过getSupportActionBar()来实现。

actionBar = getSupportActionBar();
//actionBar operation
actionBar.setTitle("ActionBar");