.

简介 : 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. JSSDK实现微信自定义分享---java 后端获取签名信息

    一.首先说下关于微信Access_token的问题,微信Access_token分为2中: 1.授权token获取方式: 这种token需要code值(如何获取code值查看官方文档) "h ...

  2. jQuery extend 方法使用 (转)

    方法介绍 jQuery 的 API 手册中,extend 方法挂载在 jQuery 和 jQuery.fn 两个不同的对象上,但在 jQuery 内部代码实现的是相同的,只是功能各不相同. 先看看官方 ...

  3. SpringMVC 教程 - URI 链接

    原文链接:https://www.codemore.top/cates/Backend/post/2018-04-22/spring-mvc-uri-links 这一节主要讲的是Spring Fram ...

  4. mysql insert插入时实现如果数据表中主键重复则更新,没有重复则插入的四种方法

    [CSDN下载] Powerdesigner 设计主键code不能重复等问题 [CSDN博客] Oracle中用一个序列给两个表创建主键自增功能的后果 [CSDN博客] MySQL自增主键删除后重复问 ...

  5. Uncaught RangeError: Maximum call stack size exceeded-栈溢出

    在看函数的arguments对象的时候,用了arguments.callee写了一个递归. 当执行函数func(99999)时候,直接报错了,一看,原来栈溢出了. 当执行递归运算的时候,忘记加点判断条 ...

  6. PHP 字符串变量

    PHP 字符串变量 字符串变量用于存储并处理文本. PHP 中的字符串变量 字符串变量用于包含有字符的值. 在创建字符串之后,我们就可以对它进行操作了.您可以直接在函数中使用字符串,或者把它存储在变量 ...

  7. Docker常见仓库MySQL

    MySQL 基本信息 MySQL 是开源的关系数据库实现. 该仓库提供了 MySQL 各个版本的镜像,包括 5.6 系列.5.7 系列等. 使用方法 默认会在 3306 端口启动数据库. $ sudo ...

  8. [ExtJS6学习笔记]Ext JS6主题系列 (Classic工具包)

    本文作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/50186709 翻译来源:http://docs.sencha.co ...

  9. Scala: 简介和安装

    http://blog.csdn.net/pipisorry/article/details/52902117 Note: lz只是稍微学学,能看懂就行,不深入.适合scala小白. Scala简介 ...

  10. Xcode 8新功能介绍

    概述 Xcode 8正式版在9月13日已经推送给开发者下载,下载之后就出现了很多编译错误,之前的插件也不能用了,但是发现Xcode8把好多不错的插件功能整合到自身了,感觉这点也挺不错. 结合自己遇到的 ...