2014年5月7日 星期三

Simple .gitignore for Android Studio projects


This is my short .gitignore file for Android Studio projects,

It should be suitable most of the android studio projects.



# build application files
*.apk
*.ap_

#files for the VM
*.dex

# generated files
bin/
gen/


#Java class files
*.class

#Local configuration file (sdk path, etc)
local.properties

# Eclipse project files
.classpath
.settings


# Intellij project files
*.iml
*.ipr
*.iws
.idea/


# Android Studio
.idea/
.gradle
/*/local.properties
/*/out
/*/*/build
/*/*/production
*.iml
*.iws
*.ipr
*~
*.swp

2014年4月28日 星期一

Android中從URL取得JSON格式

首先要先搞清楚其JSON Structure 並了解其JSONObject與JSONArray所盼演的角色,看底下圖。




想要在Android當中從URL取得JSON格式,大概需要執行以下步驟:



      1. 增加網路權限,在AndroidManifest.xml當中加入以下:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      2. 使用HttpClient與HttpResponse方法Parse URL並取得JSON String。


      3. 建立JSONObject與JSONArray來處理JSON String。


      4. 從JSONObject與JSONArray取出你要的資料。



請記得一定要使用AsyncTask來處理,因為這是UI Thread。


以下為具體程式碼:

其中我們要取得的JSON格式來源:http://hmkcode.appspot.com/rest/controller/get.json

{"articleList":
    [{
        "title":"Android Internet Connection Using HTTP GET (HttpClient)",
        "url":"http://hmkcode.com/android-internet-connection-using-http-get-httpclient/",
        "categories":["Android"],
        "tags":["android","httpclient","internet"]
    },
    {
        "title":" Android | Taking Photos with Android Camera ",
        "url":"http://hmkcode.com/android-camera-taking-photos-camera/",
        "categories":["Android"],
        "tags":["android","camera"]
    }]
}



java程式中的AsyncTask核心部份:
private class HttpAsyncTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... urls) {
        return GET(urls[0]);
    }
    // onPostExecute displays the results of the AsyncTask.
    @Override
    protected void onPostExecute(String result) {
        try {
            JSONObject json = new JSONObject(result);

            String str = "";

            JSONArray articles = json.getJSONArray("articleList");
            str += "articles length = "+json.getJSONArray("articleList").length();
            str += "\n--------\n";
            str += "names: "+articles.getJSONObject(0).names();
            str += "\n--------\n";
            str += "url: "+articles.getJSONObject(0).getString("url");
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private  String GET(String url){
        InputStream inputStream = null;
        String result = "";
        try {

            // create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // make GET request to the given URL
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            // receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // convert inputstream to string
            if(inputStream != null)
                result = convertInputStreamToString(inputStream);
            else
                result = "Did not work!";

        } catch (Exception e) {
            Log.d("InputStream", e.getLocalizedMessage());
        }

        return result;
    }

    private  String convertInputStreamToString(InputStream inputStream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
        String line = "";
        String result = "";
        while((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();
        return result;

    }
}             


其使用方式很簡單,在你的主程式當中加入以下調用:

new HttpAsyncTask().execute("http://hmkcode.appspot.com/rest/controller/get.json");

上述當中以及實現了從URL中取得JSON格式,並放至str中,我這裡是沒有將他印出,而你當然可以使用Log印出看看str,或者是你想顯示在圖形界面,隨便你。



Reference:



2014年4月15日 星期二

兩個device 利用 Uart 傳輸當中所必須注意到的問題

玩嵌入式系統當中,最一開始就要先解決傳輸問題,而最常見的就是將兩個device透過uart傳輸,傳輸過程中必須要注意一個小部份,就是"\n"換行符號,


假設說有device A, device B 而deviceA定義一個thread每一秒就會透過uart訊號傳出去,例如:

void uart_puts(void *p){
        while(1){
        printf("”Hello Device B");
        Delay(1000);
        }
}


而接收方Device B 透過下列程式去接收:

while(1){
  do
  {
   n = read(fd_uart, (void*)&c, 1);
   if (n < 0) {
    perror("Read failed - ");
    return -1;
   }else if (n == 0) /*indicates end of file*/
    printf("end of file\n");
   else{ /*n>0 means have received data.*/
    buf[cnt++] = c;
     
   }
  }
  while(n>0 && cnt<14 && c!='\n');
  buf[cnt]='\0';
  printf("%d bytes read : %s\n", cnt, buf);
                cnt = 0;
}


若是以上的方式的話,DeviceB的輸出結果並不會如期的一秒鐘顯示一次"Hello Device B",而是過了一段時間才會印出一大堆的"Hello Device B" ,  原因是因為在Device A之傳送端中,沒有加上"\n"換行符號,因為對於printf來說他會先輸出到你指定的裝置,但是會先暫存到buffer之中,直到他收到了換行符號,他才會刷新整個buffer,故此程式碼當中,沒有換行符號他就是一直塞buffer,直到緩衝區的大小滿了,才會刷新整個buffer,因此Device B才會一次出現一大堆的資料,只要在Device A中加上換行符號即可。


printf("”Hello Device B\n");


當然你也可以用標準方法,使用fflush函數,強制清空buffer且輸出buffer:

flush(stdin)刷新標準輸入緩衝區,把輸入緩衝區裡的東西丟棄   
fflush(stdout)刷新標準輸出緩衝區,把輸出緩衝區裡的東西打印到標準輸出設備上。



2014年3月11日 星期二

利用Google Translate 輸出的音效 下載成MP3

這很無聊,但由於有時候真的需要他的聲音.........好吧,還是紀錄一下。


很簡單,只要網址列輸入以下即可,輸入了就知道了不要問:

http://translate.google.com/translate_tts?tl=en&q="hello world"

or


http://translate.google.com/translate_tts?tl=zh&q="hello world"

一個是英文一個是中文。




Share the folder using by NFS Server for the Beagleboard-xM

目的:
PC與BB-xM 共享同一個資料夾,如此一來,若是需要在PC上Cross-compile就可以直接將執行檔放置此目錄夾,然後BB-xM就直接執行此資料夾的執行檔即可,不用在那邊每次compile完,就在那邊拔sd卡,很蠢。

首先在PC上建立環境:
----------------------------------------------------------------------------------------------------------------------

$sudo apt-get install nfs-common
$sudo apt-get install nfs-kernel-server

接著要設定nfs存取的權限與相關設定:

 sudo vi /etc/exports

在這邊舉我的例子,在/etc/exports裡面加入這行:

/home/jack/Desktop/nfstemp *(rw,no_root_squash,no_all_squash,sync)

nfstemp就是你在PC上所要共享的資料夾,後面的*代表是所有人都可以存取此資料夾,你也可以不要使用*,直接指定只有某個ip(實體ip)才可以存取你這個資料夾,後面的設定說明如下:

rw : read-write
no_root_squash      :   如果你想要開放用戶端使用 root 身份來操作伺服器的檔案系統,那麼這
                                    裡就得要開 no_root_squash 才行(引述鳥哥私房菜)。
no_all_squash :        保留共享文件的UID和GID(default)
sync :                        代表資料會同步寫入到記憶體與硬碟中,而async 則代表資料會先暫存於                                     記憶體當中,而非直接寫入硬碟!





接著就是在BB-xM中的設定了 , 屬於Client端。
----------------------------------------------------------------------------------------------------------------------
首先先說下我的環境,OS : Angstrom   ,  Kernel : linux kernel 2.6.32
然後要建立一個空的資料夾來共享,我在這邊習慣都是跟PC一樣的資料夾名稱,
接著輸入:

mount -o nolock 140.116.123.123:/home/jack/Desktop/nfstemp  nfstemp/
or

busybox mount -o nolock 140.116.123.123:/home/jack/Desktop/nfstemp  nfstemp/

前面的ip就是你要連結的server ip 然後存取他裡面的某個資料夾,並且共享他。

建議盡量寫一個script檔,不用每次都要輸入這些命令了。

#!/bin/sh                                                                     
#### this shell command is access host folder from NFS_server ####
busybox mount -o nolock 140.116.123.123:/home/jack/Desktop/nfstemp  nfstemp/

除此之外還可以將此script 在開機執行。

注意事項:當然BB-xM 也要給他網路囉....,同網域通常不會有什麼問題,可是如果是外網連進來共享就要考慮到有無防火牆,成大好像有。@@這就不關我的事情了,反正我只是為了在學校玩嵌入式方便用。



Reference:

  1. http://linux.vbird.org/linux_server/0330nfs.php
  2. http://hi.baidu.com/zzcqh/item/fa9ca6b6c2d2c977254b0914

2014年2月23日 星期日

「已解決」Android 自帶範例中的 BluetoothChat 會分段讀取的情況

Android 自帶的藍芽範例BluetoothChat很好用,
而且想因此學習bluetooth的原理與處理機制可以藉由這隻範例程式來研究,
但是我在測試Android  這隻BluetoothChat與其他裝置連線時(stm32f4 discovery) ,

問題來了:
  • 發現在stm32f4 送一段簡單的訊息 --> printf("This is a bug \r\n" );
而BluetoothChat接收端會有分段讀取的現象,例如一段message會拆成
          Thi 
          s is a b
          ug

          即使BluetoothChat 內部本身已經有處理掉char 與 byte的型別轉換,但是重點不在於這  
         裡,先來看BluetoothChat核心讀取端的程式碼:

public void run() {
            byte[] buffer = new byte[1024];
            int bytes;

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    // Read from the InputStream
                    bytes = mmInStream.read(buffer);

                    // Send the obtained bytes to the UI Activity
                    mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                            .sendToTarget();
                } catch (IOException e) {
                    //Error handling removed to simplify bug report
                }
            }
        }





首先先注意到這一行:

bytes = mmInStream.read(buffer);


如果你 Log 出 bytes , 你會發現就算你的other device傳送過來的指令都是一模一樣的字數,比如說固定就是傳10個char , 那你每一次在Android 這邊收到的bytes的字數都會不一樣,
這就是會分段的原因所在,所以當然你在Android 抓取一次的結果就是不完整的。

引述  Android Open Source Project - Issue Tracker

裡面提到了問題所在:
The problem is that "buffer" is reused, but obtainMessage(...) isn't guaranteed to be done with buffer by the time more data is available from the stream, and no defensive copy has been made of the buffer.


他的解決方法是將buffer定義在迴圈裡面,讓他每進入此迴圈都重新定義一個新的buffer,但是這不但會浪費多的資源,重點是我試了也沒用........還是會分段,所以再換別的方法。


我認為應該是要在迴圈內部裡面等待一段訊息全部傳完並且乾淨,才能夠當作有效的一段訊息,因此我修改程式如下:

public void run() {
            byte[] buffer = new byte[1024];
            int bytes;
            

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    String msg="";
                    
                    while(mmInStream.available()==0){
                        /*wait the message buffer*/
                    }
                    while (true){
                         // Read from the InputStream
                         bytes = mmInStream.read(buffer);
                                                  String temp_msg = new String(buffer,0,bytes);
                         msg+=_temp_msg;
                         if(mmInStream.available()==0)break;
                    }
                   
                    // Send the obtained bytes to the UI Activity
                    mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, msg)
                            .sendToTarget();
                } catch (IOException e) {
                    //Error handling removed to simplify bug report
                }
            }
        }



或者是這樣也可以,這個版本比較穩定(參照Ref  3),
只是我額外將格式改成了 ISO-8859-1 ,Code如下:

 public void run() {
        int bytes;
        byte[] buffer = new byte[1024];
        String end = "\n";
        StringBuilder curMsg = new StringBuilder();

        while (true){
            try {
                while (-1 != (bytes = mmInStream.read(buffer))) {
                    curMsg.append(new String(buffer, 0, bytes, Charset.forName("ISO-8859-1")));
                    int endIdx = curMsg.indexOf(end);
                    if (endIdx != -1) {
                        String fullMessage = curMsg.substring(0, endIdx + end.length());
                        curMsg.delete(0, endIdx + end.length());

                        // Now send fullMessage
                        // Send the obtained bytes to the UI Activity
                        mHandler.obtainMessage(ControlEPW_Fragment.MESSAGE_READ, bytes, -1, fullMessage)
                                .sendToTarget();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

上面的 end = "\n";   代表當我接收到一大串字串,只要收到了換行符號,就會送出去String給主Handler。


但是這裡要注意到我跟原始程式不同的是,原始程式傳出去是以byte[] object 傳出去主Handler ,而我是已String方式傳出去主Handler ,所以我在主Handler不用再轉一次String了 ,因此我把主Handler那裡將message 的 byte[] to String那一段拿掉,我想這不用在多說了。


附帶一提: 此修改程式在我的case下成功的,不會分段,若是有其他問題可以再回報與討論,Thanks.