在实际项目中,合理的项目结构是非常重要的,下面讲一下一般的结构形式。
各种包和类的作用:
activity: 活动相关代码
db: 数据库操作相关代码
model: 模型,简单实体类代码
receiver: 广播接收器相关代码
service: 服务相关代码
util: 工具相关代码
1、db中如何合理设计代码结构?
RealProjectOpenHelper类,继承自SQLiteOpenHelper类,用于创建数据库和各种表。
RealProjectDB类,最好是单例模式,各种操作数据库的函数,如增删改查功能。借助于RealProjectOpenHelper类获取数据库操作句柄。
public class RealProjectOpenHelper extends SQLiteOpenHelper {
//创建三个数据表的语句
public static final String CREATE_PROVINCE = "create table Province(id integer primary key autoincrement, province_name text, province_code text)";
public static final String CREATE_CITY = "create table City(id integer primary key autoincrement, city_name text, city_code text, province_id integer)";
public static final String CREATE_COUNTY = "create table County(id integer primary key autoincrement, county_name text, county_code text, city_id integer)";
//构造函数
public RealProjectOpenHelper(Context context, String name, CursorFactory factory, int version){
super(context, name, factory, version);
}
//数据库创建
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_PROVINCE);
db.execSQL(CREATE_CITY);
db.execSQL(CREATE_COUNTY);
}
//涉及到更新,此处的更新还是比较弱 参考之前的博文 知道如何更好的控制更新内容
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Province");
db.execSQL("drop table if exists City");
db.execSQL("drop table if exists County");
onCreate(db);
}
}
以及:
public class RealProjectDB {
//数据库名字
public static final String DB_NAME = "cool_weather";
//数据库版本
public static final int VERSION = 1;
//单例模式使用
private static RealProjectDB realprojectDB;
private SQLiteDatabase db;
private RealProjectDB(Context context){
//创建数据库 获取数据库操作句柄 这里是关键 为后续的对数据库的操作提供保障
RealProjectOpenHelper rpHelper = new RealProjectOpenHelper(context, DB_NAME, null, VERSION);
db = rpHelper.getWritableDatabase();
}
//线程安全的创建类实例
public static RealProjectDB getInstance(Context context){
if(realprojectDB == null) { //(1)
//只有第一次才彻底执行这里的代码
synchronized(RealProjectDB.class){
//再检查一次
if(realprojectDB == null)
realprojectDB = new RealProjectDB(context);
}
}
return realprojectDB;
}
/**
* 保存省份信息
* @param p
*/
public void saveProvince(Province p){
if(p != null){
ContentValues values = new ContentValues();
values.put("province_name", p.getProvinceName());
values.put("province_code", p.getProvinceCode());
db.insert("Province", null, values);
}
}
/**
* 获取所有省份信息
* @return
*/
public List<Province> loadProvinces(){
List<Province> list = new ArrayList<Province>();
//查询数据
Cursor cursor = db.query("Province", null, null, null, null, null, null);
if(cursor.moveToFirst()){
do{
Province p = new Province();
p.setId(cursor.getInt(cursor.getColumnIndex("id")));
p.setProvinceName(cursor.getString(cursor.getColumnIndex("province_name")));
p.setProvinceCode(cursor.getString(cursor.getColumnIndex("province_code")));
list.add(p);
}while(cursor.moveToNext());
}
return list;
}
//还是保存城市乡村信息和获取城市乡村信息 不再一一列出
}
2、有很多操作是需要访问服务器获取返回信息,此时就设计通用的类来做这件事情。
可以参考代码如下:
/**
* 与服务器交互类
* @author Administrator
*
*/
public class HttpUtil {
/**
* 向服务器发送请求方法
* @param address
* @param listener
*/
public static void sendHttpRequest(final String address, final HttpCallbackListener listener){
new Thread(new Runnable() {
public void run() {
HttpURLConnection connection = null;
try{
//建立连接
URL url = new URL(address);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
//获取输入流
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
//获取返回的内容 通过StringBuilder进行拼接
StringBuilder response = new StringBuilder();
String line;
while((line = reader.readLine()) != null){
response.append(line);
}
if(listener != null){
//回调onFinish方法
listener.onFinish(response.toString());
}
}catch(Exception e){
if(listener != null){
//回调onError方法
listener.onError(e);
}
}finally{
connection.disconnect();
}
}
}).start();
}
}
这个方法中用到了一个接口参数,该接口很简单:
/**
* 回调接口
* @author Administrator
*
*/
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
个人理解:这个方法非常牛逼和通用,根据传递的地址获取到服务器端返回的数据,然后调用接口中的方法,这个时候就非常的灵活了,因为不同功能点对于该接口的实现方法不同,比如,在下面的应用中,可以如是调用代码:
//从服务器获取数据
private void queryFromServer(final String code, final String type){
String address;
if(!TextUtils.isEmpty(code)){
address = "http://...."; //根据不同的code,设置不同的服务器地址
}else{
address = "";
}
//加载的时候,展示进度条
showProgressDialog();
//在此处确定地址,然后对于返回的数据编写回调函数
<span style="color:#ff0000;">HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {</span>
@Override
<span style="color:#ff0000;">public void onFinish(String response)</span> {
boolean result = false;
if("province".equals(type)){
result = Utility.handleProvinceResponse(db, response);
}
//去过是其他的,调用其他方法
//如果返回数据处理成功
if(result){
<span style="color:#ff0000;">//回到主线程中
runOnUiThread(new Runnable() {</span>
@Override
public void run() {
closeProgressDialog();
if("province".equals(type)){
queryProvinces();
}
//如果是其他的,获取城市或者县城数据。
}
});
}
}
@Override
<span style="color:#ff0000;">public void onError(Exception e) {</span>
runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(ChooseAreaActivity.this, "加载失败", Toast.LENGTH_SHORT).show();
}
});
}
});
}
3、数据的存储思路
如果是一些长期需要用到的数据,比如所有省份,城市信息等,那么可以存到本地数据库中,在获取数据的时候先从本地数据库获取,如果没有,那么从服务器端获取,对于返回的数据进行处理,处理的过程中存入到数据库中。如果是一些临时信息,思路是一样的,但是可以先存储在SharedPreferences中。
另外,还有一些变量用于判断某些事情发生或者没有发生,根据这些变量来做进一步的操作。此时也可以通过SharedPreferences来存储。
4、如何实现定时任务?
可以在后台启动服务,然后通过定时器启动接收器,在接收器中重新开启服务,就是这种周而复始的搞下去。就达到了定时任务的效果。
在服务中,代码核心如下:
public class AutoUpdateService extends Service {
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public int onStartCommand(Intent intent, int flags, int startId){
//开启子线程调用定时任务
new Thread(new Runnable() {
@Override
public void run() {
doSomething();
}
}).start();
//获取广播
AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
int anHour = 8 * 60 * 60 * 1000;
long triggerAtTime = SystemClock.elapsedRealtime()+anHour;
Intent i = new Intent(this,AutoUpdateReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
//定时操作
public void doSomething(){}
}
接收器代码如下:
public class AutoUpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
Intent i = new Intent(arg0,AutoUpdateService.class);
arg0.startService(i);
}
}