读ActiveAndroid源码(一)

  首先ActiveAndroid是依靠注解工作的。

  

@Table(name = "UserBean")
public class UserBean extends Model {

    @Column(name = "uid")
    public String uid;
    @Column(name = "nick_name")
    public String nick_name;

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getNick_name() {
        return nick_name;
    }

    public void setNick_name(String nick_name) {
        this.nick_name = nick_name;
    }
}

  对类添加Table注解,对类的成员添加Column注解,因此,我们可以先看看这两个注解的定义。

  

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

    public static final String DEFAULT_ID_NAME = "Id";
    public String name();
    public String id() default DEFAULT_ID_NAME;
}

  Table的定义如上,有两个成员,分别是idname,通常我们只需要设置nameid的名字为设置默认。这个name就是数据库的表名,id为表中作为id字段的名字。

  Column的定义比较复杂,但我们可以想象其中一定有name成员,name就是表中的字段名。

  然后,ActiveAndroid用了一个TableInfo类保存类和表的连接信息。先来看看这个类

  

package com.activeandroid;

/*
 * Copyright (C) 2010 Michael Pardo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.text.TextUtils;
import android.util.Log;

import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.util.ReflectionUtils;

public final class TableInfo {
    //////////////////////////////////////////////////////////////////////////////////////
    // PRIVATE MEMBERS
    //////////////////////////////////////////////////////////////////////////////////////

    private Class<? extends Model> mType;
    private String mTableName;
    private String mIdName = Table.DEFAULT_ID_NAME;

    private Map<Field, String> mColumnNames = new LinkedHashMap<Field, String>();

    //////////////////////////////////////////////////////////////////////////////////////
    // CONSTRUCTORS
    //////////////////////////////////////////////////////////////////////////////////////

    public TableInfo(Class<? extends Model> type) {
        mType = type;

        final Table tableAnnotation = type.getAnnotation(Table.class);

        if (tableAnnotation != null) {
            mTableName = tableAnnotation.name();
            mIdName = tableAnnotation.id();
        }
        else {
            mTableName = type.getSimpleName();
        }

        // Manually add the id column since it is not declared like the other columns.
        Field idField = getIdField(type);
        mColumnNames.put(idField, mIdName);

        List<Field> fields = new LinkedList<Field>(ReflectionUtils.getDeclaredColumnFields(type));
        Collections.reverse(fields);

        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class)) {
                final Column columnAnnotation = field.getAnnotation(Column.class);
                String columnName = columnAnnotation.name();
                if (TextUtils.isEmpty(columnName)) {
                    columnName = field.getName();
                }

                mColumnNames.put(field, columnName);
            }
        }

    }

    //////////////////////////////////////////////////////////////////////////////////////
    // PUBLIC METHODS
    //////////////////////////////////////////////////////////////////////////////////////

    public Class<? extends Model> getType() {
        return mType;
    }

    public String getTableName() {
        return mTableName;
    }

    public String getIdName() {
        return mIdName;
    }

    public Collection<Field> getFields() {
        return mColumnNames.keySet();
    }

    public String getColumnName(Field field) {
        return mColumnNames.get(field);
    }

    private Field getIdField(Class<?> type) {
        if (type.equals(Model.class)) {
            try {
                return type.getDeclaredField("mId");
            }
            catch (NoSuchFieldException e) {
                Log.e("Impossible!", e.toString());
            }
        }
        else if (type.getSuperclass() != null) {
            return getIdField(type.getSuperclass());
        }

        return null;
    }

}

  首先是成员变量

  

    private Class<? extends Model> mType;
    private String mTableName;
    private String mIdName = Table.DEFAULT_ID_NAME;

    private Map<Field, String> mColumnNames = new LinkedHashMap<Field, String>();

  mType:需要被储存的类的类型;

  mTableName:储存的类的表名;

  mIdName:储存的类的表的id字段名称;

  mColumnNames: 储存的表中的字段名与类中的成员的映射;

  

    public TableInfo(Class<? extends Model> type) {
        mType = type;

        final Table tableAnnotation = type.getAnnotation(Table.class);

        if (tableAnnotation != null) {
            mTableName = tableAnnotation.name();
            mIdName = tableAnnotation.id();
        }
        else {
            mTableName = type.getSimpleName();
        }

    ......

}

  tableAnnotation保存被储存类的注解,并从注解中读出表名和表id名,如果没有注解,则默认类的简名为表名。

  

    public TableInfo(Class<? extends Model> type) {
        mType = type;

      ......

        // Manually add the id column since it is not declared like the other columns.
        Field idField = getIdField(type);
        mColumnNames.put(idField, mIdName);

    ......
}

  手动添加表的id名与类的id关系。看看getIdField方法:

    private Field getIdField(Class<?> type) {
        if (type.equals(Model.class)) {
            try {
                return type.getDeclaredField("mId");
            }
            catch (NoSuchFieldException e) {
                Log.e("Impossible!", e.toString());
            }
        }
        else if (type.getSuperclass() != null) {
            return getIdField(type.getSuperclass());
        }

        return null;
    }

    一个递归,通过getSuperclass()寻找父类,一直到父类为Model,将其中mId成员返回。

  

  public TableInfo(Class<? extends Model> type) {      

     ......   

        List<Field> fields = new LinkedList<Field>(ReflectionUtils.getDeclaredColumnFields(type));
        Collections.reverse(fields);

        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class)) {
                final Column columnAnnotation = field.getAnnotation(Column.class);
                String columnName = columnAnnotation.name();
                if (TextUtils.isEmpty(columnName)) {
                    columnName = field.getName();
                }

                mColumnNames.put(field, columnName);
            }
        }

    }

  如上这段代码,通过反射取出了要储存类的所有标注的成员,并获取它们的注解字段名,如果没有解注字段名,则用成员名代替。最终将它们全部与成员本身一一映射放入mColumnNames中。

  以上就是一个TableInfo的初始化过程。下一次将阅读将所有已标注类成员取出的代码。

  Done!

时间: 2024-10-11 11:11:58

读ActiveAndroid源码(一)的相关文章

读ActiveAndroid源码(五)

前面几篇,断断续续地囫囵吞枣地读了ActiveAndroid的部分源码,大致了解了ActiveAndroid的注解反射原理.其中很多细节还不算很清楚,加之内容非常多,为了更好地阅读接下来的内容,在此对前面阅读的部分作一个总结. 在之前的几篇中,重点阅读了ActiveAndroid中的三个类:Conguration , ModelInfo , TableInfo.下面将对这三个类的作用做一个简单地总结: 一.Conguration 先看一下Conguration的成员变量: public fina

读ActiveAndroid源码(二)

上一次粗略地读了一下TableInfo这个类,了解了一下ActiveAndroid中注解的使用方法,算是一个预热,这一篇,从正常的顺序开始. 所以,这次从ActiveAndroid的初始化开始阅读. public class Application extends android.app.Application { @Override public void onCreate() { super.onCreate(); ActiveAndroid.initialize(this); } @Ove

读ActiveAndroid源码(三)

上一章,我们读完了Conguration这个类.最后我们发现,Conguration就是为了数据库的初始化.其中包含了内存大小.数据库名称.数据库版本.parser信息. public static synchronized void initialize(Configuration configuration) { if (sIsInitialized) { Log.v("ActiveAndroid already initialized."); return; } sContext

读ActiveAndroid源码(四)

上一章在读DatabaseHelper的初始化时,发现读不动了,因为ModelInfo应该放在前面读.因此,现在开始读ModelInfo. final class ModelInfo { ////////////////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS //////////////////////////////////////////////////

读Zepto源码之样式操作

这篇依然是跟 dom 相关的方法,侧重点是操作样式的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1.2.0 内部方法 classRE classCache = {} function classRE(name) { return name in classCache ? classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name

读 zepto 源码之工具函数

Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目标对象的同名属性会被源对象的属性覆盖. $.extend 其实调用的是内部方法 extend, 所以我们先看看内部方法 extend 的具体实现. function extend(target, source, deep) { for (key in source) // 遍历源对象的属性值 if (deep && (i

读Zepto源码之操作DOM

这篇依然是跟 dom 相关的方法,侧重点是操作 dom 的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1.2.0 .remove() remove: function() { return this.each(function() { if (this.parentNode != null) this.parentNode.removeChild(this) }) }, 删除当前集合中的元素. 如果父

读 Zepto 源码之内部方法

数组方法 定义 var emptyArray = [] concat = emptyArray.concat filter = emptyArray.filter slice = emptyArray.slice zepto 一开始就定义了一个空数组 emptyArray,定义这个空数组是为了取得数组的 concat.filter.slice 方法 compact function compact(array) { return filter.call(array, function(item)

读jQuery源码之四(Callbacks,Deferred,when)

看了下Sizzle部分源码,核心的原理就是使用正则表达式去匹配,找到对应的原生获取元素的方法,我没有去细究了.大家有兴趣可以自己看看,分享分享! 从2850行开始,继续往下读jQuery源码(2850-3043行) 进入Callbacks(回调函数管理模块)之前,有几个扩展方法 1.dir方法 三个参数:elem——dom元素,dir——指定elem的层级名称(例如parentNode,nextSibling),until——结束判断.返回一个数组,比如获取某个元素的parentNode,如果不