分類
Uncategorized

ant build error: The SDK Build Tools revision (x.x.x) is too low for project 'MainActivity'. Minimum required is 19.1.0

Description:

Use ant to build android project and show error message like topic
 

Root Caused:

The SDK Build Tools revision (18.0.1) is too low for project ‘MainActivity’. Minimum required is 19.1.0
 

Solution:

1. open eclipse
2. launch Android SDK Manager
3. update to Minimum required version of SDK Build Tools

分類
Uncategorized

ant build error: build.xml does not exist!

Description:

when you created a android project and want to use “ant” to build project
 

Steps to Reproduce:

1.
After Created android project and use terminal to move root of project
2.
type ant in terminal
 

Error:

Buildfile: build.xml does not exist!
Build failed

 
 

Solution:

at root director of android project and type follow command
/your-android-sdk-path/tools/android update project -p .
then some message will show on terminal

Updated local.properties
No project name specified, using Activity name 'MainActivity'.
If you wish to change it, edit the first line of build.xml.
Added file ./build.xml
Updated file ./proguard-project.txt
It seems that there are sub-projects. If you want to update them
please use the --subprojects parameter.

 
 

分類
Uncategorized

使用 ant 手動產生 unsign apk

為了自動化建置的需求, 原先經由 Eclipse 產生 unsign apk 的方式必須改成手動產生
雖然在官網上有教學, 但過程中發生的問題卻隻字未提, 這篇就把發生的問題和解決過程紀錄下來
 
要產生 unsign apk, 根據官網所述, 只要移動到該專案目錄下並輸入

ant release

即可,在專案的bin資料夾就會產生unsign apk, 但沒有ant就不用玩了,所以先安裝 ant 吧, 輸入

sudo apt-get install ant

安裝完成後再輸入 ant release, 會出現

Buildfile: build.xml does not exist!
Build failed

是的, 必須要有 build.xml, 輸入以下指令來產生 build.xml

android update project -p .

注意: android 指的是在sdk/tools/ 下的 android , 必要的話請使用完整路徑來指定吧
完成後在專案目錄下就會產生build.xml
有了build.xml 再輸入 ant release 看看吧,出現

BUILD FAILED
/android-sdk-linux/tools/ant/build.xml:483: The SDK Build Tools revision (18.0.1) is too low for project 'MainActivity'. Minimum required is 19.1.0

果然~沒這麼簡單, 根據錯誤訊息去尋找 sdk/build-tools/ 真的只有18.0.1 資料夾,好吧~開啟eclipse sdk manager 更新 buildtool,
注意:只要勾選 19.0.1 就好其他不必安裝
螢幕擷圖存為 2014-11-27 16:18:36
下載完成後在sdk/build-tools/ 也會出現19.1.0 資料夾,再輸入 ant release 吧,出現

BUILD FAILED
/android-sdk-linux/tools/ant/build.xml:601: Invalid file: /appcompat_v7/build.xml

奇怪~ 怎會跑出 appcompat_v7的build.xml, 檢查專案目錄下的project.properties,發現原專案會參考到appcompat_v7這個專案,再google一下
原因是使用eclipse更新建置版本,會出現”無限重生appcompat_v7的現象”,解決方法就是初始建立專案時,最低SDK版本(Minimum Required SDK)指定為 API 14(即 Android 4.0)
解決之後再輸入ant release
終於

BUILD SUCCESSFUL
Total time: 6 seconds

完成之後在專案目錄下的bin資料夾會出現
xxx-release-unsigned.apk , 就是unsign key 的apk
 
 
 
 
 

分類
Uncategorized

CloneZilla Backup Error: Bitmap free count error

Root Caused:
unknow
Solution:
選擇專家模式後再選擇
-fsck-src-part 存印象檔之前嘗試交談式檢查與修復來源裝置檔案系統
之後會出現詢問 Fix xxx, 選擇y

分類
Uncategorized

TraceView

Traceview 用來追蹤程式執行效能,主要可運用2種方式來產生效能分析圖(.trace)
A-1.使用插入code方式
在想分析的程式碼區塊的開頭及結尾個別加入

Debug.startMethodTracing()
//Analysis code....
//Analysis code....
//Analysis code....
Debug.stopMethodTracing();

其中Debug.startMethodTracing()可指定分析圖檔名
如Debug.startMethodTracing(“trace_report”),在/sdcard會產生trace_report.trace檔
A-2.加入

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

否則A-1的方法會丟出Exception
A-3.執行程式
A-4.將產生的分析圖從/sdcard中複製到本機的資料夾中以方便查看,使用以下指令

./adb pull /sdcard/trace_report.trace /資料夾名稱

A-5.使用android-sdk tools的 traceview來開啟.trace檔,使用以下指令

android-sdk-linux/tools$ ./traceview /資料夾名稱/trace_report.trace

B-1.使用DDMS來產生分析圖,執行程式並切換到DDMS
B-2.點擊Start Method Profiling,開始分析
B-3.點擊Stop Method Profiling,結束分析
B-4.自動產生分析檔
以下提供簡單的分析範例,尋找程式效能熱點(HotPoint)
首先這是MainActivity

public class MainActivity extends Activity
{
   
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);      
        Debug.startMethodTracing("trace_report");
        TestString testStr = new TestString();
        Debug.stopMethodTracing();
    }
}

相當簡單,只專注在 TestString 物件的建立
接著是TestString

public class TestString
{
    private String mStr = new String();
   
    public TestString(){
        initStr();
    }
   
    private void initStr(){
        for(int i=0; i<10000; ++i){
            mStr = mStr.concat(""+i);
        }
    }
}

在initStr方法內為相當消耗效能的熱點,執行程式產生分析圖如下

 
 
 
 
 
 
 
 
在Incl cpu time 佔用 89.6% 為String.concat()方法,總共佔用了9.66秒,針對這裡來修改熱點
修改後的TestString.java如下

public class TestString
{
    private StringBuffer mStr = new StringBuffer();
   
    public TestString(){
        initStr();
    }
   
    private void initStr(){
        for(int i=0; i<10000; ++i){
            mStr = mStr.append(i);
        }
    }
}

採用StringBuffer取代原來的String,重新產生分析圖

 
 
 
 
 
 
 
 
可以看到StringBuffer.append()方法仍然為熱點(95.7%),佔用時間卻降到0.73秒

分類
Uncategorized

XmlParser

網路上一堆範例不如自己作一遍還來的了解

直接切入主題,這裡使用DOM來轉換xml,以步驟來說明

Step1.
首先要有xml檔放到assets資料夾中,為了方便整理在assets 資料夾中另外開了一個xmlfiles資料夾,路徑如下

Project/assets/xmlfiles/command_simple_formatter.xml

<?xml version="1.0" encoding="utf-8"?>
<commands>
    <command
        id="1"
        enable="true"
        function_name="function1"
        type="FLOAT" />
    <command
        id="2"
        enable="false"
        function_name="function2"
        type="FIXED" />
</commands>

Step2.
接著建立對應的資料結構,根據xml中的tag來建立

public class Command
{
    private int mIndex;
    private String mFunction;
    private boolean mEnable;
    private Type mType;
 
    public enum Type {
        FIXED, FLOAT
    }
 
    public void setType(Type type){
        mType = type;
    }
 
    public Type getType(){
        return mType;
    }
 
    public void setIndex(int index)
    {
        mIndex = index;
    }
    public void setFunction(String function)
    {
        mFunction = function;
    }
    public int getIndex()
    {
        return mIndex;
    }
    public String getFunction()
    {
        return mFunction;
    }
 
    public boolean getEnable(){
        return mEnable;
    }
 
    public void setEnable(boolean enable){
        mEnable = enable;
    }
}

Step3.
接著開始撰寫轉換的本體,這裡我帶入Template Method Pattern, XmlParser為SuperClass,轉換的必要步驟都在此實作,其餘部份在個別SubClass實作

public abstract class XmlParser
{
    private Context mContext;
    public XmlParser(Context context) {
        mContext = context;
    }
    public final List<?> parserProcess(String xmlFileName)
    {
        Document document = prepareParseComponent(xmlFileName);
        Element root = getXmlBasicRootElement(document);
        List<?> javaDatas = parseXmlContentToJavaObjects(root);
        return javaDatas;
    }
 
    private Document prepareParseComponent(String xmlFileName)
    {
        DocumentBuilder documentBuilder = getDocumentBuilder();
        InputStream inputStream = getXmlInputStream(xmlFileName);
        Document document = null;
        try {
            document = documentBuilder.parse(inputStream);
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return document;
    }
    protected abstract List<?> parseXmlContentToJavaObjects(Element root);
 
    private DocumentBuilder getDocumentBuilder()
    {
        DocumentBuilder documentBuilder = null;
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        try {
            documentBuilder = builderFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        return documentBuilder;
    }
    /**
     *
     * @param xmlFileName : xml file need put in assets folder
     * @return InputStream
     */
    private InputStream getXmlInputStream(String xmlFileName)
    {
        AssetManager assetManager = mContext.getAssets();
        InputStream inputStream = null;
        try {
            inputStream = assetManager.open(xmlFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return inputStream;
    }
    private Element getXmlBasicRootElement(Document document)
    {
        Element root = document.getDocumentElement();
        return root;
    }
}

Step4.
建立繼承XmlParser的類別,主要複寫parseXmlContentToJavaObjects方法

public class CommandSimpleXmlParser extends XmlParser
{
    private String mElementName = "command";
    private String mId = "id";
    private String mFunctionName = "function_name";
    private String mEnable = "enable";
    private String mType = "type";
 
    public CommandSimpleXmlParser(Context context) {
        super(context);
    }
    @Override
    protected List<Command> parseXmlContentToJavaObjects(Element root)
    {
        NodeList commandNode = root.getElementsByTagName(mElementName);
        int commandsNodeSize = commandNode.getLength();
        return transXmlToCommand(commandNode,commandsNodeSize);
    }
 
    private List<Command> transXmlToCommand(NodeList nodeList,int size){
        List<Command> result = new ArrayList<Command>();
        for (int i = 0; i < size; ++i) {
            Command command = new Command();
            Element commandElement = (Element) nodeList.item(i);
            command.setIndex(transXmlIdTagToCommand(
                    commandElement, mId));
            command.setFunction(transXmlFunctionNameTagToCommand(
                    commandElement, mFunctionName));
            command.setEnable(transXmlEnableTagToCommand(
                    commandElement, mEnable));
            command.setUIType(trnasXmlTypeToCommand(
                    commandElement, mType));
            result.add(command);
            command = null;
        }
        return result;
    }
 
    private UIType trnasXmlTypeToCommand(Element element,String type){
        return Command.Type.valueOf(element.getAttribute(type));
    }
 
    private int transXmlIdTagToCommand(Element element,String id){
        return Integer.valueOf(element.getAttribute(id));
    }
 
    private String transXmlFunctionNameTagToCommand(Element element,String functionName){
        return element.getAttribute(functionName);
    }
 
    private boolean transXmlEnableTagToCommand(Element element,String enable){
        return Boolean.valueOf(element.getAttribute(enable));
    }
}

Step5.
使用轉換

public class XmlParserMainActivity extends Activity
{
    private static final String TAG = "XmlParserMainActivity";
    private static final String COMMAND_SIMPLE_XML_FILE_PATH = "xmlfiles/command_simple_formatter.xml";
 
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        examParseSimpleXml(COMMAND_SIMPLE_XML_FILE_PATH);
    }
    private void examParseSimpleXml(String xmlFilePath)
    {
        XmlParser simpleCommandXmlParser = new CommandSimpleXmlParser(this);
        List<Command> commands = (List<Command>) simpleCommandXmlParser
                .parserProcess(xmlFilePath);
    }
}

 

分類
Uncategorized

MonkeyRunner 紀錄

Description:
首先MonkeyRunner主要是調用
/android-sdk-linux/tools/monkeyrunner 來自動化執行腳本
Step1.
/android-sdk-linux/tools/中建立專屬的測試腳本資料夾,其中放入測試用腳本,
假設專案名稱為Project1,建立/android-sdk-linux/tools/Project1_script資料夾
Step2.
把專案apk(Project1.apk)放入步驟1建立的資料夾中並建立測試腳本(Project1_script.py),
測試腳本內容可參考以下範例
# -*- coding: utf-8 -*-
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
 
# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()
 
# Installs the Android package. Notice that this method returns a boolean, so you can test
# to see if the installation worked.
device.installPackage('../Project1_script/Project1.apk')
 
# sets a variable with the package's internal name
package = 'abc.efg.hij'
 
# sets a variable with the name of an Activity in the package
activity = 'abc.efg.hij.xxxActivity'
 
# sets the name of the component to start組合(package和activity)
runComponent = package + '/' + activity
 
# Runs the component
device.startActivity(component=runComponent)
 
# Do something u want to do...
第10行為安裝 package(app), 若 app 已安裝且沒有任何變動,這行可以刪除。
第22行為啟動 activity,其中參數 component= 為固定用法。
2.如何執行測試腳本:
使用Terminal移動到/android sdk/tools/Project1_script資料夾,再輸入
../monkeyrunner Project1_script.py
3.相關的內容在android api 中都有使用說明
http://developer.android.com/tools/help/monkeyrunner_concepts.html#APIClasses
4.常用方法紀錄
MonkeyRunner.sleep(n) ->等待n秒
 
device = MonkeyRunner.waitForConnection()
device.press('KEYCODE_NUMPAD_1','DOWN_AND_UP') -> 模擬虛擬鍵盤輸入1
device.press('KEYCODE_NUMPAD_7','DOWN_AND_UP') -> 模擬虛擬鍵盤輸入7
device.press('KEYCODE_NUMPAD_2','DOWN_AND_UP') -> 模擬虛擬鍵盤輸入2
device.press('KEYCODE_NUMPAD_DOT','DOWN_AND_UP') -> 模擬虛擬鍵盤輸入 .
以上指令可用
device.type('172.') 取代
 
device.touch(384,199,'DOWN_AND_UP') -> 點擊螢幕x:384 y:199座標
 
start = (100,100) -> 拖曳起點
end = (100,120) -> 拖曳終點
device.drag(start,end,1,10) -> 開始拖曳
 
device.getProperty() -> 可獲得系統資訊,
參考http://developer.android.com/tools/help/MonkeyDevice.html#table1
如
width = int(device,getProperty('display.width') -> 螢幕寬度
height = int(device.getProperty('display.height') -> 螢幕高度
 
#註解
print '顯示訊息'

5. MonkeyRunner 可以獨立於app測試,大部分使用 MonkeyRunner 的情況都是測試app內部功能,但MonkeyRunner可以獨立於app以外,如下腳本並沒有啟動任何activity,而是按下home key。

# -*- coding: utf-8 -*-
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()
# do anything "OUT" of app
device.press('KEYCODE_HOME','DOWN_AND_UP')

 
 

分類
Uncategorized

java Excel 錯誤:Unable to recognize OLE stream

Caused:
和許多google 找到的原因一樣 -> “jxl无法读取Excel2007和数据库导出的非文本部分”
Solution:
另開新試算表,把原本的內容複製到新試算表上,儲存格式為Microsoft Excel 97/2000/XP/2003 (xls)

分類
Uncategorized

取得網頁原始碼

使用 url 來取得網頁原始碼相當簡單,也能藉此加上其他自動化的功能如自動偵測股票網站的數值等等

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class PageData {
    /**
     * 取得網頁資料
     * @return : 回傳string型態的網頁資料
     */
    public static String getPageData(String http){
        URL u = null;
        InputStream in = null;
        InputStreamReader r = null;
        BufferedReader br = null;
        StringBuffer message = null;
        try {
           u = new URL(http);
           in = u.openStream();
           r = new InputStreamReader(in, "UTF-8");
           br = new BufferedReader(r);
           String tempstr = null;
           message = new StringBuffer();
           while ((tempstr = br.readLine()) != null) {
               message.append(tempstr);
           }
        } catch (Exception e) {
           e.getStackTrace();
           System.out.println(e.getMessage());
        } finally {
           try {
              u = null;
              in.close();
              r.close();
              br.close();
           } catch (Exception e) {
           }
    }
        return message.toString();
    }
}

 
接著再根據 getPageData() 回傳的字串做處理

分類
Uncategorized

取得執行時的各種特性(System.getProperties())

System.getProperties() 可以取得各種特性

import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
public class GetExecProperty {
    static String execSimerPath = "";
    public static void showSupplyProperties() {
        Properties pros = System.getProperties();
        Set s = pros.keySet();
        Iterator it = s.iterator();
        while (it.hasNext()) {
            String keystr = it.next().toString();
            String tempstr2 = System.getProperty(keystr);
            System.out.println("key: " + keystr + " ,value: " + tempstr2);
        }
    }
    /**
     * return path of jar
     */
    public static String getExecPath() {
        String tempstr = "";
        String local = System.getProperty("user.dir");
        System.out.println("System.getProperty user.dir: " + local);
        String[] spilttemp = local.split("\\");
        for (int i = 0; i < spilttemp.length; i++) {
            tempstr = tempstr + spilttemp[i] + "\\";
        }
        System.out.println("tempstr: " + tempstr);
        return tempstr;
    }
}