顯示具有 Java Code 標籤的文章。 顯示所有文章
顯示具有 Java Code 標籤的文章。 顯示所有文章

2011年12月29日 星期四

Java - 檔案型態 get the file type

如果你想要得知某個檔案的型態,程式如下:

        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String type = fileNameMap.getContentTypeFor("/mnt/sdcard/a.jpg");
        Log.d("gill","file type = " + type);

你可以從log看到
D/gill    ( 5710): file type = image/jpeg

這個檔案是image且是jpeg的型態

Java - 檔案處理(2) - 複製檔案

在JDK1.4之前,複製檔案可以利用

(1) FileInputStream
(2) FileOutputStream
(3) read()

這三個關鍵方法來完成,程式如下:
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis  = new FileInputStream("/mnt/sdcard/xxx.apk");
            fos = new FileOutputStream("/mnt/sdcard/xxx2.apk");
            byte[] buf = new byte[1024];
            int i = 0;
            while ((i = fis.read(buf)) != -1) {
                fos.write(buf, 0, i);
            }
            if (fis != null) fis.close();
            if (fos != null) fos.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }

到了JDK1.4之後,有更具效率的新套件可以用。我們改用FileChannel的方式來實作程式:
        FileChannel fis = null;
        FileChannel fos = null;
        try {
            fis  = new FileInputStream("/mnt/sdcard/xxx.apk").getChannel();
            fos = new FileOutputStream("/mnt/sdcard/xxx2.apk").getChannel();
            fos.transferFrom(fis, 0, fis.size());
            if (fis != null) fis.close();
            if (fos != null) fos.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }

Java - 檔案處理(1) - 如何複製貼上檔案(copy paste)

如果想要把某一個檔案,複製到另一個地方,程式如下:

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis  = new FileInputStream("/mnt/sdcard/sample.apk");
            fos = new FileOutputStream("/mnt/sdcard/sample.apk");
            byte[] buf = new byte[1024];
            int i = 0;
            while ((i = fis.read(buf)) != -1) {
                fos.write(buf, 0, i);
            }
            if (fis != null) fis.close();
            if (fos != null) fos.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }

Java - CRC32驗證程式或檔案

如果想要驗證你的程式或是檔案有沒有被更改過時,CRC32是一個很簡單的方式。比如你有一支程式可以幫手機進行檔案的更新,通常作法是先讓使用者 下載新的程式,然後再安裝。但是如果下載後,過了一段時間,程式檔案已經發生損毀,使用者不知道還進行安裝,有可能發生不可預期的錯誤。

因 此,應該在安裝前先檢查一下準備安裝的程式是不是和原本下載的程式一模一樣。CRC32的運作流程是,首先去網路上找一個CRC32的軟體,它可以計算出 你的程式的checksum,然後安裝前再用你自己寫的CRC32程式碼再計算一次當下的程式的checksum, 這兩個checksum如果相同,就代表程式沒有變動過。

用java計算 checksum程式如下:

先要
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;

然後如下:

try {
            CheckedInputStream cis = null;
            cis = new CheckedInputStream(new FileInputStream("/data/test.apk), new CRC32());
            byte[] buf = new byte[128];
            while(cis.read(buf) >= 0) {
            }

            checksum = cis.getChecksum().getValue();

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

假設你原本用網路上抓下來的軟體計算出來的checksum是1000,
然後  checksum = cis.getChecksum().getValue();  這裡計算出來的也是1000,
表示目前這個test.apk和原本提供給使用者的程式是相同的。如果計算出來不是1000,就表示test.apk和當時的程式已經不同了。

Android - 取得系統時間 - Calendar

如果要取得目前的系統時間,可用
import java.util.Calendar;
               
long time=System.currentTimeMillis();
final Calendar mCalendar=Calendar.getInstance();
mCalendar.setTimeInMillis(time);
int mHour=mCalendar.get(Calendar.HOUR);                        //小時
int mMinuts=mCalendar.get(Calendar.MINUTE);                 //分
int mSecond = mCalendar.get(Calendar.SECOND);             //秒
int mMilliSecond = mCalendar.get(Calendar.MILLISECOND);  //千分之1秒

Java - String split 拆解字串用法(含dot)

如果想要把字串,依據某字串拆解開來,可以使用split。程式如下:

String tempString="aaa:bbbb:ccc:ddddd";
String[] splitStringArray = tempString.split(":");

for (String splitString:splitStringArray){
    Log.d("gill", splitString);
}

則輸出
aaa
bbbb
ccc
ddddd

如果想要拆解的依據是特殊字元的話,則要在前面加上\ 
例如:
\b  \t  \n  \f  \r  \"  \'  \\

最後要注意的是,如果要拆解的依據是句點,也就是 "."
則要使用
\\.

Java - 字串 包含另一 字串 的檢查 indexof

如果要檢查某一字串是否有出現在某一字串,可以用string類別內的indexof,如果回傳值為-1,就表示沒有出現。如果不為-1,就表示有出現。舉例來說

string longString = "abcdefg";
string shortString = "cd";
string errorString="ck";

int havePosition = longString.indexof(shortString);
int noPosition = longString.indexof(errorString);

havePosition的值會等於2,即第1次出現的索引位置。
noPosition的值會等於-1,表示longString裡面不包含errorString這個字串。

Android - database query (2) boolean 布林值查詢

在sqlite中,存入欄位的布林值,並不是用true或是false,而是轉成字串的"1"和"0"來代替。
假設有一table如下:

name    |    isBoy
-----------------------------
Gill              1
Mary           0
Tom            1
Jenny           0

所以在下查詢條件想要找出所有男生姓名時,可以如下程式:
        Cursor cursor = this.getContentResolver().query(myURI,
                     new String[] {"name"},
                     "isBoy=?",new String[] {"1"}, null);

其中的myURL依據你自已資料來源來決定其URI。布林值要用"1"或是"0"去查,如果用"true"或是"false"是查不到的。

Android - database query (1) 模糊查詢

大家應該都知道如何使用query查詢條件,例如此篇文章所述。如果需要進行模糊查詢,則是把

=?改成是 like ?


例如table如下:
studentName |  studentNumber |  studentScore

Gill                      1                                60
Tom                    2                                100
John                    3                                70
Mary                   4                                80
Gary                    5                                30

如果想要找出名字中間有ar的資料,並依分數由高往低排序,程式寫法如下:

String likeString = "%" + "ar" + "%";

cursor = getContentResolver().query(uri, new String[]{"studentName,studentNumber,studentScore"}, "studentName like?", new String[]{likeString}, "studentScore desc");

Android - 偵測某網址是否可以正常連線 (HttpURLConnection)

如果你想要測試某個網址是否可以正常的連線,你可以使用:

int count = 0;
while (count < 5) { 
    try {
        URL myUrl = new URL("http://www.google.com");
        HttpURLConnection myConnection =
                                         (HttpURLConnection) myUrl.openConnection();
        myConnection.setConnectTimeout(5000);
        int state = myConnection.getResponseCode();
        if (state == 200) {
            Log.d("gill","the address is available!");
        }
        break;
    } catch (Exception ex) {
        count = count + 1;
    }
    Log.d("gill","the address is unavailable!");
}

getResponseCode() will return:
200 : connect normally
404 : can't connect
-1 : can't detect the result

設定setConnectTimeout(5000)表示連線5秒還沒成功就放棄。

2011年12月28日 星期三

Android - Bitmap 轉 Drawable

要把Bitmap轉成Drawable可以接受的格式時,假設myBitmap為一Bitmap物件,程式如下:

Drawable myDrawable = new BitmapDrawable(myBitmap);

Android - Json解析 (Json String parser)

JSON為新一代的資料傳輸格式,這裡有一篇文章對XML和JSON進行了清楚的比較。下面的程式透過JSONObjectJSONArray展示出如何解析放在SD卡裡面的JSON資料,檔名取為json_file。
下面為json_file的內容
{
    "student num":"3",
    "student":
    [
      {"name":"Gill",
       "age":"15"},
      {"name":"Tom",
       "age":"14"},
      {"name":"John",
       "age":"17"}
    ]
}

讀取JSON的觀念是針對每個Key去讀取其Value的,可以想像{}裡面就是一個JSONObject。而因為JSON裡面的資料可以像陣列般包含多項內容,這時候就用getJSONArray一口氣全部抓出來。大致上的流程是

(1)建立字串:內容為JSON所有的資料

(2)利用上述字串建立JSONObject

(3)利用JSONObjec取得資料 : 像是利用getInt(),getString()....等

(4)如果要解析的資料是陣列式的 : 先利用getJSONArray取出JSONARRAY後,再配合for迴圈把每個細項也就是JSONObject建立起來出來。有了JSONObject要讀資料,就和步驟(3)一樣。


程式碼如下:
public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        startParser();
    }

    public void startParser() {
        try {
            String jsonString = readJsonFile();       
            JSONObject jsonResponse = new JSONObject(jsonString);             
     
            //直接由JSONObject取出資料
            Integer studentNum = jsonResponse.getInt("student num");
            Log.d("Test","The number of student is :" + studentNum);
           
            //處理陣列型式的資料要多一個步驟
            //就是先建立JSONArray,再搭配for迴圈建立JSONObject
            JSONArray jsonArray = jsonResponse.getJSONArray("student");
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                Log.d("Test","The name value is :" + jsonObject.getString("name"));
                Log.d("Test","The age value is :" + jsonObject.getString("age"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
    //這裡先將檔案json_file裡的內容讀出,再轉換成字串
    private String readJsonFile(){
        FileInputStream fin;
        String returnString = "";
        try {
            fin = new FileInputStream(new File("sdcard/tmp/json_file"));
            byte[] buffer = new byte[fin.available()];
            while (fin.read(buffer) != -1) ;
            returnString = new String(buffer);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return returnString;
    }
}

執行結果如下:

Android - xml 解析 (XmlPullParser)

某些需要從網站下載xml資料,進行解析的程式。個人建議將解析的流程寫在一個Service裡面,如此一來才不會影響使用者當下操作的畫面。當解析完畢時,再將所需的資料丟給所需要的Activity或是DB或是進行處理。下面程式利用XmlPullParserFactoryXmlPullParser來對SD卡裡面的XML格式資料進行解析。採用XmlPullParser的好處是,如果網站下載的xml太大,而我們只需要前面一部份的資料時,就可以隨時停止解析。但是SAXParser則沒有辦法解析到一半就停止。
舉 例來說: 為了避免使用者等待太久,網頁的呈現一開始只有一部份資料,下方也許有一個Button叫「更多資料」。按下Button後,整個畫面會往下呈現全部資 料。像這種情形,就可以利用XmlPullParser在一開始先解析一部份的資料就好,以避免因解析大量XML而導致等待時間太久。


/**
* Start to parse the contents of xml file.
* The order of getEventType() is as follows,
* 1) XmlPullParser.START_DOCUMENT
* 2) XmlPullParser.START_TAG
* 3) XmlPullParser.TEXT
* 4) XmlPullParser.END_TAG
* 5) XmlPullParser.END_DOCUMENT
* The item2,itm3 and item 4 may be a loop
*/
public void startParser() {
   XmlPullParserFactory parserFactory;
   XmlPullParser pullParser;
   try {
       parserFactory = XmlPullParserFactory.newInstance();
       parserFactory.setNamespaceAware(true);
       pullParser = parserFactory.newPullParser();

       FileReader fileReader = new FileReader("sdcard/tmp/xml_file.xml");
       pullParser.setInput(fileReader);

       int eventType = pullParser.getEventType();

       int dataNum = 0 ;
       while (eventType != XmlPullParser.END_DOCUMENT) {

           if (eventType == XmlPullParser.START_TAG){
               Log.d("Test","the tag name is :" + pullParser.getName());
           }else if(eventType == XmlPullParser.TEXT ){
              Log.d("Test","the text value is :" + pullParser.getText());
              dataNum = dataNum + 1;    //讀到一筆資料了
           }
  
           if(dataNum <= 10){
               eventType = pullParser.next(); //往下一個Tag進行分析
           }else{
               break;    //讀到10筆資料後,就離開while迴圈
           }

       }
   } catch (XmlPullParserException e) {
       e.printStackTrace();
   } catch (IOException e) {
       e.printStackTrace();
   }
}

XmlPullParser詳細用法請參考原文:http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html

Java - callback function(2)

現在,讓我們用callback function的概念,來實作一個程式。這支程式有四個.java,如下:

CallBackClass.java : 裡面有一個Interface叫CallBackInterface,並包含一個function,名為ShowSomething(),ShowSomething的內容在未來會被完成。

FatherClass.java : 呼叫CallBackClass中的ShowSomething()。

Main1.java : 繼承FatherClass,並implements CallBackInterface完成ShowSomething()內容,就是出現toast。

Main2.java : 繼承FatherClass,但本身不直接implements CallBackInterface,而是另外實作CallBackInterface的實體,並在此實體完成ShowSomething()內容,就是 出現AlertDialog,這和Main1是不同行為。

完整程式碼如下:

public class CallBackClass{
    public CallBackInterface myCallBackInterface;
    public interface CallBackInterface {
        //目前還不知道要做什麼事,未來會有人implements這個Interface
        //自然就要決定ShowSomething()到底要做什麼
        void ShowSomething(String title);
    }   
   
    public void startCall(String title){
        if(myCallBackInterface!=null){
            Log.d("TestCallBack","CallBackClass/startCall()");
            myCallBackInterface.ShowSomething(title);
        }
    }
}


public class FatherClass extends Activity{
    CallBackClass myCallBackClass;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d("TestCallBack","FatherClass/onCreate()");
        super.onCreate(savedInstanceState);
        myCallBackClass = new CallBackClass();
    }
   
    public void setSomething(String title){
        Log.d("TestCallBack","FatherClass/setSomething()");
        myCallBackClass.startCall(title);
    }
}

public class Main1 extends FatherClass implements CallBackClass.CallBackInterface {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d("TestCallBack","Main1/onCreate()");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);       
       
        super.myCallBackClass.myCallBackInterface = this;
        super.setSomething("This is Main1 Title!");
       
        Button btn = (Button) findViewById(R.id.Button01);    
        OnClickListener lis = new OnClickListener() {       
            public void onClick(View v) {
                Intent it = new Intent();
                it.setClass(Main1.this, Main2.class);   
                startActivity(it);
            }
        };
        btn.setOnClickListener(lis);   
    }

    public void ShowSomething(String title) {
        // 這個ShowSomething()是因為implements CallBackClass.CallBackInterface這個介面
        // 所以一定要完成的method
        Log.d("TestCallBack","Main1/ShowSomething()");
        Toast.makeText(this, title, Toast.LENGTH_LONG).show();
    }
}

public class Main2 extends FatherClass {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main2);
       
        CallBackClass.CallBackInterface anotherWay = new CallBackClass.CallBackInterface(){
            public void ShowSomething(String title) {
                // 這個ShowSomething()是因為用 anotherWay去實作CallBackClass.CallBackInterface這個介面
                // 所以一定要完成的method,不同於Main1,這裡改用AlertDialog
                  new AlertDialog.Builder(Main2.this)
                    .setTitle(title)
                    .setMessage("ShowSomething()相同"+"\n"+"在Main1和Main2各自有不同的行為!")
                    .show();
            }          
        };
        super.myCallBackClass.myCallBackInterface = anotherWay;
        super.setSomething("This is Main2 Title!");
    }
}

執行結果如下:
執行一開始
來到Main2,卻是AlertDialog




















以這個例子來回顧一下,我們需要那些東西來完成callback function的架構
(1)一個interface (CallBackInterface),內含一個function(ShowSomething),其內容在未來會被完成(由Main1和Main2的anotherWay完成)。

(2) super.myCallBackClass.myCallBackInterface = this; 這行是一定要的。因為必需讓這個Interface有實體的產生,這樣才知道是誰完成了ShowSomething()的內容。本例中因為是 Main1implements CallBackClass.CallBackInterface,所以this指的就是Main1。

(3) 另外super.myCallBackClass.myCallBackInterface = anotherWay;則是因為anotherWay是CallBackInterface的實體,因此當要呼叫ShowSomething時,就是到 anotherWay裡面去找ShowSomething的內容。

Main1和Main2的2種寫法,就是常常看到的事件觸發(如Button Event)的寫法。

最後附上Main1執行的log,以便清楚了解程式的流程:
D/TestCallBack( 1522): Main1/onCreate()
D/TestCallBack( 1522): FatherClass/onCreate()
D/TestCallBack( 1522): FatherClass/setSomething()
D/TestCallBack( 1522): CallBackClass/startCall()
D/TestCallBack( 1522): Main1/ShowSomething()

Java - callback function(1)

常常聽到callback function這個名詞,這種技巧不限定於Java,C++或.net也有各自的寫法。但精神是相同的。call function就像是直接呼叫某個function去執行該function內的程式碼。例如:

public void doSomething(){
  //doSomething()被呼叫了,來做一些事情
}

public void main(){
     doSomething();
}



而callback function就像是在未來發生某種觸發原因後,才會去執行的程式。最常見的就是像Button的onClick事件處理。舉例來說:  

        OnClickListener lis = new OnClickListener() {       
            public void onClick(View v) {
                //按下按鈕後,做一些事情
            }
        };
        Button.setOnClickListener(lis);

你 在別的地方已經先定義好一個Interface叫OnClickListener,裡面有個方法叫onClick()。onClick()就是處理 Button被按下後的callback function應用。你不可能先在OnClickListener這個Interface內把onClick()寫死,而是在未來的程式碼內,依不同的 情況,實作一個OnClickListener,然後把onClick()程式碼的內容完成。最後把這個OnClickListener的實體(如 lis)設定某人(Button)使用,像這種架構就是callback function。

2011年12月26日 星期一

Java - IndexOf 和 lastIndexOf 用法

lastIndexOf(char ch) 可以找尋某字串中,最後一次出現ch字元的位置。位置的起始由0開始。舉例:
String tempString = "This is a good book".
System.out.println("第一次出現o的位置是: "+tempString.IndexOf('o')+" !!");
System.out.println("最後一個o的位置是: "+tempString.lastIndexOf('o')+" !!");

則會印出:
第一次出現o的位置是: 11 !!
最後一個o的位置是: 17 !!

如果字串中找不到該字元,則會回傳-1