.

简介 : Android 常用的代码结构, 包括包的规范, 测试用例规范, 数据库模块常用编写规范;

参考 : 之前写的一篇博客 【Android 应用开发】 Application 使用分析 ;

-- Application 分析 : Application 概念, 声明周期, 组件间传递数据作用, 数据缓存作用;

-- 源码分析 : 分析 Application 结构接口源码;

-- 使用示例 : 自定义 Application 注册, 保存崩溃日志到文件, 监听Activity声明周期;


一. 包结构规范

1. 基本包, 业务包, 测试包

包基础结构 :

-- base 包 : 应用中常用的公共包 和 类放在该包中, 例如 工具类, SQLiteOpenHelper, 配置类, Application, 各种类的基类 等;

-- business 包 : 应用中的实际业务包, 这个包存放 与 app 业务相关的具体实现的类 和 包;

-- test 包 : 用于存放单元测试 和 测试用例相关的包;

示例 :

2. 根据类型将 Java 类 分入不同包中

UI 相关 :

-- activity : 存放 Activity 相关的包;

-- fragment : 存放 Fragment 相关类;

-- widget : 存放自定义组件相关类;

适配器相关 :

-- adapter : 各种适配器, 尤其是 BaseAdapter 子类;

Java Bean相关 : 下面的两种包名经常存放 JavaBean 对象;

-- bean :

-- domain :

工具类相关 :

-- utils : 存放工具类;

监听器相关 :

-- listener : 存放各种监听器, 如按钮点击监听器等等;

数据库相关 :

-- sqlite : 存放数据库相关的包;

业务相关 :

-- engine : 存放业务逻辑相关类;

二. Application 代码规范

1. Application 单例规范

单例属性 : Application 本身就是单例模式, 在整个应用中, 只存在一个 Application 对象;

实现 Application 单例 :

-- 定义 Application 类型对象 : 在 自定义的 Application 中定义一个 Application 类型的函数;

private static QIApplication INSTANCE;

-- 定义共有构造方法

	/**
	 * 构造方法构造 Application
	 */
	public QIApplication() {
		INSTANCE = this;
	}

-- 公共, 静态方法获取对象 : 在任何类中, 都可以调用该方法, 获取 Application 上下文对象;

	/**
	 * 获取 Application 使用该函数可以在任意位置获取 Application 中的数据
	 * @return
	 */
	public static QIApplication getInstance() {
		return INSTANCE;
	}

2. Application 用于组件间数据传递 和 数据缓存

在  【Android 应用开发】 Application 使用分析  博客中有这方面的讲解;

Application 组件间数据传递 , Application 数据缓存;

3. Application 常用框架

代码示例 :

public class MyApplication extends Application {

	private static MyApplication INSTANCE;

	/** 用于数据传递的 Map 集合 */
	private Map<String, Object> transferMap;
	/** 用于缓存数据的 Map 集合 */
	private Map<String, Object> cacheMap; 

	/**
	 * 构造方法构造 Application
	 */
	private MyApplication() {
		INSTANCE = this;
	}

	/**
	 * 获取 Application 使用该函数可以在任意位置获取 Application 中的数据
	 * @return
	 */
	public static MyApplication getInstance() {
		return INSTANCE;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		// 初始化用于数据传递的 Map 集合
		transferMap = new HashMap<String, Object>();
		// 初始化用于数据缓存的 Map 集合
		cacheMap = new HashMap<String, Object>();
	}

	/**
	 * 获取数据传递 Map 集合
	 * @return
	 * 		数据传递 Map 集合
	 */
	public Map<String, Object> getTransferMap() {
		return transferMap;
	}

	/**
	 * 向 transferMap 集合中添加数据元素
	 */
	public void putTransferMapElement(String key, Object object) {
		transferMap.put(key, object);
	}

	public Object getTransferMapElement(String key) {
		return transferMap.get(key);
	}

	/**
	 * 向 transferMap 数据中移除对应的数据元素
	 */
	public void removeTransferMapElement(String key) {
		transferMap.remove(key);
	}

	/**
	 * 获取数据缓存 Map 集合
	 * @return
	 * 		数据缓存 Map 集合
	 */
	public Map<String, Object> getCacheMap() {
		return cacheMap;
	}

}

三. 数据库模块代码常用结构

1. SQLiteOpenHelper 类

(1) 命令 版本号

类命名 : 一般命令为 XXOpenHelper, 例如 DBOpenHelper;

版本号 : 在类中定义一个常量, 用于保存版本号;

private static final int DATABASE_VERSION = 1;

(2) 单例模式

单例 : SQLiteOpenHelper 类, 在应用中只保存一个对象即可;

-- 私有, 静态化本类成员变量 : 例如该类类名为 DBOpenHelper, 那么定义一个 DBOpenHelper 的成员变量, 注意将改变量设置成静态变量;

private static DbOpenHelper instance;

-- 私有化构造函数 :  将构造函数设置为私有函数;

	private DbOpenHelper(Context context) {
		super(context, getUserDatabaseName(), null, DATABASE_VERSION);
	}

-- 共有, 静态 方法获取成员变量 : 使用懒汉模式, 如果 本类类型成员变量 为null, 就调用私有的静态构造方法, 如果不为null, 就直接返回 本类类型静态变量;

	public static DbOpenHelper getInstance(Context context) {
		if (instance == null) {
			instance = new DbOpenHelper(context.getApplicationContext());
		}
		return instance;
	}

(3) SQL 语句字段名维护

字段名使用 :

-- SQLiteOpenHelper 中的字段 : 建立数据库需要字段名称;

-- JavaBean 中的字段 : 在代码中经常用到字段名称, 一般规律是 在JavaBean 中的变量名 与 数据库中字段名相同, 字段名在 JavaBean 中需要使用, 用于从 Cursor 中获取对象;

-- Dao 中的字段 : 在插入数据时, 也许要字段名称;

维护字段名称常量 : 个人认为字段名称常量维护在 JavaBean 中最好, 这样就可以将所有的字段名都限制在 JavaBean 类中, 其它位置不用关心字段名称;

(4) SQLiteOpenHelper 代码示例

/**
 * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved.
 *
 * 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.
 */
package com.easemob.chatuidemo.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.easemob.applib.controller.HXSDKHelper;

public class DbOpenHelper extends SQLiteOpenHelper{

	private static final int DATABASE_VERSION = 1;
	private static DbOpenHelper instance;

	private static final String USERNAME_TABLE_CREATE = "CREATE TABLE "
			+ UserDao.TABLE_NAME + " ("
			+ UserDao.COLUMN_NAME_NICK +" TEXT, "
			+ UserDao.COLUMN_NAME_ID + " TEXT PRIMARY KEY);";

	private static final String INIVTE_MESSAGE_TABLE_CREATE = "CREATE TABLE "
			+ InviteMessgeDao.TABLE_NAME + " ("
			+ InviteMessgeDao.COLUMN_NAME_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
			+ InviteMessgeDao.COLUMN_NAME_FROM + " TEXT, "
			+ InviteMessgeDao.COLUMN_NAME_GROUP_ID + " TEXT, "
			+ InviteMessgeDao.COLUMN_NAME_GROUP_Name + " TEXT, "
			+ InviteMessgeDao.COLUMN_NAME_REASON + " TEXT, "
			+ InviteMessgeDao.COLUMN_NAME_STATUS + " INTEGER, "
			+ InviteMessgeDao.COLUMN_NAME_ISINVITEFROMME + " INTEGER, "
			+ InviteMessgeDao.COLUMN_NAME_TIME + " TEXT); ";

	private DbOpenHelper(Context context) {
		super(context, getUserDatabaseName(), null, DATABASE_VERSION);
	}

	public static DbOpenHelper getInstance(Context context) {
		if (instance == null) {
			instance = new DbOpenHelper(context.getApplicationContext());
		}
		return instance;
	}

	private static String getUserDatabaseName() {
        return  HXSDKHelper.getInstance().getHXId() + "_demo.db";
    }

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(USERNAME_TABLE_CREATE);
		db.execSQL(INIVTE_MESSAGE_TABLE_CREATE);

	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

	}

	public void closeDB() {
	    if (instance != null) {
	        try {
	            SQLiteDatabase db = instance.getWritableDatabase();
	            db.close();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	        instance = null;
	    }
	}

}

2. Dao 类规范

该类作用 : 将对数据库增删查改的操作都放在该类中;

(1) 维护 SQLiteOpenHelper 变量

维护变量 : 在 Dao 类中, 维护该变量, 方法中使用 OpenHelper 快速获取数据库;

(2) 在方法中实时获取 SQLiteDatabase 变量

获取数据库对象 : 如果对数据库进行操作时, 需要在方法中根据需求获取 dbHelper.getWritableDatabase() 或者 dbHelper.getReadableDatabase() 数据库对象;

(3) Dao 代码示例

/**
 * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved.
 *
 * 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.
 */
package com.easemob.chatuidemo.db;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;

import com.easemob.chatuidemo.Constant;
import com.easemob.chatuidemo.domain.User;
import com.easemob.util.HanziToPinyin;

public class UserDao {
	public static final String TABLE_NAME = "uers";
	public static final String COLUMN_NAME_ID = "username";
	public static final String COLUMN_NAME_NICK = "nick";
	public static final String COLUMN_NAME_IS_STRANGER = "is_stranger";

	private DbOpenHelper dbHelper;

	public UserDao(Context context) {
		dbHelper = DbOpenHelper.getInstance(context);
	}

	/**
	 * 保存好友list
	 *
	 * @param contactList
	 */
	public void saveContactList(List<User> contactList) {
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		if (db.isOpen()) {
			db.delete(TABLE_NAME, null, null);
			for (User user : contactList) {
				ContentValues values = new ContentValues();
				values.put(COLUMN_NAME_ID, user.getUsername());
				if(user.getNick() != null)
					values.put(COLUMN_NAME_NICK, user.getNick());
				db.replace(TABLE_NAME, null, values);
			}
		}
	}

	/**
	 * 获取好友list
	 *
	 * @return
	 */
	public Map<String, User> getContactList() {
		SQLiteDatabase db = dbHelper.getReadableDatabase();
		Map<String, User> users = new HashMap<String, User>();
		if (db.isOpen()) {
			Cursor cursor = db.rawQuery("select * from " + TABLE_NAME /* + " desc" */, null);
			while (cursor.moveToNext()) {
				String username = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_ID));
				String nick = cursor.getString(cursor.getColumnIndex(COLUMN_NAME_NICK));
				User user = new User();
				user.setUsername(username);
				user.setNick(nick);
				String headerName = null;
				if (!TextUtils.isEmpty(user.getNick())) {
					headerName = user.getNick();
				} else {
					headerName = user.getUsername();
				}

				if (username.equals(Constant.NEW_FRIENDS_USERNAME) || username.equals(Constant.GROUP_USERNAME)) {
					user.setHeader("");
				} else if (Character.isDigit(headerName.charAt(0))) {
					user.setHeader("#");
				} else {
					user.setHeader(HanziToPinyin.getInstance().get(headerName.substring(0, 1))
							.get(0).target.substring(0, 1).toUpperCase());
					char header = user.getHeader().toLowerCase().charAt(0);
					if (header < 'a' || header > 'z') {
						user.setHeader("#");
					}
				}
				users.put(username, user);
			}
			cursor.close();
		}
		return users;
	}

	/**
	 * 删除一个联系人
	 * @param username
	 */
	public void deleteContact(String username){
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		if(db.isOpen()){
			db.delete(TABLE_NAME, COLUMN_NAME_ID + " = ?", new String[]{username});
		}
	}

	/**
	 * 保存一个联系人
	 * @param user
	 */
	public void saveContact(User user){
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put(COLUMN_NAME_ID, user.getUsername());
		if(user.getNick() != null)
			values.put(COLUMN_NAME_NICK, user.getNick());
		if(db.isOpen()){
			db.replace(TABLE_NAME, null, values);
		}
	}
}

.

【Android 应用开发】 Android 相关代码规范 更新中 ...的更多相关文章

  1. 知道创宇爬虫题--代码持续更新中 - littlethunder的专栏 - 博客频道 - CSDN.NET

    知道创宇爬虫题--代码持续更新中 - littlethunder的专栏 - 博客频道 - CSDN.NET undefined 公司介绍 - 数人科技 undefined

  2. android开发常用组件【持续更新中。。。】

    UI相关 图片 Android-Universal-Image-Loader:com.nostra13.universalimageloader:异步加载.缓存.显示图片 ImageLoader:co ...

  3. 新手开发android容易出现的错误(不断更新中...)

    才开始开发android app,因为以前一直是java开发,学习也比较容易. 记录下自己开发过程中出现的一些小问题: 静态变量 在开发中,因为习惯性的问题,经常将一些常用数据(如用户信息等)进行st ...

  4. 码农人生——从未学过Android如何开发Android App 案例讲解-第002期案例

    标题有点晃眼,本次分享是002期博文的实践故事,不会有任何代码.也不会教别人android 如何开发,类似博文已经有大批大批,而且还会有陆陆续续的人写,我写的文章,主要是经验之谈,希望总结出的一些方法 ...

  5. android studio 开发android app 真机调试

    大家都知道开发android app 的时候可以有2种调试方式, 一种是Android Virtual Device(虚拟模拟器) ,另一种就是真机调试. 这里要说的是真机调试的一些安装步骤: 1. ...

  6. Android UI开发第二十八篇——Fragment中使用左右滑动菜单

    Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...

  7. Android混合开发,html5自己主动更新爬过的坑

    如今使用混合开发的公司越来越多,尽管出现了一些新技术,比方Facebook的react native.阿里的weex,但依旧阻挡不了一些公司採用h5的决心.当然,这也是从多方面考虑的选择. 在三年前就 ...

  8. Android Studio开发Android问题集【持续更新】

    问题一:emulator:ERROR:This AVD's configuration is missing a kernel file!! 答:打开Android SDK Manager,查看相应的 ...

  9. 用Android Studio 开发Android应用

    目前AndroidStudio已经到了1.2版本了,我用了下,觉得还蛮好的,有些自动生成的资源,它会自动帮你管理.下面开始列一下,我的开发环境搭配.在开始前,你得有个VPN,可者代理.嗯.不然你下不了 ...

随机推荐

  1. tensorflow deepmath:基于深度学习的自动化数学定理证明

    Deepmath Deepmath项目旨在改进使用深度学习和其他机器学习技术的自动化定理证明. Deepmath是Google研究与几所大学之间的合作. 免责声明: 该存储库中的源代码不是Google ...

  2. Jenkins简明入门(二) -- 利用Jenkins完成Python程序的build、test、deployment

    大家可能还没搞清楚,Jenkins到底能做什么? 本节内容利用Jenkins完成python程序的build.test.deployment,让大家对Jenkins能做的事情有一个直观的了解. 本节内 ...

  3. 基于GCC的openMP学习与测试

    (一).openMP简述 Open Multiprocessing (OpenMP) 框架是一种功能极为强大的规范,可以帮助您利用 C.C++ 和 Fortran 应用程序中的多个核心带来的好处,是基 ...

  4. python3全栈开发-多进程的守护进程、进程同步、生产者消费者模式(重点)

    一.守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes a ...

  5. h5 网页版的微博微信QQ登录

    一:微博 1,先说微博吧,首先你的去http://open.weibo.com/wiki/先注册账号,通过验证审核.然后的创建网页应用.微博审核不通过的原因就是域名和网站地址,一定要按实际写的.一定要 ...

  6. 2018春招实习笔试面试总结(PHP)

    博主双非渣本计算机软件大三狗一枚,眼看着春招就要结束了,现将自己所经历的的整个春招做一个个人总结. 首先就是关于投递计划,博主自己整理了一份各大公司的春招信息,包括网申地址,开始时间,结束时间,以及自 ...

  7. Vue实践经验

    多考虑应变 如果模版中绑定了 obj.xx 时,需要注意 obj 是否是异步数据,默认值是否为 null.安全起见,可在组件最外层加 v-if 判断. <template> <div ...

  8. Red Hat Enterprise Linux7的安装与oracle 12c的安装

    Red Hat Enterprise Linux7的安装与oracle 12c的安装 本文档中用到的所有参数均位于文末附录 Red Hat Enterprise Linux7的安装 新建完虚拟机后,挂 ...

  9. Microsoft Visual Studio 2017 编译最新版 libuv 1.x

    步骤很简单 1 下载最新版的 libuv(地址:https://github.com/libuv 2 安装Git,Python 2.7 ,cmake(这里使用的是 3.11.0-win64-x64 版 ...

  10. Page Object设计模式实践

    Page Object模式是使用Selenium的广大同行最为公认的一种设计模式.在设计测试时,把元素和方法按照页面抽象出来,分离成一定的对象,然后再进行组织. Page Object模式,创建一个对 ...