visited 13 states (5.77%)
Create your own visited map of The World or Triposo world travel guide for Android

2014-09-25

Android應用程式讀寫SD上的檔案

檔案讀寫的方式有很多種,這邊放了兩個函式範例可以測試讀寫SD卡上的檔案。
//寫檔範例
ublic void writeDataToSD(){  
try{  
    

    File file  = new File(Environment.getExternalStorageDirectory(),"test.txt");  
  
    /* 判斷外部裝置是否可以讀寫 */  
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  
          
        /* 輸出資料緩衝區*/
        FileOutputStream fos = new FileOutputStream(file);  
  
        /* 寫入的資料*/  
        String message = "Test";  
  
        /* 將資料轉成byte 模式*/  
        byte[] buffer = message.getBytes();  
  
        /* 寫入資料*/  
        fos.write(buffer);  
  
        /* 關閉緩衝*/  
        fos.close();  
        Toast.makeText(MainActivity.this, "檔案寫入成功", 1000).show();  
    }  
  
}catch(Exception ex){  
    Toast.makeText(MainActivity.this, "檔案寫入失败", 1000).show();  
}  

//讀檔範例
public void readDataFromSD(){  
    try{  
          
        /* 設定檔案*/  
        File file = new File(Environment.getExternalStorageDirectory(),"test.txt");  
          
        /* 輸入資料緩衝區 */  
        FileInputStream fis = new FileInputStream(file);  
          
        /* 準備一個byte biffer用來存讀入的資料*/  
        byte[] buffer = new byte[fis.available()];  
          
        /* 讀取資料*/  
        fis.read(buffer);  
          
        /* 關閉緩衝  */  
        fis.close();  
          
        /* 將資料轉成UTF-8格式*/  
        String res = EncodingUtils.getString(buffer, "UTF-8");  
          
        Toast.makeText(MainActivity.this, "檔案讀取成功,data:"+res, 1000).show();  
          
    }catch(Exception ex){  
        Toast.makeText(MainActivity.this, "檔案讀取失败!", 1000).show();  
    }  
}

Android中File元件的各種應用

在File的運用當中, 若需要讀取到外部  憶體(SD卡), 得加入以下權限才不會crash


//check SDCard is exist or not
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
Environment.getExternalStorageState(): mounted
Environment.MEDIA_MOUNTED: mounted

//取得SD卡路徑
File SDCardpath = Environment.getExternalStorageDirectory();
ex: /mnt/sdcard

//建立資料夾
File mSDCardFile = new File( SDCardpath + "/mSDCardData" );
//判別該File  是否存在  boolean java.io.File.exists();
if( !mSDCardFile.exists() ) 
{
    //若該資料夾不存在, 則用mkdirs()建立 boolean java.io.File.mkdirs()
    //makirs上層資料夾若不  在則自動創建, mkdir則不會
    mSDCardFile.mkdirs();
}

<<建立檔案>>
File mSDCardDoc = new File( SDCardpath + "/mSDCardData.txt" );
//判別該File是否存在 
if( !mSDCardDoc.exists() ) 
{    
    try
    {
        //若該檔案不存在, 則用createNewFile()建立 
        // boolean java.io.File.createNewFile() throws IOException
            mSDCardDoc.createNewFile();
    } 
    catch (IOException e)
          {
            e.printStackTrace();
          }
}
--------------------或--------------------
try
{
      FileWriter mFileWriter = new FileWriter( SDCardpath.getAbsolutePath() + "/mSDCardData.txt" );
} 
catch (IOException e)
{
      e.printStackTrace();
}

//取得路徑(File→String)  String java.io.File.getAbsolutePath();
mSDCardFile.getAbsolutePath()

//取得上一層路徑(File→String)  String java.io.File.getParent()
mSDCardFile.getParent();

//判別是否為目錄
boolean isDirectory = mSDCardFile.isDirectory();

//判別是否為檔案
boolean isFile = mSDCardFile.isFile();

//將old.txt重新命名為new.txt
String oldPath = "/mnt/sdcard/old.txt"; 
String newPath ="/mnt/sdcard/new.txt";
File oldFile = new File( oldPath ); 
oldPath.renameTo(new File(oldFile));

//刪除檔案
mSDCardFile.delete();

//判別是否可讀
boolean canRead = file.canRead();

//判別是否可寫
boolean canWrite = file.canWrite();

//檔案寫入內容
FileWriter vFile;
try
{
    vFile = new FileWriter( "/mnt/sdcard/new.txt" );
    vFile.write("要寫一些內容");
    vFile.close();
} 
catch (IOException e) 
{
    e.printStackTrace();
}

//讀取檔案內容
try 
{
    String file = "/mnt/sdcard/new.txt";
    InputStream input = new BufferedInputStream(new FileInputStream(file));
    int res = input.available();
    byte [] byte = new byte[res];
    input.read(byte);
    //把類型設為UTF-8才能正常讀取中文字! 
    String text = EncodingUtils.getString(byte, "UTF-8");
} 
catch (IOException e) 
{
    e.printStackTrace();
}

//判別是否為隱藏檔
boolean isHidden = file.isHidden();

//以File[]儲存指定路徑下所有項目的路徑
File[] files=new File(SDCardpath.getAbsolutePath()).listFiles();

//列出所有項目的路徑
//用長度為files.length的迴圈找出  
    files[i];

--------------------或--------------------
for( File f : files )
{
     f.getPath();
}

//列出所有項目
//用長度為files.length的迴圈找出  
      files[i].getName();
--------------------或--------------------
for( File f : files )
{
    // String java.io.File.getName()
    f.getName();
}

//以關鍵字搜尋目標
//以result儲存搜尋結果
String result="";
for( File f : files )
{
    // int java.lang.String.indexOf(String string)
    if(f.getName().indexOf(keyword)>=0)//回傳在第幾個字找到keyword, 若都沒找到則回傳0
    {  
            result+=f.getPath()+"\n";
    }
}

補充:程式中可以java.io.File.separator來表示字串"/"


2014-09-24

Android應用程式中不預設focus於EditText元件的方法

加上兩行於 activity_main.xml (反正就是最主要的xml file)

android:focusableInTouchMode="true"  //設定該內本身可以被 focus
android:descendantFocusability="beforeDescendants" //代表其取得 focus 的順序優先於其子物件

之後在主程式 protected void onCreate(Bundle savedInstanceState) 中加上

private EditText edit1;
edit1-> (EditText)findViewById(R.id.Edittext1);
edit1->clearFocus();

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
 
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
>

得到Android裝置的銀幕解析度

此程式主要是得到銀幕的解析度並顯示出來
example.java

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

public class example0305 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);   //全螢幕設定
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
    WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.main);

    DisplayMetrics metrics = new DisplayMetrics();  
    getWindowManager().getDefaultDisplay().getMetrics(metrics);

    TextView TextView1 = (TextView)findViewById(R.id.TextView01);
    TextView1.setText("手機銀幕大小為 "+metrics.widthPixels+" X "+metrics.heightPixels);
  }
}

main.xml

xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView 
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
android:id="@+id/TextView01"
android:textSize="20sp"
/>
</LinearLayout>

程式主要的重點在於 
import android.util.DisplayMetrics; 

DisplayMetrics metrics = new DisplayMetrics(); 

getWindowManager().getDefaultDisplay().getMetrics(metrics);

2014-09-19

Android手機或平板ADB Interface Driver安裝與實機測試APK

有時候會需要把自行開放的Android APK放到手機或平板上測試,不必再使用模擬器消耗電腦效能,這時候就需要這套ADB Interface Driver讓手機或平板能與你電腦上的開發環境(大多數都是Eclipse)連結,將程式丟上裝置上執行。以下是幾個重要流程:

1. 將手機內的「開發人員選項」打開,如是找不到,請多點幾次關於手機裡面的版本號碼,將隱藏的開發人員選項打開。找到並開啟「USB除錯模式」與「安全性」中的「安裝來源不明的應用程式」。以上的設定位置會因各版本Android Kernel有些微差異,但選項應該都會有。


2010-8-27 下午 04-41-22
2010-8-27 下午 04-41-34

2. 將手機透過可以傳輸檔案的USB線與電腦連結,應該可以看到裝置管理員出現一個未知的裝置Android phone,select 「Update Driver Software」再選「Browse my computer for driver software」,然後選到你所下載解開的driver資料夾,裡面應該會有android_winusb.inf、androidwinusb86.cat、androidwinusba64.cat,與amd64、i386資料夾,當然也有人建議透過SKD manager來下載driver,不過我偏好自己另外安裝。



若是無法安裝,就用特殊技巧,打開裝置管理員看這支手機的PID/VID,例如MT65XX的手機,可從 Device Manager -> 選擇Android Device -> 右鍵 Properties Details-> Hardware Ids ->確認PID & VID,可以知道VID=0x19D2,PID=0x0C02,之後就可以編輯android_winusb.inf檔案,新增以下兩行於[Google.NTx86]或是[Google.NTamd64]下,視你的電腦系統而定,之後應該可以順利安裝。


%SingleAdbInterface% = USB_Install, USB\VID_19D2&PID_0C02
%CompositeAdbInterface% = USB_Install, USB\VID_19D2&PID_0C02&MI_01



3. 在你的Eclipse開發環境上,將想要放在實體裝置執行的程式,在Run Configurations.. -> Target -> Always prompt to pick device。

publishandroid1


4. 如果一切順利,在你Run As -> Android Application的時候,應該會跳出下圖選項,選擇你的手機,接著就可以在手機上看到你所寫的APK了。

8.JPG

2014-09-18

Android切換Activity與頁面layout

假設手機頁面切換只需要置換背景圖示、文字顏色及內容排版等等,只需要用到setContent就可以置換layout,但如果是要切換Activity就不能只換layout,需要移交主控權到另外一個Activity,移交主控權的方法,可在主程式裡使用startActivity()這方法來呼叫另外一個Activity,但是關鍵並不是在這一個startActivity這個方法,而是在Intent(就如同英文字意一樣,想要、企圖之意)這個物件,告訴主程式自己是什麼,想要到什麼地方去,這就是intent物件所處理的事。

Java檔 (兩個Activity兩個class)
第一個class TestExam001.java

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class TestExam001 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main001);
Button button = (Button)findViewById(R.id.button01);
button.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(TestExam001.this, TestExam002.class);
startActivity(intent); 
TestExam001.this.finish();
}
});
}
}

第二個class TestExam002.java
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class TestExam002 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main002);
Button button = (Button)findViewById(R.id.button02);
button.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(TestExam002.this, TestExam001.class);
startActivity(intent); 
TestExam002.this.finish();
}
});
}
}


XML檔 (兩個Activity兩個對應的layout)

第一個layout main001.xml

xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" Activity 001"
android:textSize="50sp"
/>
<Button
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:id="@+id/button01"
android:text="Go to Activity 002"
android:textSize="17sp"
/>
</LinearLayout>
以上的layout檔案可以類推出layout main002.xml


AndroidManifest.xml檔
Hint:請記得在AndroidManifest.xml添增一個新的activity並給予名字,否則會出錯喔!然而在一個程式內架設有多個Activity,系統要如何決定以哪一個為entry point?AndroidManifest.xml內有一行為

<category android:name="android.intent.category.LAUNCHER" />

 這就表示程式會先執行這一個Activity


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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.sam.test"

      android:versionCode="1"

      android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".TestExam001"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <activity android:name=".TestExam002"></activity>

    </application>

</manifest>
Ps.這兩個java程式在最後都使用finish()這方法,代表這個activity已經運行完畢,當系統接收到這一個指令的時候會關閉此activity,如果這時手機按下back按鍵,並不會回復到上一個Activity的畫面,如果需要讓使用者在按下back可以回到之前的畫面,就必須將這一個finish()刪掉。

device043device044

2014-09-11

Eclipse出現ADB server didn’t ACK的解決方案

解決辦法一般是在工作管理員中找出adb.exe程序,然後重啟eclipse,不過有時候會找不到adb.exe這個程序。這時候可以透過adb使用的port 5037,看是否被其他程序占用,比如:91助手或者豌豆莢等。

可以透過指令 netstat -a -o 5037,確認是否有程式占用這個port


如上圖最後一列,看到127.0.0.1:5037有一個PID為4236的程式占用了,

再用指令 tasklist /fi “pid eq 4236″ 去確認這支程式的內容


確認沒錯後,就直接在工作管理員刪除掉,之後可以重新啟動 eclipse或是重新啟動adb.exe

提供兩個指令協助:

adb kill-server:啟動adb.exe

adb start-server:終止adb.exe

2014-09-05

列舉出目錄下所有檔案與搜尋特定副檔名

How to use ?

call "FindFileInDir(char* rootDir, char* extname, BOOL recursive)" in your code base, the function can filter folder path and file path

rootDir:search root directory (EX:"D:\\test\\")
extname:filename extension (EX:".exe")
recursive:the decide to search sub-directory or not (EX:"true")

EX1:FindFileInDir("D:\\test\\", ".exe", true);  // to search every *.exe file under "D:\test\" directory
EX2:FindFileInDir("D:\\", "", false); // to search every file under "D:\" directory , but don't search in sub-directory

function:

void FindFileInDir(char* rootDir, char* extname, BOOL recursive)//, char* strRet)
{
        char fname[1024];
        ZeroMemory(fname, 1024);
        WIN32_FIND_DATA fd;
        ZeroMemory(&fd, sizeof(WIN32_FIND_DATA));
        HANDLE hSearch;
        char filePathName[256];
        char tmpPath[256];
        ZeroMemory(filePathName, 256);
        ZeroMemory(tmpPath, 256);
        strcpy(filePathName, rootDir);
        char extFileName[256];
        ZeroMemory(extFileName, 256);
        strcpy(extFileName, extname);

        BOOL bSearchFinished = FALSE;
        if( filePathName[strlen(filePathName) -1] != '\\' )
        {
                strcat(filePathName, "\\");
        }
        strcat(filePathName, "*");
        hSearch = FindFirstFile(filePathName, &fd);
        //Is directory
        if( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..") )
        {
                strcpy(tmpPath, rootDir);
                strcat(tmpPath, fd.cFileName);
                if( tmpPath[strlen(tmpPath) -1] != '\\' )
                {
                        strcat(tmpPath, "\\");
                }
                if(recursive == true)
                {
                FindFileInDir(tmpPath, extFileName, recursive);
                }
        }

        while( !bSearchFinished )
        {
                if( FindNextFile(hSearch, &fd) )
                {
                        if( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..") )
                        {
                                strcpy(tmpPath, rootDir);
                                strcat(tmpPath, fd.cFileName);
                                if( tmpPath[strlen(tmpPath) -1] != '\\' )
                                {
                                        strcat(tmpPath, "\\");
                                }
                                printf("Folder : %s\n", tmpPath); // show folder path
                                if(recursive == true)
                                {
                                FindFileInDir(tmpPath, extFileName, recursive);
                                }
                        }
                        else if( strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..") )
                        {
                                if(strstr(fd.cFileName, extFileName))
                                {
                                        printf("File : %s%s\n",rootDir,fd.cFileName);  // show file path
                                }
                        }
                }
                else
                {
                        if( GetLastError() == ERROR_NO_MORE_FILES )
                        {
                                bSearchFinished = TRUE;
                        }
                        else
                        {
                                bSearchFinished = TRUE;
                        }
                }
        }
        FindClose(hSearch);
}




2014-09-04

BCB應用於三種取出圖片像素之RGB值的方法與速度比較


1. 創立一 BCB project。
2. 拉出三個Button(命名可自訂或參考以下範例),一個Memo用來輸出訊息,一個Image物件輸入圖片影像。
3. 於Image物件中的picture屬性指定一個影像來源(BMP / JPG),當然還有很多可以載入圖片的方法,如用OpenDialog或是直接在程式內設定檔案路徑等,不過並不是本文重點。

以下為程式碼:


//---------------------------------------------------------------------------

#include
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
        Image1->Height = Image1->Picture->Bitmap->Height;
        Image1->Width = Image1->Picture->Bitmap->Width;
        Memo1->ScrollBars = ssVertical;
        Image1->Picture->Bitmap->PixelFormat = pf24bit;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button_scanlineClick(TObject *Sender)
{
        int cur_time, r, g, b;
        String str;
        BYTE *ptr;
        cur_time = GetTickCount();
        for (int i = 0; i < Image1->Height; i++)
        {
                ptr = (Byte*)Image1->Picture->Bitmap->ScanLine[i];
                for (int j = 0; j < Image1->Width; j++)
                {
                        b = ptr[3*j];
                        g = ptr[3*j+1];
                        r = ptr[3*j+2];
                }
        }
        str.sprintf("processing time : %0.3f",(float)(GetTickCount()-cur_time)/1000);
        Memo1->Lines->Add(str);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button_PixelsClick(TObject *Sender)
{
        int cur_time, r, g, b, color;
        String str;
        cur_time = GetTickCount();
        for (int i = 0; i < Image1->Height; i++)
        {
                for (int j = 0; j < Image1->Width; j++)
                {
                        color = Image1->Canvas->Pixels[j][i];
                        b = (color&0xFF0000) >> 16;
                        g = (color&0x00FF00) >> 8;
                        r = (color&0x0000FF);
                }
        }
        str.sprintf("processing time : %0.3f",(float)(GetTickCount()-cur_time)/1000);
        Memo1->Lines->Add(str);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button_GetRGBClick(TObject *Sender)
{
        int cur_time, r, g, b;
        String str;
        cur_time = GetTickCount();
        for (int i = 0; i < Image1->Height; i++)
        {
                for (int j = 0; j < Image1->Width; j++)
                {
                        b = GetBValue(Image1->Canvas->Pixels[j][i]);
                        g = GetGValue(Image1->Canvas->Pixels[j][i]);
                        r = GetRValue(Image1->Canvas->Pixels[j][i]);
                }
        }
        str.sprintf("processing time : %0.3f",(float)(GetTickCount()-cur_time)/1000);
        Memo1->Lines->Add(str);
}
//---------------------------------------------------------------------------


可以看出第一種方是用ScanLine[i]抓取每列像素的方式速度最快,然後用內建的GetBValue等函是最慢,應該是被包裝太多層的原因,所以導致執行效率較差,取出的RGB值看是要用動態二維陣列,還是另行處理後寫檔就各自發揮。另外要注意的是由於只需要RGB的資料,所以可以指定 Image1->Picture->Bitmap->PixelFormat = pf24bit,若是指定為pf32bit,則ScanLine讀回來的每組資料會由4 Bytes組成。