顯示具有 excel 標籤的文章。 顯示所有文章
顯示具有 excel 標籤的文章。 顯示所有文章

2013年4月27日 星期六

說說,專案import jar檔或是其他專案的方法。


在android中,我們開發專案時常常會需要其他朋友所開發的輪子,
於是就會需要improt其他專案檔或是封裝好的jar檔。

這有許多好處:

  1. 避免重複開發:
    自己或是有找到已經開發過的系統,我們可以直接引用來使用,
    加快開發的時間。
  2. 專職分工:
    在合作開發上,每個人負責一個獨立的需求的系統,
    由team leader或是專職負責的人來進行整合的工作。
    此時將它做成專案檔或是jar檔就很有用了,
    如果配合上足夠的java doc,對於公司或是開發的同步速度上會有很大的幫助。
  3. 分享:
    就像是工具箱的功能,網路上也有許多神人與強者分享自己所開發的jar檔,
    這真的很偉大,尤其是有許多朋友提供了其中的source code給大家進行更多優化,
    未來我們也應該要多做這樣的事情來貢獻軟體產業才是。
所以,在合法使用的前提之下,我們可以盡量import專案或是jar檔來達到快速達到功能需求的目的。至於我為什麼會一直提到"improt專案和jar檔"呢?

因為目前我知道的有兩種方法可以避免重複創作輪子:
  1. jar檔:
    副檔名為".jar"的單一檔案,其中大多為許多class,為實現特殊需求所創作出來的工具箱,
    之後我們會有個簡單的範例來教學如何import jar檔。
  2. 專案檔:
    我想如果有開發過google map api for android v2的朋友應該會有印象,我們會add一個google所開發的專案作為lib。我們也可以自己製作一個完整的專案來讓其他專案import呢!
順道一提,.jar檔基本上如果沒有擾碼,其安全性是非常低的,
可以使用反組譯的方法來看到其中的source code。
不過如果正常使用的範圍,基本上是不需要這樣操作的,
而通常我們自己做的工具箱不太會需要把它封裝成.jar檔,
大多是設定為"Is Library"來作為讓其他專案引用的接口。

好,說到底,方法很簡單。首先我們來實作怎麼樣import .jar檔案:

  1. 首先,把.jar檔放到"libs"資料夾中,這不是最重要的。
    等等我們會設定參考位置,你也可以放在外部資料夾中,
    這樣的話要注意所放置的位置必須不能改變,要不牽一髮而動全身呀。
  2. 接著看圖片:
    1. 對著專案案右鍵,選擇Properties:
    2. 然後如果你是放在"libs"資料夾中的話,參考位置的設定依照下列步驟:
    3. 如果是放在外面,可以選擇右邊第二個"Add External JARs.."選項,
      選擇外部的檔案來使用。
  3. 如果完成的話,會發現我們可以開始使用.jar檔裡面的class啦!
    至於有件很重要的事情便是:"該怎麼知道裡面有什麼東西?"

    這時我們除了對他反組譯之外,在下載時所看到的doc或是範例就很重要了。除此之外,我們也可以直接用檔案名稱來google,通常也可以找到相關的說明文檔。例如之前分享過的專案(see: 說說,關於文件匯出至Excel檔案中。)可以直接搜尋"jxl.jar",會找到一些相關的資料。
嗯嗯..我還是建議放在"libs"的資料夾中,話說這個資料夾在以前稱之為"lib",在2012年大概六月底左右eclipse的android ADT改版,當時除了create new project的流程大改之外,也改了一些結構的部分,所以如果當時有更新這波流行個開發者們會突然發現之前的project都不能run了,主要就是原本import的jar檔連結斷掉,不過解法其實很簡單,只要稍微改資料夾名稱就好哩。

然後接下來,是開發project透過import來引用的作法。
這我覺得還滿重要的,因為我們常常同時一起開發一個專案,如果我是PM或是team leader,我應該怎麼管理RD的工作方式,以能夠有最好的效率呢?

目前我的解如下:

  1. 將目前規劃的app依照需求功能切分和分類的動作。開始進行功能實現調查的動作。
    1. 功能調查完畢,我們應該會獲得所有功能完整的實作參考,甚至是demo。
  2. 此時便開始分工了,leader開始建構主程式的架構部分,實做出接口。
    1. 其他人同步開始將所負責的功能做成project,並且依照架構提供接口。
    2. 此時會架構出工具箱,提供未來開發需求時使用。
  3. 最後leader或是負責整合的夥伴,依照其他人所提供的project與doc來進行整合的動作,將系統完整建構出來。
  4. 依照該app的case進行最後修改的動作,例如刪除工具箱中不需要的功能,或是依照特殊的需求整理project的function。並且最最後壓力測試。
  5. 可靠度測試完成後,將app上線!
真的是完美的如意算盤。當然如果整個case只有一個人來做的話,這一切就只有一個人來弄了。
其中第2點和第3點的步驟中,我們將project設定成可以給其他夥伴使用的project,關鍵在這裡:
該project的Properties之中,設定為一個library用途的project,
而在main project中,要按下Add來選擇之前所設定的project,示意圖如下:
這和import .jar檔有什麼不一樣呢?
  1. 他是android獨特的import方法,可以用來import android相關的應用,包括了Activity和Service等相關類別。
  2. 因為是直接import編輯檔,所以可以一邊使用一邊檢查/修改所import的project。
    不過要注意,當library project修改過後,main project需要Refresh(按F5)過後才會重新更新鏈結,達到更新的效果。
  3. 系統功能分類會更加明確,可能不同的功能會需要相對應不同的res資料,透過這個方法我們可以將工具箱所需要的res資源分類的更好,但是另外一面來看我們也會發現可能會造成app檔案太大的問題,所以在最後才會需要有所整理的動作。

以上,個人認為import project非常好用。而以上提供兩種方法,希望對大家有所幫助。











2012年4月23日 星期一

說說,關於文件匯出至Excel檔案中。

關於「備份」這件事情,除了雲端備份之外,我們在android中常見的還有Excel備份。
在java中備份是用到「jxl.jar」這個API,
關於這個API的下載可以參考這裡,而文件可以看這裡。

網路上有非常多的人實做這個應用,今天我們來為了android來實做,
首先先來試著想想android對於備份的應用怎麼做,使用流程如下:

  1. 產生資料。
  2. 存入SQLite。
  3. 修改資料:
    1. 提取 SQLite中 對應的資料。
    2. 進行資料修改。
    3. 存入SQLite,覆蓋至對應的位置。
  4. 備份資料:
    1. 建立Excel檔案(.xls)。
    2. 建立 Excel檔案的工作表與建立第一列的欄位(通常Excel都會這樣做吧?)
    3. 提取SQLite中所有資料。
    4. 將提取出來的資料分批存入Excel檔案中。
大概是這樣,然後小書實做了一個範例,是修改之前的wifiTest所作,下載位置在這裡。

要注意的是,jxl這個API裡面,.write()這個方法必須在最後調用,所以在範例中小書把他放到最後一個,寫完就關閉了這樣。
目前沒有做.xls檔案查詢的功能,有幾個理由:
  1. 要看這檔案的人,會透過M$的專門軟體來開啟,而且也已經有許多人開發了相對應的檢視軟體了。
  2. 我們對SQLite的操作比較瞭解,而這個API提供的方法不能確定其是否適合存取交替運作。
所以我們把.xls檔案的操作專注在「將SQLite的內容整理並複製置.xls檔案中」。

其實做的code如下,首先,我們必須增加能夠外部存取的權限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="exceltest.susan.idea"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name=".ExcelTestActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

接著,這是layout的內容:

<?xml version="1.0" encoding="utf-8"?>



    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <TextView
            android:id="@+id/textView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="center"
            android:text="Test" />
    </ScrollView>


然後,我們寫入兩個class,分別是databaase和excel所封裝起來的class:


package exceltest.susan.idea;

import java.sql.Timestamp;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseForExcelTest {

    private static final String TAG = DatabaseForExcelTest.class.getSimpleName();

    static final int VERSION = 1;
    static final String DATABASE = android.os.Environment
            .getExternalStorageDirectory().getAbsolutePath()
            + "/ExcelTest/database.db3";
    static final String TABLE = "tableOfthisDataBase";

    /**
     * "date", "bssid", "ssid","level"
     */
    public static final String[] KEY_COLUMNS = { "date", "bssid", "ssid",
            "level" };

    private static class DbHelper extends SQLiteOpenHelper {

        public DbHelper(Context context) {
            super(context, DATABASE, null, VERSION);
        }

        @Override
        // 只會被呼叫一次,在第一次資料庫建立的時候
        public void onCreate(SQLiteDatabase db) {
            Log.i(TAG, "Creating database: " + DATABASE);
            db.execSQL(getCreateSQL());
        }

        public String getCreateSQL() {
            StringBuffer mStringBuffer = new StringBuffer();
            mStringBuffer.append("CREATE TABLE IF NOT EXISTS " + TABLE + " ("
                    + "_id" + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
                    + KEY_COLUMNS[0]
                    + " TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,");
            for (int n = 1; n < KEY_COLUMNS.length; n++) {
                mStringBuffer.append(KEY_COLUMNS[n] + " TEXT, ");
            }
            mStringBuffer.delete(mStringBuffer.length() - 2,
                    mStringBuffer.length());// 刪除", "
            mStringBuffer.append(");");
            return mStringBuffer.toString();
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
            db.execSQL("DROP TABLE IF EXISTS " + TABLE);
            this.onCreate(db);
        }
    }

    private final DbHelper dbHelper;
    private SQLiteDatabase db;

    public DatabaseForExcelTest(Context context) {
        dbHelper = new DbHelper(context);
        Log.i(TAG, "Initialized database in Constructor of DB");
    }

    public DatabaseForExcelTest openToWrite() throws SQLException {
        db = dbHelper.getWritableDatabase(); // 若資料庫存在則開啟;若不存在則建立一個新的
        return this;
    }

    public DatabaseForExcelTest openToRead() throws SQLException {
        db = dbHelper.getReadableDatabase(); // 若資料庫存在則開啟;若不存在則建立一個新的
        return this;
    }

    public void close() {
        dbHelper.close();
    }

    /** 添加資料 */
    public void insert(ContentValues values) throws SQLException {
        db.insertOrThrow(TABLE, null, values);
        Log.i(TAG, "insert data into db");
    }

    /**
     * 更新資料(測試)
     * 
     * @param column
     *            輸入欄位名稱
     * @param oldValue
     *            輸入欄位內欲查詢的變數
     * @param newValue
     *            輸入要更新的值
     */
    public void update(String column, String oldValue, ContentValues newValue)
            throws SQLException {
        db.update(TABLE, newValue, column + "=" + oldValue, null);
    }

    /**
     * 刪除資料(測試)
     * 
     * @param column
     *            輸入欄位名稱
     * @param value
     *            輸入欄位內欲查詢的變數
     */
    public void deleteData(String column, String value) throws SQLException {
        db.delete(TABLE, column + "=" + value, null);
    }

    /**
     * 獲得資料(測試)
     * 
     * @param column
     *            輸入欄位名稱
     * @param value
     *            輸入欄位內欲查詢的變數
     */
    public Cursor getData(String column, String value) {
        String cmd = "SELECT * FROM " + TABLE + " WHERE " + column + "="
                + value;
        return db.rawQuery(cmd, null);
    }

    /** 獲得全部資料 */
    public Cursor getAll() {
//         return db.rawQuery("SELECT * FROM " + TABLE, null);
        return db.query(TABLE, null, null, null, null, null, null);
    }

    /** 依照時間間隔獲取資料 */
    public Cursor getIntervalData(Timestamp from, Timestamp to) {
        String cmd = "SELECT * FROM " + TABLE + " WHERE (" + KEY_COLUMNS[0]
                + " >= '" + from.toString() + "') AND (" + KEY_COLUMNS[0]
                + " <= '" + to.toString() + "')";

        return db.rawQuery(cmd, null);
    }

    /** 清除全部的資料 */
    public boolean clearAll() {
        return db.delete(TABLE, null, null) > 0;
    }
    
    

}




package exceltest.susan.idea;

import java.io.File;
import java.io.IOException;

import jxl.Workbook;
import jxl.format.Colour;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;

/** 參考:http://jexcelapi.sourceforge.net/resources/javadocs/current/docs/ */
public class ExcelHelper {

    String path, fileName;
    String[] labelNames;
    WritableWorkbook mWritableWorkbook;
    Workbook mWorkbook;

    String EXCEL_PATH;

    static WritableCellFormat mWritableCellFormat;

    /** 開啟一個可寫入的excel檔案,注意最後必須調用closeExcelWritableWorkbook以完成寫入。 */
    public boolean createExcelWritableWorkbook(String path, String fileName
            ) {
        this.path = path;
        this.fileName = fileName + ".xls";
        
        EXCEL_PATH = this.path + "/" + this.fileName;
        try {
            // 打开文件
            File dir = new File(path);
            if (!dir.exists()) // true if this file exists, false otherwise.
            {
                dir.mkdir();// true if the directory has been created, false
                            // otherwise
            }// 如果資料夾不存在則創立一個資料夾..

            mWritableWorkbook = Workbook.createWorkbook(new File(EXCEL_PATH));
            return true;
        } catch (Exception e) {
            System.out.println(e);
            return false;
        }
    }

    
//    public boolean getExcelBook() {
//        
//        if(mWritableWorkbook!=null){
//            try {
//                mWritableWorkbook.close();
//            } catch (WriteException e) {
//                e.printStackTrace();
//                return false;
//            } catch (IOException e) {
//                e.printStackTrace();
//                return false;
//            }
//        }
//        
//        try {
//            mWorkbook = Workbook.getWorkbook(new File(EXCEL_PATH));
//            return true;
//        } catch (BiffException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return false;
//    }
    
    /** 關閉excel檔案,很重要!最後一定要執行 */
    public boolean close() {
        if (mWritableWorkbook != null) {
            try {
                wrriteExcelWritableWorkbook();
                mWritableWorkbook.close();
                return true;
            } catch (WriteException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(mWorkbook!=null){
            mWorkbook.close();
        }
        return false;
    }

    public WritableSheet getOrCreateExcelSheet(String sheetName) {
        // 產生excel中的工作表
        if (mWritableWorkbook != null) {
            WritableSheet sheet = mWritableWorkbook.getSheet(sheetName);
            if (sheet == null) {
                sheet = mWritableWorkbook.createSheet(sheetName, 0);
            }
            return sheet;
        }
        return null;
    }
    
    /**放置文字至指定工作表中。*/
    public boolean putData(WritableSheet sheet, int c, int r,
            String lableString, WritableCellFormat mWritableCellFormat) {
        Label label;
        if (mWritableCellFormat != null) {
            label = new Label(c, r, lableString, mWritableCellFormat);
        } else {
            label = new Label(c, r, lableString);
        }
        try {
            sheet.addCell(label);

            return true;
        } catch (RowsExceededException e) {
            e.printStackTrace();

        } catch (WriteException e) {
            e.printStackTrace();
        }

        return false;
    }

    

    /**放置數字至指定工作表中。*/
    public boolean putData(WritableSheet sheet, int c, int r,
            double numberDouble, WritableCellFormat mWritableCellFormat) {
        jxl.write.Number number;
        if (mWritableCellFormat != null) {
            number = new jxl.write.Number(c, r, numberDouble,
                    mWritableCellFormat);
        } else {
            number = new jxl.write.Number(c, r, numberDouble);
        }
        try {
            sheet.addCell(number);

            return true;
        } catch (RowsExceededException e) {
            e.printStackTrace();

        } catch (WriteException e) {
            e.printStackTrace();

        }
        return false;
    }

    private boolean wrriteExcelWritableWorkbook() {
        try {
            mWritableWorkbook.write();
            return true;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 設定表格的樣式。參考:http://jexcelapi.sourceforge.net/resources/javadocs/current/
     * docs/
     */
    public static WritableCellFormat putWritableCellFormat(
            WritableFont.FontName writableFont, int paintSize, Colour mColour) {
        if (mWritableCellFormat == null) {
            mWritableCellFormat = new WritableCellFormat();
        }
        WritableFont chFont11w = new WritableFont(writableFont, paintSize);
        /*
         * WritableCellFormat cellFormat1 = new WritableCellFormat ();
         * cellFormat1.setFont(chFont11w);
         * cellFormat1.setBackground(Colour.DARK_GREEN);
         * cellFormat1.setAlignment(Alignment.CENTRE);
         * cellFormat1.setBorder(Border.ALL, BorderLineStyle.THIN,
         * Colour.GRAY_80);
         */

        try {
            chFont11w.setColour(mColour);
        } catch (WriteException e) {
            e.printStackTrace();
        }
        mWritableCellFormat.setFont(chFont11w);
        return mWritableCellFormat;
    }

}


最後,是main class,其中的流程是這樣的:

  1. 增新資料,存入SQLite。
  2. 顯示資料,這邊是多餘的動作。
  3. 將資料從SQLite讀出來,再置入Excel當中。



package exceltest.susan.idea;

//生成Excel的类
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.TimeZone;

import jxl.format.Colour;
import jxl.write.WritableFont;
import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.TextView;

public class ExcelTestActivity extends Activity {
    TextView mTextView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mTextView = (TextView) this.findViewById(R.id.textView);
        createTestingDataToSQLite(50);//增新n筆資料
        showDataBase();//顯示資料,這邊顯示的資料應該會被蓋過去。
        saveDataToExcelFromDatabase();//儲存資料
    }

    /** 建立測試檔案 */
    private void createTestingDataToSQLite(int number) {
        DatabaseForExcelTest db = new DatabaseForExcelTest(this);
        db.openToWrite();
        db.clearAll();//先做一個清空的動作。
        Calendar c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));// 設定時區為台灣時間。
        Timestamp timestamp;
        ContentValues contentValues = new ContentValues();
        for (int n = 0; n < number; n++) {
            timestamp = new Timestamp(c.getTimeInMillis());// 先行建立,於輸入database時置入
            putDatabaseValue(db, contentValues, timestamp,
                    "BSSID" + n, "SSID" + n, "LEVEL" + n);
        }
        db.close();
    }

    /** 顯示database中的檔案內容 */
    private void showDataBase() {
        DatabaseForExcelTest db = new DatabaseForExcelTest(this);
        db.openToRead();
        Cursor mCursor = db.getAll();
        mCursor.moveToFirst();
        do {
            mTextView.append("顯示database資訊:");
            mTextView
                    .append("\nBSSID:"
                            + mCursor.getString(mCursor
                                    .getColumnIndex(DatabaseForExcelTest.KEY_COLUMNS[1])));
            mTextView
                    .append("\nSSID:"
                            + mCursor.getString(mCursor
                                    .getColumnIndex(DatabaseForExcelTest.KEY_COLUMNS[2])));
            mTextView
                    .append("\nLEVEL:"
                            + mCursor.getString(mCursor
                                    .getColumnIndex(DatabaseForExcelTest.KEY_COLUMNS[3])));
        } while (mCursor.moveToNext());

        db.close();
    }

    /** 顯示database中的檔案內容 */
    private void saveDataToExcelFromDatabase() {
        mTextView.setText("儲存資料...");
        final String path = android.os.Environment
                .getExternalStorageDirectory().getAbsolutePath() + "/ExcelTest";// 路徑名稱
        final String name = "ExcelTest";// 檔案名稱,不用加上副檔名
        final String nameOfSheet = "第一頁";// 工作表名稱
        ExcelHelper mExcelHelper = new ExcelHelper();
        if (mExcelHelper.createExcelWritableWorkbook(path, name)) {//如果開啟成功
            for (int n = 0; n < DatabaseForExcelTest.KEY_COLUMNS.length-1; n++) {
                mExcelHelper.putData(mExcelHelper
                        .getOrCreateExcelSheet(nameOfSheet), n, 0,
                        DatabaseForExcelTest.KEY_COLUMNS[n+1], ExcelHelper
                                .putWritableCellFormat(WritableFont.TIMES, 16,
                                        Colour.BLACK));
                //這個for裡面,注意為了不要獲取time的資料欄位所做了+1-1等更動。
            }
        }
        //打開database
        DatabaseForExcelTest db = new DatabaseForExcelTest(this);
        db.openToRead();
        Cursor mCursor = db.getAll();//獲得所有內容
        mCursor.moveToFirst();
        String[] showInfo = { "\nBSID:", "\nSSID:", "\nLEVEL:" };
        int inSheetRow=1;//因為第0列顯示的是欄位名稱
        do {
            mTextView.append("\n顯示database資訊:");
            for (int n = 0; n < DatabaseForExcelTest.KEY_COLUMNS.length-1; n++) {
                //顯示資訊
                mTextView
                        .append(showInfo[n]
                                + mCursor.getString(mCursor
                                        .getColumnIndex(DatabaseForExcelTest.KEY_COLUMNS[n+1])));
                //將資訊儲存至excel
                mExcelHelper
                        .putData(
                                mExcelHelper.getOrCreateExcelSheet(nameOfSheet),
                                n,
                                inSheetRow,
                                mCursor.getString(mCursor
                                        .getColumnIndex(DatabaseForExcelTest.KEY_COLUMNS[n+1])),
                                ExcelHelper.putWritableCellFormat(
                                        WritableFont.TIMES, 30, Colour.BLACK));
                //這個for裡面,注意為了不要獲取time的資料欄位所做了+1-1等更動。
            }
            inSheetRow++;//移到下一個row
        } while (mCursor.moveToNext());
        
        mExcelHelper.close();//寫入,關閉excel。
        mTextView.append("\n完畢!");
        db.close();
    }

    /**添加一筆資料至database*/
    private void putDatabaseValue(DatabaseForExcelTest database,
            ContentValues contentValues, Timestamp timestamp, String bssid,
            String ssid, String level) {

//        contentValues.clear();
        contentValues.put(DatabaseForExcelTest.KEY_COLUMNS[0],
                timestamp.toString());
        contentValues.put(DatabaseForExcelTest.KEY_COLUMNS[1], bssid);
        contentValues.put(DatabaseForExcelTest.KEY_COLUMNS[2], ssid);
        contentValues.put(DatabaseForExcelTest.KEY_COLUMNS[3], level);
        database.insert(contentValues);
    }

}


其檔案可以從SD卡的ExcelTest資料夾中找到.db3和.xls檔。




追蹤者