书签的功能已经完成了,那么现在开始就是历史的功能模块。
因为为了方便于数据的管理,所以在原有的书签管理的基础上,进行了相应的修改,通过这个修改,可以使得我们能够同时管理书签和历史。
自然还是数据管理的接口的修改:
package com.example.database;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public interface IDatabase {
/**
* 增加
* @param sqLiteDatabase 数据库
* @param tableName 表
* @param name 名
* @param url 地址
* @param date 日期
* */
public boolean add(SQLiteDatabase sqLiteDatabase, String tableName,String name, String url,long date);
/**
* 删除
* @param sqLiteDatabase 数据库
* @param tableName 表
* @param id 书签ID
* */
public boolean delete(SQLiteDatabase sqLiteDatabase, String tableName,String id);
/**
* 删除所有
* @param sqLiteDatabase 数据库
* @param tableName 表
* */
public boolean deleteAll(SQLiteDatabase sqLiteDatabase, StringtableName);
/**
* 修改
* @param sqLiteDatabase 数据库
* @param tableName 表
* @param id 修改的ID
* @param name 修改后的名
* @param url 修改后的地址
* */
public boolean modify(SQLiteDatabase sqLiteDatabase, String tableName,String id, String name, String url);
/**
* 获取所有
* @param sqLiteDatabase 数据库
* @param tableName 表
* @return Cursor
* */
public Cursor getAll(SQLiteDatabase sqLiteDatabase, StringtableName);
/**
* 查询某个书签是否存在,即查询url是否重复
* @param tableName 表
* @param sqLiteDatabase 数据库
* @param url 地址
* */
public boolean multiply(SQLiteDatabase sqLiteDatabase, StringtableName, String url);
/**
* 开始事务
* @param readOnly是否只读
* @param callback函数回调
* */
void transactionAround(boolean readOnly, CallBack callback);
}
代码片段10.2.19 修改后的数据接口
注意,我们可以看到,我在这里添加了一个String的参数,这个参数的形参名为tableName,即是用来分别是对书签还是历史进行操作。
至于数据管理的实现,基本没有什么变更,将原本固定的数据表改为变量tableName即可。不过,因为数据的表示不一样,历史相对于书签来说多了个字段就是日期,历史可以通过这个日期来划分组,不过现阶段对这个不做处理。
@Override
public boolean add(SQLiteDatabase sqLiteDatabase, String tableName,String name, String url,long date) throws SQLException{
ContentValues values = new ContentValues();
values.put("name", name);
values.put("url", url);
if(tableName.equals(FavAndHisManager.TABEL_NAME_Favorite)){
Log.d(DEG_TAG,"name:"+name+",url:"+url);
}else{
values.put("date", date);
Log.d(DEG_TAG,"name:"+name+",url:"+url+",date:"+date);
}
long id = sqLiteDatabase.insert(tableName,null, values);
if(id!=-1){
return true;
}else{
return false;
}
}
//新增的方法,用来清空历史
@Override
public boolean deleteAll(SQLiteDatabase sqLiteDatabase, StringtableName) {
Log.d(DEG_TAG,"deleteAll");
int number = sqLiteDatabase.delete(tableName,null, null);
Log.d(DEG_TAG,"deleteAll_result:"+number);
if(number!=0){
return true;
}else{
return false;
}
}
@Override
public Cursor getAll(SQLiteDatabase sqLiteDatabase, StringtableName) {
String[] returnColmuns = null;
if(tableName.equals(FavAndHisManager.TABEL_NAME_Favorite)){
returnColmuns = new String[]{
"id as_id",
"name",
"url"
};
}else{
returnColmuns = new String[]{
"id as_id",
"name",
"url",
"date"
};
}
Cursor result = sqLiteDatabase.query(tableName, returnColmuns,null, null,null, null,null);
while(result.moveToNext()){
String id = String.valueOf(result.getInt(result.getColumnIndex("_id")));
String name = result.getString(result.getColumnIndex("name"));
String url = result.getString(result.getColumnIndex("url"));
if(tableName.equals(FavAndHisManager.TABEL_NAME_Favorite)){
Log.d(DEG_TAG,"id:"+id+",name:"+name+",url:"+url);
}else{
String date = String.valueOf(result.getLong(result.getColumnIndex("date")));
Log.d(DEG_TAG,"id:"+id+",name:"+name+",url:"+url+",date:"+date);
}
}
return result;
}
代码片段10.2.20 需要修改的方法
这里的新增的方法有个清空历史,因为我们在操作浏览器的时候,往往会清空一些历史数据,来释放空间。
而修改的两个方法前者是因为插入的时候列不同需要处理,后者是因为返回的时候历史界面需要额外的有一个date日期列。
处理好了这个,该是处理历史事务的时候了,其实也就是调用上述的数据管理。
/**
* 增加历史
* @param name 历史名
* @param url 历史地址
* @param date 存放历史时间
* */
public boolean addHistory(final String name,final String url, finallong date) {
flag = false;
this.database.transactionAround(false,new CallBack() {
@Override
public voiddoSomething(SQLiteDatabase sqLiteDatabase) {
//历史可重复,不重复的为id和date
flag = database.add(sqLiteDatabase, TABEL_NAME_History, name, url, date);
}
});
Log.d(DEG_TAG,"result:"+flag);
return flag;
}
/**
* 删除历史
* @param id 历史ID
* */
public boolean deleteHistory(final String id) {
flag = false;
this.database.transactionAround(false,new CallBack() {
@Override
public void doSomething(SQLiteDatabase sqLiteDatabase) {
flag = database.delete(sqLiteDatabase, TABEL_NAME_History, id);
}
});
return flag;
}
/**
* 删除所有历史
* */
public boolean deleteAllHistory(){
flag = false;
this.database.transactionAround(false,new CallBack() {
@Override
public void doSomething(SQLiteDatabase sqLiteDatabase) {
flag = database.deleteAll(sqLiteDatabase, TABEL_NAME_History);
}
});
return flag;
}
/**
* 获取所有历史
* @return Cursor
* */
public Cursor getAllHistories() {
this.database.transactionAround(true,new CallBack() {
@Override
public void doSomething(SQLiteDatabase sqLiteDatabase) {
resultMap = database.getAll(sqLiteDatabase, TABEL_NAME_History);
}
});
return resultMap;
代码片段10.2.21 新增加历史的事务管理
因为数据库都是同一个,所以,我尽量将这个事务的管理整合到了书签事务管理的类中,重新命名这个类为FavAndHisManager。
历史事务管理已经完成,现在就开始进行相关的页面编辑。页面的编辑跟书签的没啥区别,因为我现在并没有以时间进行划分。我们可以先看看效果,也就是书签的编辑效果,就是更改了字体的显示。
图10.2.8 编辑菜单长按预览
至于页面的ListView,这个跟书签的ListView保持一致。所以我在这里就不展示了。
下面是历史的ListView的初始化数据的代码:
/**
* 初始化ListView中History的数据
* */
@SuppressWarnings("deprecation")
private void initDataHistory() {
//获取书签管理
this.favAndHisManager =new FavAndHisManager(this);
this.favAndHisCursor =this.favAndHisManager.getAllHistories();
this.favAndHisAdapter =new SimpleCursorAdapter(getApplicationContext(),
R.layout.list_item,this.favAndHisCursor,
new String[]{"_id","name","url","date"},
new int[]{R.id.item_id, R.id.item_name,R.id.item_url,R.id.item_date});
this.historyContent.setAdapter(this.favAndHisAdapter);
}
代码片段10.2.22 历史ListView的初始化
长按单击事件基本与书签的相同,只不过是布局的不同以及取出来的组件不同:
itemLongClickedPopWindow = new ItemLongClickedPopWindow(FavAndHisActivity.this,
ItemLongClickedPopWindow.HISTORY_ITEM_POPUPWINDOW, 200, 200);
itemLongClickedPopWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.favandhis_activity));
itemLongClickedPopWindow.showAsDropDown(view, view.getWidth()/2,-view.getHeight()/2);
TextView deleteHistory = (TextView) itemLongClickedPopWindow.getView(R.id.item_longclicked_deleteHistory);
TextView deleteAllHistories = (TextView) itemLongClickedPopWindow.getView(R.id.item_longclicked_deleteAllHistories);
ItemClickedListener itemClickedListener = newItemClickedListener(view);
deleteHistory.setOnClickListener(itemClickedListener);
deleteAllHistories.setOnClickListener(itemClickedListener);
代码片段10.2.23 popupwindow的历史弹出菜单
单击事件如下:
Intent intent = new Intent();
intent.putExtra("url",((TextView) arg1.findViewById(R.id.item_url)).getText().toString());
setResult(0, intent);
finish();
代码片段10.2.24 ListView的条目单击事件
可以看到这个跟书签的条目单击事件一模一样。另外需要注意的是,如果我们没有点击任何单击事件,而是直接返回,会发现出现NULLPOINTER的空指针错误,这个就是因为没有设置默认的返回码的缘故。没有任何的返回码,自然在父Actiivty的onActivity的方法中接受返回码的时候会报出异常。
解决这个问题也很简单,我们只需要在onCreate函数中设置如下语句即可:
//添加默认返回值
setResult(-1);
代码片段10.2.25 设置默认返回值
当然,还需要在接受返回值的那里进行处理:
@Override
protected void onActivityResult(int requestCode,int resultCode, Intent data) {
switch (resultCode) {
case -1:
//不做任何处理
break;
case 0:
webHolder.loadUrl(data.getStringExtra("url"));
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
这样空指针的错误就解决了。
那么还有一个最重要的问题,在什么时候记录历史呢?我认为,在每个页面加载完成的时候,就可以将这次访问加入,但因为是历史记录的关系,并不需要进行重复性判断(也许需要根据时间来判断,相同的时间前提下不能进行重复添加,不过这个暂时不进行考虑)。
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
webUrlLayoutInput.setVisibility(View.GONE);
webUrlLayoutShow.setVisibility(View.GONE);
inputShow = false;
webUrlStr.setText(url);
changeStatueOfWebToolsButton();
//添加历史
String date = new SimpleDateFormat("yyyyMMdd", Locale.CHINA).format(newDate()).toString();
favAndHisManager.addHistory(title, url, Long.parseLong(date));
}
代码片段10.2.27 添加历史记录在每次访问后
至此,历史的功能完成。
案例:
AndroidStudy_web_V2.1_bydddd牛仔