概述:這個小程序,你講學習到基本控件(Button,Listview,Gridview,TextView等)的使用技巧,AssetManager類的使用,XML數據的解析方式,BaseAdapter,幾種佈局的使用,Sqlite的使用等等。java
1、簡單需求設計android
左右分欄的形式,左欄爲一級菜單,右欄爲二級菜單。經過點擊一級菜單列表在右欄現實二級菜單,在二級菜單中點擊相關選項進入網頁。一級菜單,二級菜單均有編輯功能,或增,或刪,或改。爲提升用戶體驗,將二級菜單的顯示模式定爲兩種,一爲列表模式,二爲表格方式。將在一二級菜單中添加列表頭或者列表尾進行添加操做。爲更迎合用戶的偏好使用,將設計將用戶本次的設置保存到系統中,方便用戶下次使用。提供恢復默認設置的選項,即將數據初始爲原始狀態。sql
2、技術實現可能性預見數據庫
就我本人而言,作過的項目很少,那麼首先我會作一個簡單的技術考察,或作一些小Demo。那麼這裏,我就以個人方式來闡述下這個項目須要用到的一個技術。首先,必然要用到xml的解析,那麼xml有三種解析方式(這裏只作簡單說明):(1)DOM解析,Dom解析器會在解析xml文檔是,把文檔中全部的元素按照其出現的層次關係解析成一個個Node節點對象,Node節點對象提供了相應的方法去獲取父節點和子節點,那麼咱們能夠經過這些方法讀取整個xml並對其操做,它的缺點是一次性加載整個xml文件,那麼對於移動設備,內存是很是寶貴的,因此咱們不用它。(2)SAX解析,SAX解析容許在讀取文檔的時候,即對文檔進行處理,而沒必要等到整個文檔撞在完畢纔對其進行操做。它是基於事件驅動的(3)PULL方式,和SAX同樣也是基於事件驅動的,使用起來也比較簡單,那麼咱們就用Pull。Activity之間的數據傳遞和保存,這個是徹底能夠處理的。調用相應的方法,或者將須要存儲的數據保存到sqlite就能夠了。這些開始開代碼吧。功能的實現,基本沒有什麼問題了,那麼下一步咱們就來佈局下界面。小程序
3、界面佈局的設計數組
根據以前的需求設計,大體將界面佈局定爲如下樣式。瀏覽器
4、項目關鍵技術點講解及代碼展現緩存
一、在Eclipse中新建工程,SurfingDemo,程序包名:org.winplus.sufingapp
二、按照個人編碼習慣,我喜歡先將UI弄好,而後直接取數據,並將其顯示。那麼根據上圖UI的設計草圖,咱們能夠將幾個主要的佈局進行排版設計。代碼以下:ide
surfing.xml(佈局描述文件)
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<!-- 左邊的操做佈局即,一級菜單的顯示-->
<LinearLayout
android:id="@+id/layout_left"
android:layout_width="200px"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/left_msg"
android:layout_width="wrap_content"
android:layout_height="40px"
android:text="@string/txt_left_msg" />
<ListView
android:id="@+id/list_first_classify"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- 右邊佈局,即二級菜單的顯示-->
<LinearLayout
android:id="@+id/layout_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
<!-- 右邊操做佈局,顯示模式的設置-->
<LinearLayout
android:id="@+id/layout_right_oper"
android:layout_width="fill_parent"
android:layout_height="40px"
android:orientation="horizontal" >
<TextView
android:id="@+id/right_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/txt_right_msg" />
<ImageButton
android:id="@+id/display_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:src="@drawable/ic_display_list"/>
<ImageButton
android:id="@+id/display_grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00000000"
android:src="@drawable/ic_display_grid"/>
</LinearLayout>
<!-- 二級菜單的主顯示-->
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" >
<ListView
android:id="@+id/second_classify_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<GridView
android:id="@+id/second_classify_grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:columnWidth="80dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
</FrameLayout>
</LinearLayout>
</LinearLayout>
</span></span>
界面佈局完成了,下一步咱們先將一些數據整理出來,我把數據整理成xml文檔,供程序初始化使用,數據文檔以下:
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;"><?xml version="1.0" encoding="utf-8"?>
<classify>
<!--視頻(奇異高清,QQ視頻,優酷,土豆,新浪視頻)-->
<subclassify name="視頻" icon="img/video.png">
<url_data id="1" name="奇異高清" icon="img/vqiyi.png" url="http://www.qiyi.com" describe=""/>
<url_data id="1" name="QQ視頻" icon="img/vqq.png" url="http://www.v.qq.com" describe=""/>
<url_data id="1" name="優酷" icon="img/vyouku.png" url="http://www.youku.com" describe=""/>
<url_data id="1" name="土豆" icon="img/vtudou.png" url="http://www.tudou.com" describe=""/>
<url_data id="1" name="新浪視頻" icon="img/vsina.png" url="http://video.sina.com.cn/" describe=""/>
</subclassify>
<!-- 新聞(新浪新聞,新華網,騰訊新聞,網易新聞,中國新聞網) -->
<subclassify name ="新聞" icon="img/news.png">
<url_data id="2" name="新浪新聞" icon="img/nsina.png" url="http://news.sina.com.cn/" describe=""/>
<url_data id="2" name="新華網" icon="img/nxinhua.png" url="http://www.xinhuanet.com/" describe=""/>
<url_data id="2" name="騰訊新聞" icon="img/nqq.png" url="http://news.qq.com/" describe=""/>
<url_data id="2" name="網易新聞" icon="img/n163.png" url="http://news.163.com/" describe=""/>
<url_data id="2" name="中國新聞網" icon="img/nchina.png" url="http://www.chinanews.com/" describe=""/>
</subclassify>
<!-- 軍事(中華軍事,鐵血網,環球軍事,新浪軍事,東方軍事)-->
<subclassify name ="軍事" icon="img/war.png">
<url_data id="3" name="中華軍事" icon="img/wchina.png" url="http://military.china.com/zh_cn/" describe=""/>
<url_data id="3" name="鐵血網" icon="img/wtiexue.png" url="http://www.tiexue.net/" describe=""/>
<url_data id="3" name="環球軍事" icon="img/whuanqiu.png" url="http://mil.huanqiu.com/" describe=""/>
<url_data id="3" name="新浪軍事" icon="img/wsina.png" url="http://mil.news.sina.com.cn/" describe=""/>
<url_data id="3" name="東方軍事" icon="img/weast.png" url="http://mil.eastday.com/" describe=""/>
</subclassify>
</classify>
</span></span>
固然還有圖片資源,資源圖片我就不提供了。對此項目感興趣的就本身PS或者直接到網站去截圖吧。
根據上面的數據顯示,我定義了兩個bean,來保存數據。
UrlClassify.java(用於保存subclassify的Name和Icon)
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">package org.winplus.sufing;
public class UrlClassify {
private int id;
private String name;
private byte[] icon;
//getter setter method
}
</span></span>
UrlInfo.java(用於保存url_data標籤的相關屬性)
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">public class UrlInfo {
private int fid;
private String name;
private byte[] icon;
private String url;
private String describe;
//getter setter method
}
</span></span>
OK,實體Bean定義好了,如今能夠解析xml數據了。上面的xml數據被我定義爲urldata.xml並將其放在Android工程目錄assets下,經過AssetManager管理。要解析xml數據,就要用到上面提到的3中方法,這裏咱們使用Pull(你可使用以上任意一種處理方式)。爲了程序更有擴展性,咱們將處理xml數據的方法寫成一個接口,而後再經過實現接口去真正解析xml數據。直接看代碼。
接口類很簡單,就定義了一個接口:
IxmlParseService.java(解析XMl數據的接口類)
<span style="font-family: 'Microsoft YaHei'; font-weight: normal; "><span style="font-size:16px;">public interface IXmlParseService {
public Map<UrlClassify,ArrayList<UrlInfo>> getUrlsByParseXml(InputStream is) throws Exception;
}
PullParseService.java(實現解析數據的接口類),如下是主要方法
public Map<UrlClassify,ArrayList<UrlInfo>> getUrlsByParseXml(InputStream is)
throws Exception {
Map<UrlClassify,ArrayList<UrlInfo>> map = null; // 定義一個Map用於保存一級菜單和二級菜單數據(根據xml的結構,將一級菜單UrlClassify做爲鍵值保存在Map中,UrlInfo數字列表保存爲Map的值)
ArrayList<UrlInfo> classifies = null; // 定義保存UrlInfo的數組列表。
UrlClassify urlClassify = null;
UrlInfo urlInfo = null;
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); // 獲得一個PullParserFactory實例,用於建立Pull解析器
XmlPullParser parser = factory.newPullParser(); // 建立解析器
parser.setInput(is,"UTF-8"); // 設置解析格式
int type = parser.getEventType(); // 獲得當前事件的類型(文檔開始、結束,標籤開始結束)
byte[] by = null; // 圖片文件
while (type!=XmlPullParser.END_DOCUMENT) { // 當前事件類型爲文檔結束再也不循環
String typeName = parser.getName();
if (type==XmlPullParser.START_TAG) {
if ("classify".equals(typeName)) {
map = new LinkedHashMap<UrlClassify, ArrayList<UrlInfo>>();
}else if ("subclassify".equals(typeName)) {
by = imgFile2Byte(parser.getAttributeValue(1));
urlClassify = new UrlClassify(parser.getAttributeValue(0), by);
classifies = new ArrayList<UrlInfo>();
}else if("url_data".equals(typeName)){
by = imgFile2Byte(parser.getAttributeValue(2));
int fid = Integer.valueOf( parser.getAttributeValue(0));
String name = parser.getAttributeValue(1);
String url = parser.getAttributeValue(3);
String describe = parser.getAttributeValue(4);
urlInfo = new UrlInfo(fid,name,by,url,describe);
classifies.add(urlInfo);
}
}else if (type == XmlPullParser.END_TAG) {
map.put(urlClassify, classifies);
}
type = parser.next();
}
return map;
}
</span></span>
解析xml的方法搞定,解析出來的數據是顯示在listview中的,咱們經過listview.setAdapter()方法設置數據,因而就須要先定義一個繼承Adapter的類。在定義Adapter類以前,咱們又有必要設計好在listview顯示的佈局描述文件(固然你也可使用系統自帶的佈局)。在這個項目中,我並不打算花太多的精力去作界面上的美化工做,只實現基本的功能,或者演示基本的使用狀況。我將一級菜單數據顯示的UI定義成以下的樣式。
根據上面的顯示,定義了以下文件first_classify_adapter.xml(一級菜單Adapter佈局文件)
<span style="font-family: 'Microsoft YaHei'; font-weight: normal; "><span style="font-size:16px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<ImageView
android:id="@+id/edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:src="@drawable/ic_edit" />
<ImageView
android:id="@+id/img"
android:layout_width="80dip"
android:layout_height="40dip" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</span></span>
細心的讀者會注意到,上面的佈局文件中有一個隱藏的「編輯按鈕」圖標,非編輯狀況下這個圖標時隱藏不顯示的,只有在編輯模式下才將圖標顯示。這個編輯功能應該是這樣,在編輯模式下,點擊編輯圖片按鈕,而後跳轉到相應的Activity中,編輯當前項,而後將編輯過的項更新到數據庫或者文件中,而後再返回當前的界面。爲了減小對數據庫的操做,我並無打算更新數據後,再查一次數據庫中的數據,而後在顯示在界面。並且請注意:這個描述文件是在Adapter中使用的,咱們都知道諸如startActivityForResult,startActivity(intent)是Activity中的方法,但在Adapter中怎麼使用呢?沒辦法,我只有將SurfingDemoActivity經過構造函數傳遞到Adapter中,來實現引用,下面是關鍵代碼。
FirstClassifyAdapter.java(一級列表的Adapter)
<span style="font-size:16px;">/**
* 如下的關於顯示的處理方式是googleIO大會提出的優化方式之一,推薦使用這種方式!
*/
@Override
public View getView(int position, View convertView, ViewGroupparent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.first_classify_adapter, null);
holder.img = (ImageView) convertView.findViewById(R.id.img);
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.imgEdit = (ImageView) convertView.findViewById(R.id.edit);
convertView.setTag(holder); // 這點很關鍵,當初我就是忘記了設置Tag,致使整個列表值緩存了一屏數據,當數據超過一屏數據時就重複顯示了。在網上也看到不少哥們關於重複顯示的迷惑。
} else {
holder = (ViewHolder) convertView.getTag();
}
final FirstClassify classify = mClassifies.get(position);
byte[] by = classify.getIcon();
if (by != null) {
ByteArrayInputStream bais = new ByteArrayInputStream(classify.getIcon());
holder.img.setImageDrawable(Drawable.createFromStream(bais,String.valueOf(position)));
} else {
holder.img.setBackgroundResource(R.drawable.ic_launcher);
}
holder.text.setText(classify.getName());
if (isEdit) {
holder.imgEdit.setVisibility(View.VISIBLE);
holder.imgEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "classify.getName=" + classify.getName());
Intent intent = new Intent();
intent.setClassName("org.winplus.sufing","org.winplus.sufing.FirstClassifyEditActivity");
Bundle bundle = new Bundle();
bundle.putSerializable("classify", classify);
intent.putExtras(bundle);
mActivity.startActivityForResult(intent,
Constant.REQUEST_EDIT_CLASSIFY);
}
});
} else {
holder.imgEdit.setVisibility(View.GONE);
}
return convertView;
}
class ViewHolder {
public ImageView img;
public TextView text;
public ImageView imgEdit;
}</span>
固然還有二級分類的顯示Adapter,二級分類顯示又有兩種(ListView,GridView)顯示方式,這裏就省略了,實現方式和上面FirstClassifyAdapter類同樣。
完成了上面的工做以後,咱們終於能夠將數據顯示到界面上了!在自動生成的類SurfingDemoActivity中,先定義並初始化xml文件中相關的各個組件。從上面的需求以及surfing.xml描述文件中咱們看到了,這個類中須要實現幾個必須得事件監聽類。固然也能夠不經過實現的方式,直接重寫控件的方法,這樣若是控件多,實現起來就比較冗餘,我的習慣吧。這個類中咱們經過實現OnClickListener,OnItemClickListener,OnItemLongClickListener三個類來處理ListView的點擊、長按,以及按鈕的點擊事件。
這個類中,加載數據的流程是這樣,先判斷是不是第一次運行,若是是第一次運行則解析xml數據,並將其保存到數據庫,而後再顯示在界面。若是非第一次運行,則直接查詢數據庫中的數據,而後顯示。SurfingDemoActivity.java這個類中關鍵代碼以下。
SurfingDemoActivity.java(代碼中都有註釋,這裏就不說了。)
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">/**
* 初始化數據(判斷程序是不是第一次運行,若是是第一次運行則將數據加載到數據庫中),關因而否第一次運行的判斷,我是直接經過SharedPreferences,將數據保存在共享文件中,若是讀取到的值爲false表示第一次運行。第一次運行後設置共享文件中的值爲true,便可實現。這個好像沒有什麼好的實現方式吧?
*/
private void init() {
if (!utils.isFirstRunning()) {
map = new LinkedHashMap<FirstClassify, ArrayList<UrlInfo>>();
// TODO: 加線程
initXML();
initData();
utils.setFirstRuslt();
}
setDefaultData(false);
getSecondDisplay();
}
/**
* 解析數據
*/
private void initXML() {
InputStream stream = null;
AssetManager manager = getAssets();
try {
stream = manager.open("urldata.xml");
} catch (IOException e) {
Log.i(TAG, e.getMessage());
}
try {
map = new PullParseService(manager).getUrlsByParseXml(stream);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 將一級分類和二級分類的數據加載到數據庫中
*/
private void initData() {
ArrayList<UrlInfo> urlInfos = new ArrayList<UrlInfo>();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
HashMap.Entry entry = (HashMap.Entry)iter.next();
FirstClassify classify = (FirstClassify) entry.getKey();
urlInfos.addAll((ArrayList<UrlInfo>)entry.getValue()); // 二級分類添加到列表
mDbHelper.insertClassify(classify);// 將一級分類的數據保存在數據中
}
int count = urlInfos.size();
for (int i = 0; i < count; i++) {
UrlInfo urlInfo = urlInfos.get(i);
mDbHelper.insertUrlInfo(urlInfo);
Log.i(TAG, "to dburlInfo.name=" + urlInfo.getName());
}
}
/**
* 設置默認顯示的數據
*/
private void setDefaultData(boolean editMode) {
Log.i(TAG, "setDefaultData");
mClassifies = mDbHelper.queryClassify();
getFirstClassifyDisplay(editMode);
int def = utils.getDefaultLoading();
mUrlInfos = mDbHelper.queryUrlInfo(def);
if (mUrlInfos.isEmpty()) {
mUrlInfos = mDbHelper.queryUrlInfo(1);
}
getSecondDisplay();
}
/**
* 一級菜單顯示
*
* @param editMode 是否編輯
*/
private void getFirstClassifyDisplay(boolean editMode) {
FirstClassifyAdapteradapter = new FirstClassifyAdapter(mClassifies,
mContext, isEdit, this);
Log.i(TAG, "adapter.count=" + adapter.getCount());
lstFirstClassify.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
/**
* 獲得默認設置的顯示方式
*/
private void getSecondDisplay() {
switch (utils.getDisplayStyle()) {
case Constant.GRID_DISPLAY:
SecondClassifyGridAdapter secondClassifyGridAdapter = newSecondClassifyGridAdapter(mUrlInfos, mContext);
gidSecondClassify.setAdapter(secondClassifyGridAdapter);
lstSecondClassify.setVisibility(View.GONE);
gidSecondClassify.setVisibility(View.VISIBLE);
secondClassifyGridAdapter.notifyDataSetChanged();
break;
default:
SecondClassifyListAdapter secondClassifyAdapter = newSecondClassifyListAdapter(mUrlInfos, mContext);
lstSecondClassify.setAdapter(secondClassifyAdapter);
lstSecondClassify.setVisibility(View.VISIBLE);
gidSecondClassify.setVisibility(View.GONE);
secondClassifyAdapter.notifyDataSetChanged();
break;
}
}
/**
* 打開瀏覽器
* @param url
*/
private void openBrowser(String url){
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
Uri content_uri_browsers = Uri.parse(url);
intent.setData(content_uri_browsers);
intent.setClassName("com.android.browser","com.android.browser.BrowserActivity");
startActivity(intent);
}
</span></span>
對於列表的點擊功能,上面咱們說過經過實現OnItemClickListener,重寫其中的方法
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
UrlInfo urlInfo;
switch (parent.getId()) {
case R.id.list_first_classify:
FirstClassify firstClassify = (FirstClassify) lstFirstClassify.getItemAtPosition(position); // 獲得當前點擊的對象,這句代碼關鍵
txtRightMsg.setText(firstClassify.getName());
mUrlInfos = mDbHelper.queryUrlInfo(firstClassify.getId());
getSecondDisplay();
break;
case R.id.second_classify_list:
urlInfo = (UrlInfo) lstFirstClassify.getItemAtPosition(position);
openBrowser(urlInfo.getUrl());
break;
case R.id.second_classify_grid:
Log.i(TAG, "grid_context");
urlInfo = (UrlInfo) gidSecondClassify.getItemAtPosition(position);
openBrowser(urlInfo.getUrl());
break;
default:
break;
}
}
</span></span>
細心的讀者又發現了,上面提到主要的方法中咱們有調用到DBHelper類中相關的方法。是的,DBHelper是數據庫相關操做的類,這裏我列出來,給你們作個參考,類有待優化,還請各位別拍磚,呵呵
DBHelper.java(Sqlite數據庫操做類)
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">package org.winplus.surfing;
import java.util.ArrayList;
import android.R.integer;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
public class DBHelper {
private static final String TAG = "DBHelper";
public static final String ID = "_id";
public static final String NAME = "_name";
public static final String URL = "_url";
public static final String ICON = "_icon";
public static final String DESCRIBE = "_describe";
public static final String FKEY = "_fkey";
public static final String FID = "_id";
public static final String FNAME = "_name";
public static final String FICON = "_icon";
public static final int VERSION = 1;
public static final String DATABASE_NAME = "surfing.db";
public static final String TABLE_NAME_URLINFO = "urldata";
public static final String TABLE_NAME_CLASSIFY = "classify";
private static final String CREATE_TABLE_URLINFO = "create table "
+ TABLE_NAME_URLINFO + "(" + ID
+ " integer primary key autoincrement," + NAME + " text not null,"
+ URL + " text not null," + ICON + " blob," + DESCRIBE + " text,"
+ FKEY + " integer)"; // 建立二級菜單關於URLinfo的表
private static final String CREATE_TABLE_CLASSFIY = "create table "
+ TABLE_NAME_CLASSIFY + "(" + FID
+ " integer primary key autoincrement," + FNAME + " text," + FICON
+ " blob)"; // 建立一級菜單數據表
private SQLiteDatabase sqldb;
private Context mContext;
private ContentValues values;
private SurfingSQLHelper sqlHelper;
public DBHelper(Context context) {
mContext = context;
}
/**
* 一個幫助類,用於建立和對數據庫的版本進行管理
* @author acer
*
*/
class SurfingSQLHelper extends SQLiteOpenHelper {
public SurfingSQLHelper() {
// 建立數據庫和數據庫版本號
super(mContext, DATABASE_NAME, null, VERSION);
}
/**
* 此方法在第一次建立數據庫的時候調用,通常咱們用它來建立表
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_URLINFO);
db.execSQL(CREATE_TABLE_CLASSFIY);
}
@Override
public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
// TODO Auto-generated method stub
db.execSQL("drop table if exists " + CREATE_TABLE_URLINFO);
db.execSQL("drop table if exists " + CREATE_TABLE_CLASSFIY);
onCreate(db);
}
}
/**
* 打開數據庫
*/
public void open() {
sqlHelper = new SurfingSQLHelper();
sqldb = sqlHelper.getWritableDatabase();
}
/**
* 關閉數據庫
*/
public void close() {
sqlHelper.close();
}
/**
* 添加網址信息
*
* @param urlInfo
* @return
*/
public int insertUrlInfo(UrlInfo urlInfo) {
open();
values = new ContentValues();
values.put(NAME, urlInfo.getName());
values.put(URL, urlInfo.getUrl());
values.put(ICON, urlInfo.getIcon());
values.put(DESCRIBE, urlInfo.getDescribe());
values.put(FKEY, urlInfo.getFid());
// empty是表中沒有指向的列時用empty代替
int i = (int) sqldb.insert(TABLE_NAME_URLINFO, "empty", values);
close();
return i;
}
/**
* 添加一級分類記錄
*
* @param classify
* @return
*/
public int insertClassify(FirstClassify classify) {
open();
Log.i(TAG, "insertClassify");
values = new ContentValues();
values.put(FNAME, classify.getName());
Log.i(TAG, "classify.getIcon()=" + (classify.getIcon() == null));
values.put(FICON, classify.getIcon());
// empty是表中沒有指向的列時用empty代替
int i = (int) sqldb.insert(TABLE_NAME_CLASSIFY, "empty", values);
close();
return i;
}
/**
* 刪除UrlInfo信息
*
* @param id
* @return
*/
public int deleteUrlInfo(int id) {
open();
String[] whereArgs = new String[] { String.valueOf(id) };
int i = sqldb.delete(TABLE_NAME_URLINFO, "_id=?", whereArgs);
close();
return i;
}
/**
* 根據以及分類的ID刪除其全部子類
*
* @param fId
* @return
*/
public int deleteUrlInfoFid(int fId) {
open();
String[] whereArgs = new String[] { String.valueOf(fId) };
int i = sqldb.delete(TABLE_NAME_URLINFO, "_fkey=?", whereArgs);
close();
return i;
}
/**
* 刪除Classify信息
*
* @param id
* @return
*/
public int deleteClassify(int id) {
open();
String[] whereArgs = { String.valueOf(id) };
int i = sqldb.delete(TABLE_NAME_CLASSIFY, "_id=?", whereArgs);
close();
return i;
}
/**
* 根據ID修改網址記錄
*
* @param urlInfo
* @return
*/
public int updateUrlInfo(UrlInfo urlInfo) {
open();
values = new ContentValues();
values.put(NAME, urlInfo.getName());
values.put(URL, urlInfo.getUrl());
values.put(ICON, urlInfo.getIcon());
values.put(DESCRIBE, urlInfo.getDescribe());
values.put(FKEY, urlInfo.getFid());
String[] whereArgs = { String.valueOf(urlInfo.getFid()) };
int i = sqldb.update(TABLE_NAME_URLINFO, values, ID + "=?", whereArgs);
close();
return i;
}
/**
* 根據ID修改分類記錄
*
* @param classify
* @return
*/
public int updateClassify(FirstClassify classify) {
open();
values = new ContentValues();
values.put(FNAME, classify.getName());
values.put(FICON, classify.getIcon());
String[] whereArgs = { String.valueOf(classify.getId()) };
int i = sqldb.update(TABLE_NAME_CLASSIFY, values, ID + "=?", whereArgs);
return i;
}
/**
* 根據ID查詢UrlInfo
*
* @return
*/
public ArrayList<UrlInfo> queryUrlInfo(int id) {
open();
String[] whereArgs = new String[] { String.valueOf(id) };
Cursor cursor = sqldb.query(TABLE_NAME_URLINFO, null, "_fkey=?",
whereArgs, null, null, null, null);
ArrayList<UrlInfo> urlInfos = new ArrayList<UrlInfo>();
int count = cursor.getCount();
for (int i = 0; i < count; i++) {
cursor.moveToPosition(i);
UrlInfo urlBean = new UrlInfo();
urlBean.setFid(cursor.getInt(cursor.getColumnIndex(ID)));
urlBean.setName(cursor.getString(cursor.getColumnIndex(NAME)));
urlBean.setUrl(cursor.getString(cursor.getColumnIndex(URL)));
urlBean.setIcon(cursor.getBlob(cursor.getColumnIndex(ICON)));
urlBean.setDescribe(cursor.getString(cursor
.getColumnIndex(DESCRIBE)));
urlInfos.add(urlBean);
}
close();
return urlInfos;
}
/**
* 查詢全部的Url分類
*
* @return
*/
public ArrayList<FirstClassify> queryClassify() {
open();
Cursor cursor = sqldb.query(TABLE_NAME_CLASSIFY, null, null, null,
null, null, null);
ArrayList<FirstClassify> classifies = new ArrayList<FirstClassify>();
int count = cursor.getCount();
for (int i = 0; i < count; i++) {
cursor.moveToPosition(i);
FirstClassify classify = new FirstClassify();
classify.setId(cursor.getInt(cursor.getColumnIndex(FID)));
classify.setName(cursor.getString(cursor.getColumnIndex(FNAME)));
classify.setIcon(cursor.getBlob(cursor.getColumnIndex(FICON)));
classifies.add(classify);
}
close();
return classifies;
}
}
</span></span>
Ok,項目寫到這裏,主要功能差很少完成了。固然還有不少須要優化的細節,好比說圖片,好比說代碼、UI優化工做,先上效果圖看看(這只是初步的實現主要功能)
下面,咱們再SurfingDemoActivity.java中添加一個Menu,首先在res目錄下添加一個名爲menu的文件夾,再新建一個名爲surfing_menu.xml的xml文件。
surfing_menu.xml(Menu)
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;"><?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/menu_add"
android:icon="@drawable/ic_launcher"
android:title="添加"/>
<item
android:id="@+id/menu_edit"
android:icon="@drawable/ic_launcher"
android:title="編輯"/>
<item
android:id="@+id/menu_default"
android:icon="@drawable/ic_launcher"
android:title="恢復默認"/>
</menu>
</span></span>
在android中實現Menu的功能很簡單,只須要重寫onCreateOptionsMenu方法就行了,點擊菜單執行相應的操做重寫:onOptionsItemSelected。這裏,我直接引用上面的xml文件來實現menu的佈局。固然你能夠直接在代碼裏面寫。引用也很簡單,就一句話:
<span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">this.getMenuInflater().inflate(R.menu.surfing_menu, menu);</span></span>
上面咱們提到在菜單中有編輯功能。好比說添加一級菜單,二級菜單,這些都是些簡單的邏輯處理,這裏就再也不貼代碼了。最後我就編輯中選擇圖片的功能作一個簡單的介紹,這個相似於一個簡單的文件瀏覽器。咱們先看看界面
其實實現這個功能是很簡單的。先獲取設備的目錄地址,枚舉此目錄下全部的文件,而後顯示在界面上,若是是圖片,就直接將圖片的略縮圖顯示出來。點擊圖片就直接獲取其地址,返回給設置界面,賦值給EditText就能夠了。這裏我貼出關鍵代碼,做爲參考,頗有改善餘地的。呵呵,各位見諒了…
BrowserFileAdapter.java這個是繼承BaseAdapter的,沒有什麼好說的。
<div style="font-weight: normal; text-align: left; "><span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">package org.winplus.surfing;</span></span></div><span style="font-size:16px;"><span style="font-family: 'Microsoft YaHei'; "></span></span><div style="text-align: left;"><span style="font-weight: normal;"><span style="font-size:16px;">
</span></span></div><span style="font-size:16px;"><span style="font-weight: normal;"></span></span><div style="text-align: left;"><span style="font-size:16px;">import java.util.ArrayList;</span></div><div style="text-align: left;"><span style="font-family: 'Microsoft YaHei'; "><span style="font-weight: normal; "><span style="font-size:16px;">
</span></span></span></div><span style="font-size:16px;"><span style="font-family: 'Microsoft YaHei'; "></span></span><div style="text-align: left;"><span style="font-weight: normal;"><span style="font-size:16px;">
</span></span></div><span style="font-size:16px;"><span style="font-weight: normal;"></span></span><div style="text-align: left;"><span style="font-size:16px;">import android.content.Cont</span></div><div style="text-align: left;"><span style="font-size:16px;">ext;</span></div><div style="text-align: left;"><span style="font-size:16px;">t android.view.LayoutInflater;
impo</span></div><div style="text-align: left;"><span style="font-size:16px;">impo</span></div><div style="text-align: left;"><span style="font-size:16px;">rrt android.view.View;</span></div><div style="text-align: left;"><span style="font-size:16px;">wGroup;
import android.widget.</span></div><div style="text-align: left;"><span style="font-size:16px;">import android.view.Vi</span></div><div style="text-align: left;"><span style="font-size:16px;">eBaseAdapter;</span></div><div style="text-align: left;"><span style="font-size:16px;">import android.widget.ImageView;</span></div><div style="text-align: left;"><span style="font-size:16px;">rowserFileAdapter extends BaseA</span></div><div style="text-align: left;"><span style="font-size:16px;">import android.widget.TextView;</span></div><span style="font-size:16px;">
</span><div style="text-align: left;"><span style="font-size:16px;">ublic class </span></div><span style="font-size:16px;">
p
</span><div style="text-align: left;"><span style="font-size:16px;">Bdapter {</span></div><span style="font-size:16px;">
</span><div style="text-align: left;"><span style="font-size:16px;">rayList<DirFileInfo> mDirFileInfos = new ArrayList<DirFileInfo>();
private L</span></div><span style="font-size:16px;"> private A
rayoutInflater inflater;
</span><div style="text-align: left;"><span style="font-size:16px;">(ArrayList<DirFileInfo> dirFileInfos,Context context) {
mDirFileInfos = dirFile</span></div><span style="font-size:16px;"> public BrowserFileAdapte
rInfos;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
</span><div style="text-align: left;"><span style="font-size:16px;">rride
public Object getItem(int </span></div><span style="font-size:16px;"> if (!mDirFileInfos.isEmpty()) {
return mDirFileInfos.size();
}
return 0;
}
@Ov
eposition) {
if (!mDirFileInfos.isEmpty()) {
return mDirFileInfos.get(position);
}
return null;
}
@Override
</span><div style="text-align: left;"><span style="font-size:16px;">iewGroup parent) {
ViewHolder holde</span></div><span style="font-size:16px;"> public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView,
Vr = null;
DirFileInfo dirFileInfo = mDirFileInfos.get(position);
if (convertView == null) {
holder = new ViewHolder();
</span><div style="text-align: left;"><span style="font-size:16px;">.list_photo_icon);
holder.name = (TextView) convertView.findViewBy</span></div><span style="font-size:16px;"> convertView = inflater.inflate(R.layout.list_photo_browser, null);
holder.icon = (ImageView) convertView.findViewById(R.i
dId(R.id.list_photo_name);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
holder.icon.setBackgroundDrawable(dirFileInfo.getIcon());
</span><div style="text-align: left;"></div><span style="font-size:16px;"> holder.name.setText(dirFileInfo.getName());
return convertView;
}
private class ViewHolder{
public ImageView icon;
public TextView name;
}
</span><div style="text-align: left;"></div><span style="font-size:16px;">}
</span>
DirFileInfo.java(目錄文件信息)
<span style="font-weight: normal;"><span style="font-family: 'Microsoft YaHei'; "><span style="font-size:16px;">public class DirFileInfo{
private Drawable icon;
private String name;
private String path;
private boolean isDir;
// getter。Setter
}</span></span></span>
BrowserPhotoActivity.java(Activity顯示界面)
<span style="font-size:16px;">package org.winplus.surfing;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
public class BrowserPhotoActivity extends Activity implements OnClickListener,
OnItemClickListener {
private static final String TAG = "BrowserPhotoActivity";
private EditText edtPath;
// private Button btnList;
// private Button btnGrid;
private ListView lstFile;
private GridView gidFile;
private Context mContext;
private BrowserFileAdapter fileAdapter;
private ArrayList<DirFileInfo> dirFileInfos = new ArrayList<DirFileInfo>();
private static StringBuffer mPath = new StringBuffer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_browser);
setupViews();
}
private void setupViews() {
edtPath = (EditText) findViewById(R.id.photo_path);
//btnGrid = (Button) findViewById(R.id.photo_grid_display);
//btnList = (Button) findViewById(R.id.photo_list_display);
lstFile = (ListView) findViewById(R.id.photo_list);
gidFile = (GridView) findViewById(R.id.photo_grid);
gidFile.setVisibility(View.GONE);
//btnGrid.setOnClickListener(this);
//btnList.setOnClickListener(this);
lstFile.setOnItemClickListener(this);
mContext = BrowserPhotoActivity.this;
// 添加表頭
LinearLayout layout=new LinearLayout(mContext);
layout.setGravity(Gravity.LEFT);
ImageView imageView = new ImageView(mContext);
imageView.setBackgroundResource(R.drawable.ic_prev_dir);
layout.addView(imageView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
lstFile.addHeaderView(layout);
mPath.append(Environment.getExternalStorageDirectory().getPath());
getCurrentPathFileDir(mPath.toString());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.photo_grid:
break;
case R.id.photo_list:
break;
default:
break;
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
if (position==0) {
int pathCount = mPath.toString().lastIndexOf("/");
if (pathCount==0) {
mPath.delete(0, mPath.length()).append("/");
}else {
mPath.delete(pathCount,mPath.length());
}
getCurrentPathFileDir(mPath.toString());
}else {
DirFileInfo dirFileInfo = (DirFileInfo) lstFile.getItemAtPosition(position);// 獲得當前點擊的對象
if(dirFileInfo.isDir()){
// 爲目錄時,點擊顯示下級目錄中的圖片文件和文件夾
Log.i(TAG, "is dir");
Log.i(TAG, "mpath="+mPath+";dirFileInfo.name="+dirFileInfo.getName());
mPath.append("/").append(dirFileInfo.getName());
getCurrentPathFileDir(mPath.toString());
}else {
// 選擇圖片
Intent intent = new Intent();
Log.i(TAG, "dirFileInfo.getPath()="+dirFileInfo.getPath());
intent.putExtra("iconAbsPath",dirFileInfo.getPath());
setResult(Constant.BROWSER_IMAGE, intent);
finish();
Log.i(TAG, "is file");
}
}
}
/**
* 獲得當前目錄下的圖片文件和文件夾
* @param path
*/
private void getCurrentPathFileDir(String path){
edtPath.setText(path);
dirFileInfos = Utils.getDirFile(path, mContext);
fileAdapter = new BrowserFileAdapter(dirFileInfos, mContext);
lstFile.setAdapter(fileAdapter);
fileAdapter.notifyDataSetChanged();
}
}
</span>
5、擴展,咱們在界面設計中看到有一個排序功能,這是一個擴展的功能,其實在這個應用程序中能夠不作,意義不大,若是非要作這個功能的話,我建議作成Music中可以經過拖動列表進行排序這樣的功能