2015年12月2日 星期三

字串檢查與判別

1. 判斷字串中的特殊符號

String str = "ghf^645";
String regEx = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);


參考資料:



2. 判斷字串長度與字元位置

String a="abcd";.  int. b=a.length();
String string = "java";
System.out.println(string.charAt(1)); // a


參考資料:




3. 判斷國內電話號碼

 - 市內(長途)區域號碼開頭對照:http://zhun.tw/comm/pstn-number.html
 --- 02~09開頭、共9~10碼 (包含區碼)
 - 手機號碼(未加國際碼): 09開頭、共10碼
 - 判斷長度和開頭2碼




4. Email格式判斷

private Pattern pattern; 
private Matcher matcher;
String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
matcher = pattern.matcher(str); 
matcher.matches(); // check result boolean


參考資料:

如何匯出 apk 安裝檔

下面介紹如何透過生成 .keystore 與 導出 .apk (其實就是 jar 檔) 後, 再安裝到 Android 的手持裝置.
由以下步驟來完成安裝檔的產生與裝置安裝:

0. Android Studio > Build > Generate Signed APK

1. 生成 .keystore :
    -  此組 Password 為 Master Password,當完成 Key Store 的建立後,下次進入時直接輸入 Master Password 即可:
 1.
 2.
2. 建立 Key Store 下的 Key alias 鑰匙別名(簽名):一個 Store 可以擁有多個 alias 別名,即每個別名用於不同 app project 上。
 1.
 2.

3. 導出 signed .apk 檔 : Next 至此步驟,並選擇 Build Type 產生 apk 的版本屬於 debug 版還是 release 版。
 - debug 版:用於自行安裝測試於裝置上。
 - release 版:用於上傳至 Google Play Developer Console 中,進行 app 上架用的發布安裝檔。
 - 當跑完後會自動跳出 apk 所在的資料夾視窗:檔名: app-debug.apk / app-release.apk

Google Play Developer Console:https://play.google.com/apps/publish/

4. 安裝 .apk 到手持裝置 :將該 .apk 透過 SD 卡或是 usb 傳輸到 Android 手持裝置上,並使用資料夾瀏覽尋找 apk 檔和點擊安裝。
1. 關閉USB儲存裝置,按設定>應用程式>未知來源打勾 
2. 利用ASTRO檔案總管讀取放在SD那中的APK檔,選擇Open App Manager 並點擊 "Install" 
 1.
2.

5. 若要上架至 Android Store 時,需要注意:
android:versionCode="x"         // 在上架後,versionCode 的設定不能與之前所擁有的號碼相同,否則上傳 apk 時,會顯示 versionCode 有重複並上無法上傳。
android:versionName="1.0.0"  // 此為 play store 上所顯示的版本名稱,不影響上架設定。




參考資料:
  • [Android 精華文章] 生成 .keystore 並導出 .apk 檔案後安裝到 Android 平台:http://puremonkey2010.blogspot.tw/2011/08/android-keystore-apk-android.html

取得螢幕寬高


雖然Android可設定成隨著手機螢幕的大小來調整縮放比例,但是手機開發者在設計的時候還是必須清楚得知手機銀幕的邊界,
避免在縮放的時候造成版面(layout)上的詭異變型,根據各家手機廠商螢幕尺寸的不同,必須對其螢幕解析度有所概念。

ex:藉著幾行程式碼來取得手機螢幕的解析度,當中的關鍵為DisplayMetrics類別應用。
DisplayMetrics metrics = new DisplayMetrics();  
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int dw = metrics.widthPixels;
int dh = metrics.heightPixels;

取Drawable寬高.Bitmap、BitmapFactory.decodeResource()、getHeight()、getWidth();


參考資料:

this、super

this通常指”當前類別”super通常指”父類別”


參考資料:

 - EX1:

 this 用法:
在你的方法中的某个變數名与当前对象的某个成员有相同的名字,这时为了不至于混淆,你便需要明确使用this关键字来指明你要使用某个成员,使用方法是“this.成员名”,而不带this的那个便是前對象變數
輸出結果
DemoSuper:
Name=kevin Age=22
 public class DemoThis// 紅字為同一個類別的變數
        private String name// 共用暫存變數
        private int age;
        DemoThis(String nameint age){
             setName(name); //你可以加上this来调用方法,像这                                样:this.setName(name);但这并不是必须的
        setAge(age);
        this.print(); // 可以用 print() 取代
        }
        public void setName(String name){
            this.name=name;//此处必须指明你要引用成员变量
        }
        public void setAge(int age){
            this.age=age;
        }
        public void print(){
            System.out.println("Name="+name+" Age="+age);//在此行中并                        不需要用this,因为没有会导致混淆的东西
        }
        public static void main(String[] args){
            DemoThis dt=new DemoThis("Kevin","22");
        }
}


 - EX2:

 this , super用法:
輸出結果:
A Person.
chinese.
A person name is:kevin
his name is:kevin
A person name is:kevin
his name is:kevin
his age is:22

 父類別:Person
            class Person{
 
         public static void prt(String s){              System.out.println(s);          }
          Person(){               prt("A Person.");          }
          Person(String name){                prt("A person name is:"+name);          }
}
 類別
public class Chinese extends Person{
 
 Chinese(){    super(); //调用父类构造函数(1    prt(“A chinese.”); // 繼承Person使用prt()
  }
  Chinese(String name){
    super(name);//调用父类具有相同形参的构造函数(2    prt(“his name is:”+name);  }
  Chinese(String name,int age){    this(name);//调用当前具有相同形参的构造函数(3    prt("his age is:"+age);  }

public static void main(String[] args){  Chinese cn=new Chinese();  cn=new Chinese("kevin");  cn=new Chinese("kevin",22);  }
}

2015年11月30日 星期一

Resource ID


在 Android 中,只要你將一個圖檔 (例如 flag.png) 放入到 res/drawable 目錄中,Android Studio 就會自動幫你為這圖檔產生個 ID 名和值 (int) (ID 名和檔案名是相同的,在此例就是 R.drawable.flag),並定義在 R.java 中

一般使用:圖檔 (例如 flag.png) 放入到 res/drawable 目錄中,並透過 R.drawable.flag 取得id
取得單一圖檔的 Drawable 物件: flag.png
Drawable dw = getResources().getDrawable(R.drawable.flag);
取得多圖擋的Drawable物件: flag1~10.png
var Drawable[] dw = new Drawable[10];
for (int i = 1; i <= 10; i++) {
  int id = getResources().getIdentifier(
                    "flag" + i,
                    "drawable", getPackageName());
  dw[i-1] = getResources().getDrawable(id);
}


參考資料:


SurfaceView

SurfaceView 介面最適合開發顯示速率較快的應用程式。
一張靜態的圖是看不出 SurfaceView 的能力的, 如果要讓圖 "動"起來, 則還需要配合執行緒的運用, 
透過執行緒不斷去改變圖片的座標並反覆貼上圖片, 就可以達到動態的效果。

Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系:
1. Surface:
    屏幕显示内容合成器(screen compositor)所管理的原生缓冲器。
    用来画图形(graphics)或图像(image)的地方。
    常画图是在一个Canvas对象上面进行。
2. SurfaceView:
    通过SurfaceView就可以看到Surface的部分或者全部的内容
    
     
3. SurfaceHolder:
    一个接口,其作用就像一个关于Surface的监听器。
    提供访问和控制SurfaceView背后的Surface 相关的方法
    通过三个回调方法,让我们可以感知到Surface的创建 surfaceCreated、销毁 surfaceDestroyed 或者改变 surfaceChanged 

參考資料:



在 canvas 畫布上貼圖的三個步驟:
1. 鎖住畫布 : canvas = holder.lockCanvas(); 
2. 在畫布上貼圖 : canvas.drawBitmap(bp,x,y,null);
3. 解鎖並po出畫布 : holder.unlockCanvasAndPost(canvas);

SurfaceHolder.Callback 相關聯的三個程序 :
public void surfaceCreated(...) -- surface 建立時
public void surfaceChanged(...) -- surface 改變時
public void surfaceDestroyed(...) -- surface 結束時


參考資料:



用 SurfaceView 與 View 繪圖的差異性:
1. SurfaceView :是在一個新起的單獨執行緒中可以重新繪製畫面
     - 主動更新。比如一個人在一直跑動。這就需要一個單獨的 Thread 不停的重繪人的狀態,避免阻塞主 UI Thread。 (如: 拉霸台 App, 太陽系 App)
2. View :必須在 UI 的主執行緒中更新畫面。
     - 被動更新畫面的。比如棋類,這種用 View 就好了。
     - 因為畫面的更新是賴於 onTouch 來更新,可以直接使用 invalidate。因為這種情況下,這一次 Touch 和下一次的 Touch 需要的時間比較長些,不會產生影響。           (如: 繪圖 App)

在 UI 的主執行緒中更新畫面,可能會引發問題,比如你更新畫面的時間過長,那麼你的主 UI 執行緒會被你正在畫的函數阻塞,那麼將無法回應按鍵,觸屏等消息。
SurfaceView 具有雙緩衝機制。因此,開發遊戲時儘量使用 SurfaceView 而不要使用 View,這樣的話效率較高,而且 SurfaceView 的功能也更加完善。


參考資料:



SurfaceView 刷新特定區域:
內部矩形:比如surfaceview上绘制旋转图片的时候,只刷新一个特定的矩形区域就可以了。
在 "鎖住畫布" 步驟中,加入要刷新的矩形區域:
canvas = holder.lockCanvas(new Rect(0, 0, 130, 130)); //获取画布 像这种带rect参数的就是脏矩形的刷新。


參考資料:


2015年11月29日 星期日

Program, Process, Thread

----------------------------------------------------------------------
1. Program 與 Process 觀念:
----------------------------------------------------------------------
Program:
一群程式碼的集合,用以解決特定的問題。以物件導向的觀念來類比,相當於Class。

Process:
由Program所產生的執行個體,一個Program可以同時執行多次,產生多個Process。以物件導向的觀念來類比,相當於Object。每一個Process又由以下兩個東西組成
    1. 一個Memory Space。相當於Object的variable,不同Process的Memory Space也不同,彼此看不到對方的Memory Space。
    2. 一個以上的Thread。Thread代表從某個起始點開始(例如main),到目前為止所有函數的呼叫路徑,以及這些呼叫路徑上所用到的區域變數。當然程式的執行狀態,除了紀錄在主記憶體外,CPU內部的暫存器(如Program Counter, Stack Pointer, Program Status Word等)也需要一起紀錄。所以Thread又由下面兩項組成
            a. Stack:紀錄函數呼叫路徑,以及這些函數所用到的區域變數
            b. 目前CPU的狀態


參考資料:







----------------------------------------------------------------------
2. Thread的使用
----------------------------------------------------------------------
- Thread 線程:
指運行中的程序的調度單位。一個線程指的是進程(Processes)中一個單一順序的控制流。它是系統獨立調度和分派的基本單位。同一進程中的多個線程將共享該進程中的全部系統資源,比如文件描述符和信號處理等等。 一個進程可以有很多線程,每個線程并行執行不同的任務。.所以意思就是當主程式在進行時,同時又需要去執行別的任務,就可以另起一個Thread(線程),將要執行的內容在背後運作,等到執行完成後,再把結果秀出來

 - Android Thread:
    1. Android於Thread有一個重要的限制「Android為了考量安全性和執行效能,不允許副執行緒直接更改主畫面的資料」,也就是說在我們另起的Thread都沒辦法做出如:將畫面變色與改變文字內容等畫面上的行為,而解決方法就是利用"Handler"來做溝通的橋樑。
    2. MainThread(UI Thread)和Worker Thread:
        a. 所有与UI有关的代码写在MainThread当中。
        b. 主线程不能阻塞,主线程一般不进行耗时较长的操作,比如联网下载,读取大文件等。

 - Android Activity 間传递数据的方法:
Intent对象的基本概念:
    1. Intent是Android应用程序组件之一
    2. Intent对象在Android系统中表示一种意图
    3. Intent当中最重要的内容是action与data
使用Intent在Activity之间传递数据的方法:
    1. 在Activity之间可以通过Intent对象传递数据
    2. 使用putExtra()系列方法向Intent对象当中存储数据
    3. 使用getXXXExtra()系列方法从Intent对象当中取出数据

 - 整個流程是:.
1. 主執行緒開始執行。.
2. 需要Thread(副執行緒)運行比較久的程序,開始執行Thread。.
3. Thread於背景執行(通常附帶時間控管,如Thread.sleep(1000);).
4. Thread完成,傳送訊息告知Handler。.
5. 執行Handler內的邏輯程式,改變畫面內容。


 - 如何產生Thread
1. Class Thread有兩個Constructor: 
    (1) Thread()
    (2) Thread(Runnable)
2. Runnable是一個interface,定義於java.lang內,其宣告為
    public interface Runnable {
      public void run(); 
    }    
3. 使用Thread()產生的Thread,其進入點為Thread裡的run();
4. 使用Thread(Runnable)產生的Thread,其進入點為Runnable物件裡的run()。
5. 當run()結束時,這個Thread也就結束了 。
6. 啟動 thread 時,使用 start() 方法:Thread.start();
7. 清除 thread 時,使thread 為 null: Thread = null;

 (1)Thread thread = new Thread(){
      @Override
        public void run() {

      }
 
 (2)
Thread 
thread = new Thread();
Runnable1 r1  = new Runnable1(“test”);
thread(r1).start();
     
class Runnable1 implements Runnable {
      /* 附加執行的副程式 */
      private String name;

      public Runable1 (String name) {
          this.name = name;
      }
      /* Runnable 主體 */
      public void run(){
   }
};
Thread的優先權
優先權高的Thread其佔有CPU的機會比較高,但優先權低的也都會有機會執行到
Thread.setPriority(int)設定Thread的優先權,數字越大優先權越高。
public static final int MAX_PRIORITY 10 
public static final int MIN_PRIORITY 1 
public static final int NORM_PRIORITY 5
其他有關Thread執行的方法有:
yield():先讓給別的Thread執行
sleep(int time):休息time mini second(1/1000)
join():呼叫ThreadA.join()的執行緒會等到ThreadA結束後,才能繼續執行
Critical Section(關鍵時刻)的保護措施
如果設計者沒有提供保護機制的話,Thread取得和失去CPU控制權的時機是由作業系統來決定
Java的解決辦法是,JVM會在每個物件上擺一把鎖(lock),然後程式設計者可以宣告執行某一段程式,必須拿到某物件的鎖才行,這個鎖同時間最多只有一個執行緒可以擁有它
Ex: 1. 使用string 或 int 等變數 flag 及 if else 判斷式來進行保護。
     2. 
使用 try catch 排除例外狀況
 - Handler、Looper和MessageQueue的基本原理?
Handler把消息对象添加到MessageQueue中,Looper负责从MessageQueue的头部不断取出消息对象,取出一个消息对象之后交给Handler处理。
Message msg = handler.obtainMessage();//获取Message对象
msg.what = 2;//给Message属性赋值,msg.obj = s; // 6. 把s赋值给obj
handler.sendMessage(msg);//把消息对象放到消息队列当中去
//1. Looper将会从消息队列当中将消息对象取出,
//2. Looper将会找到与消息对象对应的Handler对象(每一个消息对象都有一个对应的Handler对象)。
//3. Looper将会调用消息对象的handleMessage(Message msg)方法,用于处理该消息对象

EX:
public class MainActivity enxtends Activity {
private Textview textview;
private Button button;
private Handler handler; //3. 定义一个变量
@Override
protected void conCreate(Bundle savedInstanceState) {
super.onCreate(savedINstanceState);
setContentView(R.layout.activity_main);

textView = (TextView)findViewById(R.id.textViewId);
button = (Button)findViewById(R.id.buttonId);

handler = new Myhandler(); //4.使用Myhandler类生成对象

button.setOnClickListener(new ButtonListener());//绑定监听器
}

class MyHandler extends Handler { 
//1.首先定义一个handler的实现类,继承Handler
@Override
public void handleMessage(Message msg) {
//2. 然后实现handleMessage方法

System.out.println("handleMessage--->" + Thread.currentThread().getName()); // 测试说明:打印当前线程的名字

String s= (String)msg.obj; // 8. 在主线程中将数值取出
textView.setText(s); //在主线程中操作UI

}
}

class ButtonListener implements OnClickListener {

@Override
public void onClick(View v) {
Thread t = new NetWorkThread();
t.start();
}
}

class NetworkThread extends Thread {
//本线程为Worker Thread
//@Override
public void run(){

System.out.println("network--->" + Thread.currentThread().getName()); // 测试说明:打印当前线程的名字

//模拟访问网络,所以当线程运行时,首先休眠2秒
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//变量s的值,模拟从网络中获取的数据
String s = "网络中的数据";
//textView.setText(s);//这样的操作是错误的,安卓系统中UI操作原则上只能在主线程中进行

Message msg = handler.obtainMessage(); // 5.生成Message对象
//sendMessage方法无论在主线程中发送还是在Worker Thread中发送都可以,这里在WorkerThread当中发送,然后在主线程将消息取出。
msg.obj = s; // 6. 把s赋值给obj
handler.sendMessage(msg); // 7. 调用sendMessage方法发送消息

}
}

}


參考資料:






----------------------------------------------------------------------
3. 安全中止一個Thread
----------------------------------------------------------------------
class MyThread implements Runnable{
      public void run() {
       // TODO Auto-generated method stub
       //  定义自己的变量
      while(!Thread.currentThread().isInterrupted()){
                try { 
                       doSomeThingNeed();//需要更新的操作   
                                                         //休眠控制最大帧率为每秒3绘制30次
                       Thread.sleep(30);
                } catch (Exception e) {
                       // TODO: handle exception
                       Log.v(tag2, "DrawSurfaceView:绘制失败...");
                       Thread.currentThread().interrupt();
                } 
       }
}


參考資料:







----------------------------------------------------------------------
4. Thread傳Message到Handler
----------------------------------------------------------------------
Thread中並沒有辦法改變畫面上的任何UI,所以會使用Handler來完成UI更新的目的
在 Android 中,Activity 可透過 Handler 傳遞Message 去切換不同的 UI 介面 (setContentView( ViewSurfaceViewR.Layout.xml_file )
但在計算中並不是都會正確的完成,所以在Handler中也必須判斷Thread的執行狀況來做出不同的反應,那麼就必須依靠Message來完成兩者間的資訊傳遞
1. 建立一個Thread,並傳遞指定相關資訊到Message中,利用handler.sendMessage傳遞出去。
Thread thread = new Thread(){  @Override  public void run() {  Message message;
  String obj = "OK";  message   handler.obtainMessage(1,obj);  handler.sendMessage(message);
  }
thread.start();
thread = null;
2. handler中依照傳遞的訊息做出相對應的反應
private Handler DOFindAttributehandler = new Handler(){    @Override    public void handleMessage(Message msg) {          super.handleMessage(msg);
          String MsgString = (String)msg.obj;
          if (MsgString.equals("OK"))          {
          ......
          } 
     }
};
P.S Override 為覆寫繼承之父類別中的方法,若覆寫完後仍須使用原方法時,即用super (指向繼承之父類別)


參考資料:


 - 範例:500毫秒,TextView 向上計數一次 : http://givemepass.blogspot.tw/2011/11/threadhandler.html
在 main thread 執行時,會產生 ANR (Application is Not Responding)的對話框,並且終止程式
text = (TextView)findViewById(R.id.textView);
int i =0;
while(true){ // 無窮迴圈造成 ANR
    i++;
    text.setText(Integer.toString(i));
}

         new Thread(new Runnable(){
                @Override        
                public void run() {
                // TODO Auto-generated method stub          
                while(true){ // 保護機制
                    try{
                        Message msg = new Message();
                        msg.what = 1;
                        mHandler.sendMessage(msg);
                        Thread.sleep(500); // 休息500ms
                    }
                   catch(Exception e){
                        e.printStackTrace();
                    }        
                }
              }           
           }).start();
             text = (TextView)findViewById(R.id.textView);
             mHandler = new Handler(){
             int i = 0;
             @Override
             public void handleMessage(Message msg) {
                    switch(msg.what){
                    case 1:
                            i++;
                            text.setText(Integer.toString(i));
                    break;
                    }
                    super.handleMessage(msg);
                } 
            };


參考資料: