在實際項目中,合理的項目結構是非常重要的,下面講一下一般的結構形式。
各種包和類的作用:
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);
}
}