顯示具有 Android App 標籤的文章。 顯示所有文章
顯示具有 Android App 標籤的文章。 顯示所有文章

TraceView

Traceview 用來追蹤程式執行效能,主要可運用2種方式來產生效能分析圖(.trace)

A-1.使用插入code方式
在想分析的程式碼區塊插入Debug.startMethodTracing()及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
MainActivity.java
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
TestString.java
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秒


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來建立

Command.java
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,
XmlParser.java
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方法
CommandSimpelXmlParser.java
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.
使用轉換
XmlParserMainActivity.java
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);
    }

}

MonkeyRunner 紀錄

紀錄:
首先MonkeyRunner主要是調用
/android-sdk-linux/tools/monkeyrunner 來自動化執行腳本

步驟1
在/android-sdk-linux/tools/中建立專屬的測試腳本資料夾,其中放入測試用腳本,
假設專案名稱為Project1,建立/android-sdk-linux/tools/Project1_script

步驟2
把專案apk(Project1.apk)放入步驟1建立的資料夾中並建立測試腳本(Project1_script.py),
測試腳本內容可參考以下範例,必須修改
device.installPackage('../Project1_script/Project1.apk') ->路徑必須對應apk位置
package = 'abc.efg.hij' -> package name
activity = 'abc.efg.hij.xxxActivity' -> activity name


範例如下
Project1_script.py

# 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....





2.如何執行測試腳本:
使用Terminal移動到/android sdk/tools/Project1_script資料夾,再輸入
../monkeyrunner Project1_script.py

3.相關的內容在android api 中都有使用說明

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 '顯示訊息'

開啟手機閃光燈(手電筒)(Camera & Camera.Parameters)


開啟閃光燈相當簡單,因為閃光燈是 Camera 類別的功能,所以必須先建立 Camera 物件再搭配 Camera.Parameters以控制 Camera 的設定,如下

   1:      Camera c;
   2:      Parameters p;
   3:      
   4:      @Override
   5:      public void onCreate(Bundle savedInstanceState) {
   6:          super.onCreate(savedInstanceState);
   7:          setContentView(R.layout.activity_main);
   8:          
   9:          c = Camera.open();
  10:   
  11:          p = c.getParameters();
  12:          p.setFlashMode(Parameters.FLASH_MODE_TORCH);
  13:          
  14:          c.setParameters(p);
  15:         
  16:      }

事實上打開閃光燈是靠著第 12 行來達成,之後的關閉閃光燈也是類似的做法

關閉(切換)閃光燈

   1:              String s = p.getFlashMode();
   2:              if(s.equals(Parameters.FLASH_MODE_TORCH)){
   3:                  p.setFlashMode(Parameters.FLASH_MODE_OFF);
   4:              }
   5:              else if(s.equals(Parameters.FLASH_MODE_OFF)){
   6:                  p.setFlashMode(Parameters.FLASH_MODE_TORCH);
   7:              }
   8:   
   9:                  c.setParameters(p);

藉由 setFlashMode 方法來切換閃光燈的開關(第 3 , 6行)

調整閃光燈強度為弱光可以使用

   1:  p.setFocusMode("macro");//調整為弱光
   2:   
   3:  p.setFocusMode("auto");//恢復正常亮度

來切換

測試結果 samsung s2 可以使用, 不過 htc incredible s 卻沒有 macro 可以使用,應該有其它的方法可以控制才對










製作狀態列的提醒內容(Notification)


狀態列在手機畫面的最上方,作用是提醒或通知使用者一些訊息,如下圖




只要使用 Notification 這個類別,你也可以製作自己的狀態列訊息,基本的程式碼如下

   1:          Intent it = new Intent(this,Table_Flow.class);
   2:          it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   3:          PendingIntent pi = PendingIntent.getActivity(All_List.this, 0, it, 0);
   4:          
   5:          Notification nn = new Notification();
   6:          nn.icon = R.drawable.notpic;
   7:          nn.tickerText = "歡迎使用極簡黑記帳本!!!";
   8:          nn.defaults = Notification.DEFAULT_ALL;
   9:          nn.setLatestEventInfo(All_List.this, "極簡黑記帳本", "歡迎使用極簡黑記帳本!!!", pi);
  10:   
  11:          NotificationManager nm;
  12:          nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
  13:          nm.notify(0, nn);

第 1 行第 1 個參數為目前的類別,第 2 個參數為點選狀態列的訊息執行的類別
第 2 行設定 Flags
第 3 行設定 PendingIntent , 第 1 個參數為目前類別,第 2 個參數為 requsetcode , 第 3 個參數為 intent , 第 4 個參數為 flag
第 5 ~ 8 行就是狀態列的顯示內容
第 6 行為顯示圖形,尺寸為 30x30
第 7 行為顯示內容
第 8 行為出現訊息時的預設行為,包括手機震動,音效,指示燈
第 9 行為點選狀態列之後出現的內容
第 11 ~ 13 行發送剛剛的 Notification

上面的內容可以在應用程式離開前使用

結果為
結束應用程式後





點選狀態列





























上架 google play(android market) 的準備


1.先來做 icon 吧, Android 支援各種不同的尺寸,可以製作 96x96(x), 72x72(h), 48x48(m), 36x36(l), 4種不同尺寸的 icon 圖, 我使用 firework 來作圖, 先製作 96x96 的 icon , 之後的尺寸再調整就可以了
先製作 icon 底圖, 底圖最好小於該尺寸 10 個單位,以 96x96 為例,下面底圖最好是 86x86


 




接著就根據自己的喜好,加上圖案吧,設計完成後,再調整各個尺寸,如 72x72 的 icon 就設定為 62x62 ,接著到 專案\res\drawable-xhdpi , res\drawable-hdpi , res\drawable-mdpi , res\drawable-ldpi, 替換原先的 ic_launcher.png


2.更改應用程式名稱,到 AndroidManifest.xml 中尋找 <application 中的 android : label ,修改其內容

3.製作 apk 檔, 製作 apk 檔之前必須先製作金鑰檔,上架時上傳的 apk 必須先經過金鑰來簽名,製作金鑰檔的方式為

開啟命令提示字元 -> 輸入 keytool ,會顯示一連串可用的命令如下












接著輸入

keytool -genkey -v -keystore testkey.store -alias testkey.keystore -keyalg RSA -validity 20000
-genkey 為產生key , testkey.store 為 金鑰檔 -keyalg 為演算法, -validity 為有效日 50年(最好超過)

接下來會出現一些填資料的畫面如下














最後會產生 1 個名稱為 testkey.store 的金鑰檔,回到 eclipse,在專案上點選右鍵,



















在必要的地方填入剛剛設定的密碼















最後選擇位置















製作 apk 檔完成!!!

最後就是登入後台並上傳檔案,當然在後台還有一些資料需要設定,不過大部分都是圖案等等


如何製作上鎖功能(EditText + SharedPreferences)


上鎖功能相當簡單,基本上只需要 EditText 和 SharedPreferences(也可以使用其它的儲存類別如 fileoutputstream,SQLite) 就能完成,,不過為了操作的方便,我還加上了 button 和 textview ,基本介面如下
開鎖畫面


















輸入密碼畫面


















而程式碼的實作原理也相當簡單,為了不把主流程複雜化,我把解鎖(UnLock_Flow.java)和加鎖(Lock_Flow.java)分開成2個類別,首先在主流程開始前先判斷是否有密碼鎖,有就先進解鎖,沒有就直接開始主流程,而在主流程中會有個選項是加入密碼鎖的選擇,點選進入 Lock_Flow.java,相當簡單吧

首先在主流程中判斷的方法如下

   1:      void lock() {
   2:          // get data for accountdetail
   3:          SharedPreferences sp = getSharedPreferences("bcn", 0);
   4:   
   5:          // get accountdetail count
   6:          String passstr = sp.getString("adlock", "");
   7:          
   8:          // no lock
   9:          if(passstr.equals("")){
  10:              
  11:          }
  12:          //lock exist
  13:          else {
  14:              
  15:          //call Lock_Flow
  16:              Intent inte = new Intent();
  17:              inte.setClass(All_List.this, UnLock_Flow.class);
  18:              
  19:              startActivityForResult(inte, 3);
  20:              overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
  21:          }
  22:      }


其中 SharedPreferences 的用法請參考這篇,本篇不再多加詳述
第 9 行判斷內容是否為空,是的話代表沒有密碼鎖直接進入主流程,否的話就呼叫解鎖類別(16 ~ 20 行)

解鎖類別(UnLock_Flow.java)如下

   1:  package com.example.helloworld;
   2:   
   3:  import FoXxLib.FP;
   4:  import android.annotation.SuppressLint;
   5:  import android.app.Activity;
   6:  import android.app.AlertDialog;
   7:  import android.content.DialogInterface;
   8:  import android.content.SharedPreferences;
   9:  import android.os.Bundle;
  10:  import android.view.KeyEvent;
  11:  import android.view.View;
  12:  import android.view.View.OnClickListener;
  13:  import android.widget.Button;
  14:  import android.widget.EditText;
  15:  import android.widget.TextView;
  16:  import android.widget.Toast;
  17:   
  18:  @SuppressLint("NewApi")
  19:  public class UnLock_Flow extends Activity {
  20:   
  21:      EditText et;
  22:      Button byes;
  23:      Button bno;
  24:   
  25:      TextView tv;
  26:   
  27:      int tryNum = 2;
  28:   
  29:      public void onCreate(Bundle savedInstanceState) {
  30:          super.onCreate(savedInstanceState);
  31:   
  32:          initXml();
  33:   
  34:      }
  35:   
  36:      void initXml() {
  37:          setContentView(R.layout.unlockflow);
  38:   
  39:          tv = (TextView) findViewById(R.id.textView1);
  40:   
  41:          tv.setText("請輸入密碼解鎖");
  42:   
  43:          et = (EditText) findViewById(R.id.username_edit);
  44:          et.setHint("輸入密碼");
  45:   
  46:          byes = (Button) findViewById(R.id.buttonYes);
  47:          byes.setOnClickListener(new OnClickListener() {
  48:   
  49:              @Override
  50:              public void onClick(View v) {
  51:                  // TODO Auto-generated method stub
  52:   
  53:                  checkPassWord();
  54:              }
  55:          });
  56:   
  57:          bno = (Button) findViewById(R.id.buttonNo);
  58:          bno.setOnClickListener(new OnClickListener() {
  59:   
  60:              @Override
  61:              public void onClick(View v) {
  62:                  // TODO Auto-generated method stub
  63:   
  64:                  // use AlertDialog
  65:                  AlertDialog ad = new AlertDialog.Builder(UnLock_Flow.this,
  66:                          AlertDialog.THEME_TRADITIONAL).create();
  67:                  ad.setTitle("警告!!");// 設定警告標題
  68:                  ad.setMessage("確定離開程序??");
  69:   
  70:                  ad.setButton2("確定", new DialogInterface.OnClickListener() {// 設定按鈕2
  71:   
  72:                              @Override
  73:                              public void onClick(DialogInterface dialog,
  74:                                      int which) {
  75:   
  76:                                  // 點選按鈕2後執行的動作
  77:                                  finishEdit(1);
  78:                              }
  79:                          });
  80:                  ad.setButton("取消", new DialogInterface.OnClickListener() {// 設定按鈕2
  81:   
  82:                              @Override
  83:                              public void onClick(DialogInterface dialog,
  84:                                      int which) {
  85:   
  86:                                  // 點選按鈕2後執行的動作
  87:   
  88:                              }
  89:                          });
  90:   
  91:                  ad.setCanceledOnTouchOutside(true);// 當警告提示出現後,點選提示以外範圍,是否會取消提示,預設是true
  92:   
  93:                  ad.setCancelable(true);// 當警告提示出現後,點選其他實體按鈕(backkey等等),是否會取消提示,預設是true
  94:   
  95:                  ad.show();
  96:   
  97:              }
  98:          });
  99:      }
 100:   
 101:      void checkPassWord() {
 102:   
 103:          if (et.getText() == null) {
 104:              // use Toast
 105:              tryNum--;
 106:              Toast.makeText(UnLock_Flow.this, "未輸入密碼!!!" + "還剩" + tryNum + "次",
 107:                      Toast.LENGTH_SHORT).show();
 108:   
 109:              et.setText("");
 110:          } else {
 111:   
 112:              String tempstr = et.getText().toString();
 113:   
 114:              // get data for accountdetail
 115:              SharedPreferences sp = getSharedPreferences("bcn", 0);
 116:   
 117:              // get accountdetail count
 118:              String passstr = sp.getString("adlock", "");
 119:   
 120:              if (tempstr.equals(passstr)) {
 121:                  Toast.makeText(UnLock_Flow.this, "密碼正確!!!", Toast.LENGTH_SHORT)
 122:                          .show();
 123:                  finishEdit(0);
 124:              } else {
 125:                  Toast.makeText(UnLock_Flow.this,
 126:                          "密碼錯誤!!!" + "還剩" + tryNum + "次", Toast.LENGTH_SHORT)
 127:                          .show();
 128:                  tryNum--;
 129:              }
 130:   
 131:          }
 132:   
 133:          if (tryNum < 0) {
 134:   
 135:              finishEdit(1);
 136:          }
 137:      }
 138:   
 139:      public boolean onKeyDown(int keycode, KeyEvent event) {
 140:   
 141:          FP.p("keycode:" + keycode);
 142:          FP.p("event:" + event.getAction());
 143:   
 144:          finishEdit(1);
 145:   
 146:          switch (keycode) {
 147:   
 148:          // menu key
 149:          case 82:
 150:   
 151:              break;
 152:          }
 153:   
 154:          return super.onKeyDown(keycode, event);
 155:      }
 156:   
 157:      /**
 158:       * 
 159:       * @param result
 160:       *            0 ok
 161:       */
 162:      void finishEdit(int result) {
 163:   
 164:          if (result == 0) {
 165:              UnLock_Flow.this.setResult(0);
 166:   
 167:              UnLock_Flow.this.finish();
 168:   
 169:              overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
 170:          } else if (result == 1) {
 171:   
 172:              UnLock_Flow.this.setResult(1);
 173:   
 174:              UnLock_Flow.this.finish();
 175:   
 176:          }
 177:      }
 178:   
 179:  }

其中比較重要的為 101 行的 checkPassWord() 方法,會取得 在 et 中輸入的字串內容並與 passstr 字串做比較(120行),相同則解鎖成功(finishEdit(0)),失敗則嘗試次數減少,當嘗試次數減為 0 ,那麼會直接回到主程序再結束 (finishEdit(1))

以上是解鎖的部分,接下來是上鎖的部分,在主程序中會有個按鈕,用來觸發加鎖動作,如下

   1:  //call Lock_Flow
   2:                      Intent inte = new Intent();
   3:                      inte.setClass(All_List.this, Lock_Flow.class);
   4:                      
   5:                      startActivityForResult(inte, 4);
   6:                      overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);

接著是 Lock_Flow.java的內容,必須注意在沒有上鎖的情況下,可以直接設定密碼,完成上鎖,但相反的若已經有上鎖過,則必須先輸入原先的密碼以解鎖,再上鎖,如下

   1:  package com.example.helloworld;
   2:   
   3:  import FoXxLib.FP;
   4:  import android.annotation.SuppressLint;
   5:  import android.app.Activity;
   6:  import android.app.AlertDialog;
   7:  import android.content.DialogInterface;
   8:  import android.content.SharedPreferences;
   9:  import android.os.Bundle;
  10:  import android.view.KeyEvent;
  11:  import android.view.View;
  12:  import android.view.View.OnClickListener;
  13:  import android.widget.Button;
  14:  import android.widget.EditText;
  15:  import android.widget.TextView;
  16:  import android.widget.Toast;
  17:   
  18:  @SuppressLint("NewApi")
  19:  public class Lock_Flow extends Activity{
  20:   
  21:      EditText et;
  22:      Button byes;
  23:      Button bno;
  24:      
  25:      TextView tv;
  26:      
  27:      int tryNum =2;
  28:      
  29:      //0:lock exist 1:no lock
  30:      int flow =0;
  31:      
  32:      public void onCreate(Bundle savedInstanceState){
  33:          super.onCreate(savedInstanceState);
  34:          
  35:          initXml();
  36:          
  37:      }
  38:      
  39:      void initXml(){
  40:          
  41:          setContentView(R.layout.lockflow);
  42:          
  43:          tv = (TextView)findViewById(R.id.textView1);
  44:          
  45:          // get data for accountdetail
  46:          SharedPreferences sp = getSharedPreferences("bcn", 0);
  47:   
  48:          // get accountdetail count
  49:          String passstr = sp.getString("adlock", "");
  50:          
  51:          //no lock
  52:          if(passstr.equals("")){
  53:              flow =1;
  54:              tv.setText("請輸入密碼:");
  55:          }
  56:          //lock exist
  57:          else{
  58:              flow =0;
  59:              tv.setText("請輸入原始密碼:");
  60:              
  61:          }
  62:          
  63:          et = (EditText)findViewById(R.id.username_edit);
  64:          et.setHint("輸入密碼");
  65:          
  66:          byes = (Button)findViewById(R.id.buttonYes);
  67:          byes.setOnClickListener(new OnClickListener() {
  68:              
  69:              @Override
  70:              public void onClick(View v) {
  71:                  // TODO Auto-generated method stub
  72:                  
  73:                  checkPassWord();
  74:              }
  75:          });
  76:          
  77:          
  78:          bno = (Button)findViewById(R.id.buttonNo);
  79:          bno.setOnClickListener(new OnClickListener() {
  80:              
  81:              @Override
  82:              public void onClick(View v) {
  83:                  // TODO Auto-generated method stub
  84:                  
  85:                  //use AlertDialog
  86:                  AlertDialog ad = new AlertDialog.Builder(Lock_Flow.this,AlertDialog.THEME_TRADITIONAL).create();
  87:                  ad.setTitle("警告!!");//設定警告標題
  88:                  ad.setMessage("未上鎖,確定返回程序??");
  89:                  
  90:                  ad.setButton2("確定", new DialogInterface.OnClickListener() {// 設定按鈕2
  91:   
  92:                              @Override
  93:                              public void onClick(DialogInterface dialog, int which) {
  94:   
  95:                                  // 點選按鈕2後執行的動作
  96:                                  finishEdit(1);
  97:                              }
  98:                          });
  99:                  ad.setButton("取消", new DialogInterface.OnClickListener() {// 設定按鈕2
 100:   
 101:                      @Override
 102:                      public void onClick(DialogInterface dialog, int which) {
 103:   
 104:                          // 點選按鈕2後執行的動作
 105:                          
 106:                      }
 107:                  });
 108:                  
 109:                  ad.setCanceledOnTouchOutside(true);//當警告提示出現後,點選提示以外範圍,是否會取消提示,預設是true
 110:                  
 111:                  ad.setCancelable(true);//當警告提示出現後,點選其他實體按鈕(backkey等等),是否會取消提示,預設是true
 112:                  
 113:                  ad.show();
 114:                  
 115:                  
 116:                  
 117:              }
 118:          });
 119:      }
 120:      
 121:      void checkPassWord(){
 122:          
 123:          if(flow==0){
 124:              if(et.getText().toString().equals("")){
 125:                  // use Toast
 126:                  
 127:                  Toast.makeText(Lock_Flow.this, "未輸入密碼!!!"+"還剩"+tryNum+"次",Toast.LENGTH_SHORT).show();
 128:                  tryNum--;
 129:                  et.setText("");
 130:              }
 131:              else{
 132:                  
 133:                  String tempstr = et.getText().toString();
 134:                  
 135:                  // get data for accountdetail
 136:                  SharedPreferences sp = getSharedPreferences("bcn", 0);
 137:   
 138:                  // get accountdetail count
 139:                  String passstr = sp.getString("adlock","");
 140:                  
 141:                  if(tempstr.equals(passstr)){
 142:                      Toast.makeText(Lock_Flow.this, "密碼正確!!!",Toast.LENGTH_SHORT).show();
 143:                      flow =1;
 144:                      
 145:                      tv.setText("輸入新密碼:");
 146:                  }
 147:                  else{
 148:                      Toast.makeText(Lock_Flow.this, "密碼錯誤!!!"+"還剩"+tryNum+"次",Toast.LENGTH_SHORT).show();
 149:                      tryNum--;
 150:                  }
 151:                  
 152:              }
 153:              
 154:              if(tryNum<0){
 155:                  
 156:                  //use AlertDialog
 157:                  AlertDialog ad = new AlertDialog.Builder(Lock_Flow.this,AlertDialog.THEME_TRADITIONAL).create();
 158:                  ad.setTitle("更改密碼失敗!!");//設定警告標題
 159:                  ad.setMessage("原始密碼不正確");
 160:                  
 161:                  ad.setButton("返回", new DialogInterface.OnClickListener() {// 設定按鈕2
 162:   
 163:                      @Override
 164:                      public void onClick(DialogInterface dialog, int which) {
 165:                          finishEdit(0);
 166:                      }
 167:                  });
 168:                  
 169:                  ad.setCanceledOnTouchOutside(false);//當警告提示出現後,點選提示以外範圍,是否會取消提示,預設是true
 170:                  
 171:                  ad.setCancelable(false);//當警告提示出現後,點選其他實體按鈕(backkey等等),是否會取消提示,預設是true
 172:                  
 173:                  ad.show();
 174:                  
 175:              }
 176:          }
 177:          else if(flow==1){
 178:              if(et.getText().toString().equals("")){
 179:                  // use Toast
 180:                  Toast.makeText(Lock_Flow.this, "未輸入密碼!!!",Toast.LENGTH_SHORT).show();
 181:                  
 182:                  et.setText("");
 183:              }
 184:              else{
 185:                  
 186:                  String tempstr = et.getText().toString();
 187:                  
 188:                  // get data for accountdetail
 189:                  SharedPreferences sp = getSharedPreferences("bcn", 0);
 190:                  SharedPreferences.Editor spe = sp.edit();
 191:                  
 192:                  spe.putString("adlock", tempstr);// for more putXXX
 193:                  spe.commit();
 194:   
 195:                  //use AlertDialog
 196:                  AlertDialog ad = new AlertDialog.Builder(Lock_Flow.this,AlertDialog.THEME_TRADITIONAL).create();
 197:                  ad.setTitle("上鎖完成!!");//設定警告標題
 198:                  ad.setMessage("密碼為"+tempstr);
 199:                  
 200:                  ad.setButton("返回", new DialogInterface.OnClickListener() {// 設定按鈕2
 201:   
 202:                      @Override
 203:                      public void onClick(DialogInterface dialog, int which) {
 204:                          finishEdit(1);
 205:                      }
 206:                  });
 207:                  
 208:                  ad.setCanceledOnTouchOutside(false);//當警告提示出現後,點選提示以外範圍,是否會取消提示,預設是true
 209:                  
 210:                  ad.setCancelable(false);//當警告提示出現後,點選其他實體按鈕(backkey等等),是否會取消提示,預設是true
 211:                  
 212:                  ad.show();
 213:                  
 214:              }
 215:          }
 216:          
 217:          
 218:      }
 219:      
 220:      public boolean onKeyDown(int keycode, KeyEvent event){
 221:          
 222:          FP.p("keycode:"+keycode);
 223:          FP.p("event:"+event.getAction());
 224:          
 225:          finishEdit(1);
 226:          
 227:          switch(keycode){
 228:              
 229:          // menu key
 230:          case 82:
 231:              
 232:              break;
 233:          }
 234:          
 235:          return super.onKeyDown(keycode, event);
 236:      }
 237:      
 238:      /**
 239:       * 
 240:       * @param result 0 ok
 241:       */
 242:      void finishEdit(int result){
 243:          
 244:          if(result==0){
 245:              Lock_Flow.this.setResult(0);
 246:              
 247:              Lock_Flow.this.finish();
 248:              
 249:              overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
 250:          }
 251:          else if(result==1){
 252:              
 253:              Lock_Flow.this.setResult(1);
 254:              
 255:              Lock_Flow.this.finish();
 256:              
 257:              overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
 258:          }
 259:      }
 260:      
 261:      
 262:  }

第 30 行 flow=0代表已經有鎖, 必須先解鎖,而flow=1,代表沒有鎖,可以直接輸入密碼上鎖

結果為




















EditText 的使用


EditText 用來輸入編輯資料,它繼承自 TextView,許多在 TextView中的方法也可以在這使用, 可藉由 xml 來定義, 其中參數可以調整輸入資料格式,長度等等,一個 EditText 在 xml 中定義如下

   1:      <EditText
   2:          android:id="@+id/editTextTime"
   3:          android:layout_width="wrap_content"
   4:          android:layout_height="wrap_content"
   5:          android:ems="10"
   6:          android:inputType="date" >
   7:          <requestFocus />
   8:      </EditText>

第 5 行限制字數為 10 個字元
第 6 行限制輸入格式為 date

也有一些常用的方法如下

   1:          //get EditText
   2:          EditText etMoney = (EditText) findViewById(R.id.editTextMoney);
   3:          etMoney.setText("0000");
   4:          etMoney.getText().toString(); 
   5:          etMoney.setHint("提示");
   6:          etMoney.setInputType(InputType.TYPE_NULL);// disappear keyboard

特殊方法
1.
點擊 EditText 關閉原本的 keyboard, 並跳出調整日期選項,調整完再設定到 EditText 中

   1:          //get edTime
   2:          etTime = (EditText) findViewById(R.id.editTextTime);        
   3:          //get now date
   4:          final Calendar cal = Calendar.getInstance();
   5:          String dateStr = "" + cal.get(Calendar.YEAR) // 2012
   6:                  + "/" + (cal.get(Calendar.MONTH) + 1) // 12 (add 1 because it start from 0)
   7:                  + "/" + cal.get(Calendar.DATE);// 24
   8:                                                  // ....
   9:          //now date set to etTime
  10:          etTime.setText(dateStr);
  11:          // set keyboard disappear
  12:          etTime.setInputType(InputType.TYPE_NULL);
  13:          // touch etTime will show datePickDialog
  14:          etTime.setOnClickListener(new OnClickListener() 
  15:          {
  16:              
  17:              @Override
  18:              public void onClick(View v) {
  19:                  // TODO Auto-generated method stub
  20:                  
  21:                  new DatePickerDialog(ADEdit_Flow.this, new DatePickerDialog.OnDateSetListener()
  22:                  {
  23:                      
  24:                      @Override
  25:                      public void onDateSet(DatePicker view, int year, int monthOfYear,
  26:                              int dayOfMonth) {
  27:                          // TODO Auto-generated method stub
  28:                          etTime.setText(""+year+"/"+(monthOfYear+1)+"/"+dayOfMonth);
  29:                          FP.p("touch");
  30:                      }
  31:                  }, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DATE)).show();
  32:              }
  33:          });

2.
檢查輸入字數不可超過 7 位數,超過出現提示並重新輸入

   1:          //get EditText
   2:          EditText etMoney = (EditText) findViewById(R.id.editTextMoney);
   3:          etMoney.setText("100");
   4:          
   5:          etMoney.addTextChangedListener(new TextWatcher() {
   6:              
   7:              @Override
   8:              public void onTextChanged(CharSequence s, int start, int before, int count) {
   9:                  // TODO Auto-generated method stub
  10:                  
  11:              }
  12:              
  13:              @Override
  14:              public void beforeTextChanged(CharSequence s, int start, int count,
  15:                      int after) {
  16:                  // TODO Auto-generated method stub
  17:                  
  18:              }
  19:              
  20:              @Override
  21:              public void afterTextChanged(Editable s) {
  22:                  // TODO Auto-generated method stub
  23:                  if(s.length()>7){
  24:                      Toast.makeText(ADEdit_Flow.this, "最大輸入7位數字,請重新輸入",Toast.LENGTH_SHORT).show();
  25:                      s.clear();
  26:                  }
  27:              }
  28:          });

3.
若字串開頭部分有0,去掉0再重整,如 00987 -> 987,原理是藉由 Integer 的 parseInt() 來達成

   1:  String temps =  etMoney.getText().toString();//只要可以轉換為字串即可   
   2:  int tempi = Integer.parseInt(temps);
   3:  String.valueOf(tempi);




Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Affiliate Network Reviews