2015年11月29日 星期日

extends, implements, interface


在java中如果用戶編寫類的時候沒有提供構造函數 (建構式),那麼編譯器會自動提供一個默認構造函數
它會把所有的實例字段設置为默認值:所有的數字變量初始化为0;所有的布爾變量設置为false;所有對象變量設置为null;
ex :
public class myClass {
    // 建構式
    public myClass(){ 
   
    }
}




 - extends 繼承:
java中的繼承,和C++中是有差別的.比如JAVA不支持多重繼承。但是JAVA可以通過implements來實現額外的接口.

ex :DogDeriveClass就全盤繼承了AnimalBaseClass中的所有方法;
public
{
    // 建構式
    public myClass(){ 
   
    }
};

如果還需要其它功能,那麼則可以通過implements關鍵字來實現需要用到的接口.
ex :
public class DogDeriveClass extends AnimalBaseClass Implements Shout, Run
{
    // 建構式
    public myClass(){ 
   
    }
};




 - implements 實現:
Implements關鍵字在class聲明中使用,以指示所聲明的類提供了在implements關鍵字後面的名稱所指定的接口中所聲明的所有方法的實現。
接口中的方法不能是static,因为static不能被派生類重寫(Override)

ex

public class UserSurfaceView extends SurfaceView implements Android.view.SurfaceHolder.Callback  
{
     @Override 
     public void surfaceChanged(SurfaceHolder holder, int format, int with, int heigh)
     {
     //TODO Auto-generated method stub
     }
    @Override
     public void surfaceCreated(SurfaceHolder holder)
     {
     //TODO Auto-generated method stub
     }
     @Override
     public void surfaceDestroyed(SurfaceHolder holder)
     {
     //TODO Auto-generated method stub
     }
};



 - interface 接口:
介面有點像是完全沒有任何方法被實作的抽象類別,但實際上兩者在語義與應用上是有差別的。
1. 「繼承某抽象類別的類別必定是該類別的一個子類」透過繼承父類別型態進行多型操作。
2. 「實作某介面的類別並不被歸屬於哪一類」:一個物件上可以實作多個介面。


介面的宣告是使用"interface"關鍵字,宣告方式如下:
interface 介面名稱 {
    傳回型態 方法(參數列);
    傳回型態 方法(參數列);

    // ....
}

ex
public interface Android.view.SurfaceHolder.Callback 
{
         void surfaceChanged(SurfaceHolder holder, int format, int with, int heigh);
        void surfaceCreated(SurfaceHolder holder);
        void  surfaceDestroyed(SurfaceHolder holder);
};
由於接口中的方法聲明默認就是public的,因此不需要特意加上public修飾符.

ex :  自定義一個 Class 繼承 Dialog 的自創對話框介面,透過 Interface Function 自訂義此 Class之button 的 myOnClickListener。
使用此 myOnClickListener 來執行 外部所對應的動作:

 MyDialog 部分:

public class MyDialog extends Dialog {
    public MyDialog(Context context, myOnClickListener myclick) {
        super(context);
        this.myListener = myclick;
    }
    public myOnClickListener myListener;
         
        // This is my interface //
    public interface myOnClickListener {
        void onButtonClick();
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.alert);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new android.view.View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // 外部所宣告 interface function : myOnClickListener
                // 將會插入在此處,並執行其內容。 
                myListener.onButtonClick(); // I am giving the click to the
                                            // interface function which we need
                                            // to implements where we call this
                                            // class
            }
        });
    }
}

 - main Activity

import com.coderzheaven.interfacedemo.MyDialog.myOnClickListener;
...


public class MainActivity extends Activity {
    public myOnClickListener myListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // create new onclicklistener interface //
        myListener = new myOnClickListener() {
            @Override
            public void onButtonClick() {
                System.out.println("I am clicking the button in the dialog");
                Toast.makeText(getApplicationContext(),
                        "I am clicking the button in the dialog",
                        Toast.LENGTH_LONG).show();
            }
        };
        MyDialog mydialog = new MyDialog(this, myListener);
        mydialog.show();
    }
}


參考資料:

Canvas, Bitmap, Drawable



Bitmap指的是你今天有一張圖片存在電腦,
它的格式可能是bmp, jpg, png或者gif, 常看到的是這幾個,
而Android剛好也支援這幾個, 因此我們可以用Bitmap這個類別的物件,
將我們的圖檔讀進Android, 通常讀進去以後它就變成串流模式(Stream),

View你可以想像成一種容器, 它可以用來裝你的Bitmap,
根據你事先排好的格式, 然後呈現在畫面上,
那系統因應user的需求, 也制定了一些需要的View容器給大家來使用,
例如ImageView、GridView、ListView、Button、EditText...等等。

Canvas就是一張畫布, 上面可以讓你畫你想畫的東西,
你可以想像成他就是小畫家工具,你想畫一條線, 一個矩形...等等,都可以。
那畫完以後把它裝到容器裡面,容器有哪些?
就是我們前面講的ImageView、GridView、ListView...等等, 就是系統幫我們做好的容器,
把我們畫的東西包成一個容器,容器裡面裝的是我們的畫布。

Drawable有時候我們會想要畫矩形, 畫圓形或者畫弧形之類的,
而如果是自己用手畫, 很容易, 但是如果是用程式畫,
你就必須自己設定角度、長度、大小、顏色等屬性,
這些步驟有點麻煩, 因此通常都會設定好一個框架讓你使用,
只需要你指定屬性值, Android就會幫你設計好, 不用在自己設計一套,
例如Drawable的子類別ShapeDrawable就可以幫你完成許多圖形,
ArcShape, OvalShape, RectShape...等等。


Paint就是畫筆, 你在小畫家上面畫畫的時候,
都會選擇畫筆來作畫, 像顏色, 粗細等之類的屬性,
將結果畫在畫布上面,通常Paint都會跟在Drawable的相關類別或者自定View類別一起使用。

ex: 取得Drawable的畫筆, 將畫筆改成藍色,最後完成藍色的矩形。
public class CustomDrawableView extends View{
    private ShapeDrawable mDrawable;
    private Paint mPaint;
    private int x = 0;
    private int y = 0;
    private int width = 100;
    private int height = 50;
    public CustomDrawableView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        mDrawable = new ShapeDrawable(new RectShape());
        mDrawable.setBounds(x,y,x+width,y+height);
   
        mPaint = mDrawable.getPaint();
        mPaint.setColor(Color.BLUE);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        mDrawable.draw(canvas);
    }
}






-----------------------------------
1. Bitmap 使用方法:
-----------------------------------

* 重點注意事項:
可配合 BitmapFactory 將 ByteArray, File, Resource, Stream 轉為 bitmap 物件。
同時可選配 BitmapFactory.Options 來設定 Bitmap 內容。

 - BitmapFactory 
decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
decodeFile(String pathName, BitmapFactory.Options opts)
decodeResource(Resources res, int id, BitmapFactory.Options opts)
decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)
 - BitmapFactory.Options
inJustDecodeBounds // 取得 Bitmap 參數,但不回傳 bitmap
inInputShareable
inPurgeable
inSampleSize // 設定取樣尺寸, 以此壓縮 尺寸來減少記憶體消耗
outHeight
outWidth

常用參數:
getHeight()
getWidth()
getScaledHeight(DisplayMetrics metrics)  //參考 display 解析度
getScaledWidth(DisplayMetrics metrics) //參考 display 解析度
setHeight(int height)
setHeight(int height)
isRecycled()

常用方法:
 - createBitmap
createBitmap(Bitmap source, int x, int y, int width, int height)
createBitmap(int width, int height, Bitmap.Config config)
createBitmap(DisplayMetrics display, int width, int height, Bitmap.Config config)
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
 - 其他效果
createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
eraseColor(int c) //擦除颜色(INT C)
extractAlpha() //提取阿尔法()
recycle()

EX: 先讀取常寬,再縮放重制
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);

int width=options.outWidth;
int height=options.outHeight;
float scale = 1000/height;

options = new BitmapFactory.Options();

options.inPurgeable = true;
options.inInputShareable = true;
options.inSampleSize=(int)scale;
Bitmap newbp = BitmapFactory.decodeByteArray(data, 0, data.length, options);


參考資料:

EX: Bitmap Touch 點擊事件

@Override
public boolean onTouchEvent(MotionEvent event)
{
    float x = event.getX();
    float y = event.getY();
    switch(event.getAction())
    {
        case MotionEvent.ACTION_DOWN:
        //Check if the x and y position of the touch is inside the bitmap
        if( x > bitmapXPosition && x < bitmapXPosition + bitmapWidth && y > bitmapYPosition && y < bitmapYPosition + bitmapHeight )
        {
            //Bitmap touched
        }
        return true;
    }
    return false;
}

How to make a bitmap using canvas clickable? :http://stackoverflow.com/questions/18826808/how-to-make-a-bitmap-using-canvas-clickable






-----------------------------------
2. Canvas 使用方法:
-----------------------------------
* 重點注意事項:
可繪製文字、圖型、顏色、圖片( 可參考 Rect 或 Matrix ,進行縮放或變形處理 )

常用參數:
getHeight
getWidth
getMatrix
getMaximumBitmapHeight
getMaximumBitmapWidth

常用方法:
drawARGB
drawColor
drawPoints  // 畫點
drawPath     // 畫線
drawArc       // 畫圓弧
drawOval     // 畫橢圓
drawCircle
drawLine, drawLines

drawText
drawRect
drawRoundRect
drawBitmap  (Bitmap bitmap, Matrix matrix, Paint paint), drawBitmap(Bitmap bitmap, Rect srcRectF dst, Paint paint)

rotate
scale
translate
skew            // 傾斜
restore()
save

EX:
1. 將文字繪製 Bitmap 上

Bitmap tempBp = Bitmap.createBitmap(PidBitmap.getWidth(), PidBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas tempCv = new Canvas(tempBp); // 依 tempBp 為基底
canvas.drawText( "Android Canvas" , center_x , center_y, mPaint);
canvas.restore();
// 透過 Canvas 在 tempBp 上繪製處理後,tempBp 將自動儲存變為新的結果 

2. 用於 SurfaceView 的繪製方式,透過 save and restore 來刷新視屏
canvas.save();
canvas.drawColor(Color.WHITE); // 繪製填滿色
canvas.rotate(45, center_x, center_y);
canvas.drawText( "Android Canvas" , center_x , center_y, mPaint);
canvas.restore();



參考資料:




-----------------------------------
3. Drawable 使用方法:
-----------------------------------
Drawable就是一個可畫的對象,其可能是一張位圖(BitmapDrawable),也可能是一個圖形(ShapeDrawable),
還有可能是一個圖層(LayerDrawable),我們根據畫圖的需求,創建相應的可畫對象
有別於 View,Drawable 沒有任何 facility 來接收處理事件和互相作用關係。
結合與 Drawable Resources ,用於動態圖片或圖片編輯中。

1、將Drawable轉化为Bitmap 
public static Bitmap drawableToBitmap(Drawable drawable) {   
        // 取 drawable 的長寬   
        int w = drawable.getIntrinsicWidth();   
        int h = drawable.getIntrinsicHeight();   
   
        // 取 drawable 的顏色格式   
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888   
                : Bitmap.Config.RGB_565;   
       // 建立對應 bitmap   
        Bitmap bitmap = Bitmap.createBitmap(w, h, config);   
        // 建立對應 bitmap 的畫布   
        Canvas canvas = new Canvas(bitmap);   
        drawable.setBounds(0, 0, w, h);   
        // 把 drawable 內容畫到畫布中   
        drawable.draw(canvas);   
        return bitmap;   
    }  

2、Bitmap轉換成Drawable 
Bitmap bm=xxx; //xxx根據你的情況獲取   
BitmapDrawable bd= new BitmapDrawable(getResource(), bm);    
因为BtimapDrawable是Drawable的子類,最終直接使用bd對象即可。

3、Drawable縮放 
public static Drawable zoomDrawable(Drawable drawable, int w, int h) {   
    int width = drawable.getIntrinsicWidth();   
   int height = drawable.getIntrinsicHeight();   
    // drawable轉換成bitmap   
    Bitmap oldbmp = drawableToBitmap(drawable);   
    // 創建操作圖片用的Matrix對象   
   Matrix matrix = new Matrix();   
    // 計算縮放比例   
    float sx = ((float) w / width);   
    float sy = ((float) h / height);   
    // 設置縮放比例   
    matrix.postScale(sx, sy);   
    // 建立新的bitmap,其內容是對原bitmap的縮放後的圖   
    Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,   
            matrix, true);   
    return new BitmapDrawable(newbmp);   
}  

4利用ImageView 在畫面上顯示圖片

【第一種方式】xml layout 中 設定 src 屬性,讀取res/drawable中的圖片

【第二種方式】利用ImageView類別的方法,將res/drawable 中的圖片載入
    secondImage = (ImageView) findViewById(R.id.imageView2);
    secondImage.setImageResource(R.drawable.firefox);

【第三種方式】網址(url)抓到圖片再顯示
    thirdImage = (ImageView) findViewById(R.id.imageView3);
    thirdImage.setImageDrawable(loadImageFromURL("http://cdn.inside.com.tw/wp-content/uploads/2012/05/Chrome.jpg")); 


    private Drawable loadImageFromURL(String url){
        try{
            InputStream is = (InputStream) new URL(url).getContent();
            Drawable draw = Drawable.createFromStream(is, "src");
            return draw;
        }catch (Exception e) {
            //TODO handle error
            Log.i("loadingImg", e.toString());
            return null;
        }
    }



參考資料:


Camera 與 Gallery 使用

--------------------------------------------
1. Camera
--------------------------------------------

Android中應用相機功能,一般有兩種:

 - Method 1:調用系統相機,使用Intent跳轉到系統相機,action
    在 manifests xml 中 加入 Camera 權限 和 外部存取權限 來抓取相機拍照後所回傳的結果相片。

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

     - 在 Main.java 中所使用的 function 方法:
    private final static int CAMERA = 66 ;

    // get Display Height and Widht pixel
    private DisplayMetrics metrics; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 抓取 display 變數 
        metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }

    private void goCamera() {
        // Start an intent for Camera Capture with ResultActivity
        Intent cameraIntent = new Intent(
                android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        try {
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());
            if (cameraIntent.resolveActivity(getPackageManager()) != null) {
                startActivityForResult(cameraIntent, CAMERA);  //設定回傳 resultCode
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

            // Put and Draw Selected Photo in SurfaceView
            Uri imageUri = null;
            InputStream inputStream = null;
            if ( requestCode == CAMERA ){
                // 將拍照完的圖片儲存再 m_imagePath 路徑內,以便讀圖編輯
                try {
                    if (data!=null){
                        // 其他相機程式回傳的 uri
                        imageUri = data.getData();
                    } else {
                        // 內建相機程式回傳的 uri
                        File file = new File(m_imagePath);
                        imageUri = Uri.fromFile(file);
                    }
                    inputStream = getContentResolver().openInputStream(imageUri);
                    try {
                        Bitmap getbp =  ScaleLoadBitmapByOption(getBytesFromInputStream(inputStream), 
                                                                                               metrics.widthPixels,
                                                                                               metrics.heightPixels);

                    }catch (OutOfMemoryError e) {
//                    Toast.makeText(Phone2.this, "Out Of Memory", Toast.LENGTH_SHORT).show();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
    }

- Method 2. 自己寫的相機
    1. SurfaceView顯示照相機中的預覽效果,        - Camera類提供:
            a. 一個 setPreviewDisplay( SurfaceHolder ) 的方法來連接 surfaceHolder, 並通過他來控制 surfaceView。
            b. startPreview() 和 stopPreview() 來開启和關閉預覽.
    2. 開启相機.Camera.open() 這是個靜態方法,如果相機沒有別人用着,則會返回一個 相機引用,如果被人用着,則會拋出異常。
    3. 不能放在構造方法或者 onCreate() 方法中,會照成沒有預覽效果.
    4. 當開始拍照時,會依次調用:
            a. shutter的onShutter()方法,  shutter--拍照瞬間調用
            b. raw的onPictureTaken方法 ,  raw--獲得沒有壓縮過的圖片數據
            c. jpeg的onPictureTaken方法 . jpeg---返回jpeg的圖片數據

    5. 透過控制裝置相機,來拍好圖片。
            a. 其設置相關的参數:
                Camera.Parameters parames = myCamera.getParameters();        //獲得参數對象
                parames.setPictureFormat(PixelFormat.JPEG);                             //設置圖片格式
                parames.setPreviewSize(640,480);                                                 //這裏面的参數只能是幾個特定的参數,否則會報錯.                                                                                                                                                                                    //(176*144,320*240,352*288,480*360,640*480)
                myCamera.setParameters(parames);
            b. 自動對焦方法:
                myCamera.autoFocus();                                                                   //這個方法必須在startPreview()和stopPreview()中間。(有些手機沒有此功能)
                AutoFocusCallback是自動對焦的接口,實現它必須實現public void onAutoFocus(boolean success, Camera camera)這個方法

- 在 manifests xml 中 加入 Camera 權限 和 外部存取權限 來抓取相機拍照後所回傳的結果相片。
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.autofocus" />

 - CameraTest_4.java - 
import android.app.Activity;  
....
import android.view.View.OnClickListener;  

public class CameraTest_3 extends Activity implements Callback, OnClickListener, AutoFocusCallback {  

     SurfaceView mySurfaceView;         //surfaceView聲明  
     SurfaceHolder holder;                     //surfaceHolder聲明  
     Camera myCamera;                      //相機聲明  
     String filePath="/sdcard/wjh.jpg";    //照片保存路徑  
     boolean isClicked = false;               //是否點擊標識  

     //創建jpeg圖片回調數據對象 
     PictureCallback jpeg = new PictureCallback() {   
          
        @Override  
        public void onPictureTaken(byte[] data, Camera camera) {   
            // TODO Auto-generated method stub  
             try  {// 獲得圖片  
                    Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);   
                    File file = new File(filePath);   
                    BufferedOutputStream bos =  new BufferedOutputStream(new FileOutputStream(file));  
                    bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//將圖片壓縮到流中  
                     bos.flush();//輸出   
                    bos.close();//關閉   
            }catch(Exception e)   {   
                e.printStackTrace();  
            } 
        }   
    };  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState); 
        requestWindowFeature(Window.FEATURE_NO_TITLE);                                              //無標題  
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);   //設置拍攝方向  
        setContentView(R.layout.main);  

        mySurfaceView = (SurfaceView)findViewById(R.id.surfaceView1);                                //獲得控件  
        holder = mySurfaceView.getHolder();                                                                              //獲得句柄 

        holder.addCallback(this);                                                                                                 //添加回調
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);                          //設置類型 
        mySurface.setOnClickListener(this);                                                                               //設置監聽 
    }

    @Override  
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {   
        // TODO Auto-generated method stub   
        //設置参數並開始預覽  
        Camera.Parameters params = myCamera.getParameters();  
        params.setPictureFormat(PixelFormat.JPEG);   
        params.setPreviewSize(640,480);   
        myCamera.setParameters(params);   
        myCamera.startPreview();  
    }  

    @Override   
    public void surfaceCreated(SurfaceHolder holder) {  
        // TODO Auto-generated method stub  
        //開启相機  
        if(myCamera == null)  {   
            myCamera = Camera.open();  
            try {  
                myCamera.setPreviewDisplay(holder);  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
             }  
        }           
    }  

    @Override   
    public void surfaceDestroyed(SurfaceHolder holder) {  
        // TODO Auto-generated method stub   
        //關閉預覽並釋放資源  
        myCamera.stopPreview();  
        myCamera.release();   
        myCamera = null;           
    }  

    @Override  
    public void onClick(View v) {  
        // TODO Auto-generated method stub  
        if(!isClicked)  {   
            myCamera.autoFocus(this);//自動對焦   
            isClicked = true;   
        }else  {  
             myCamera.startPreview();//開启預覽  
             isClicked = false;  
        }          
    }

    @Override  
    public void onAutoFocus(boolean success, Camera camera) {  
        // TODO Auto-generated method stub  
        if(success)  {  
            //設置参數,並拍照  
             Camera.Parameters params = myCamera.getParameters();   
             params.setPictureFormat(PixelFormat.JPEG);  
             params.setPreviewSize(640,480);  
             myCamera.setParameters(params);   
             myCamera.takePicture(null, null, jpeg);  
        }  
    }  
}


參考資料:







--------------------------------------------
2. Gallery
--------------------------------------------

讀取 Android gallery 中 相簿相片:

    在 manifests xml 中 加入 外部存取權限 來抓取相簿後所回傳的結果相片。
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

     - 在 Main.java 中所使用的 function 方法:
    private final static int PHOTO= 66 ;

    // get Display Height and Widht pixel
    private DisplayMetrics metrics; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 抓取 display 變數 
        metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }

    private void goAlbums() {
        // Start an intent for user Albums with ResultActivity
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(intent, PHOTO);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

            Uri imageUri = null;
            InputStream inputStream = null;
            if (requestCode == PHOTO && data != null)
            {
                try{
                    imageUri = data.getData();
                    inputStream = getContentResolver().openInputStream(imageUri);
                    try {
                         Bitmap getbp = ScaleLoadBitmapByOption(getBytesFromInputStream(inputStream), // bytes[]
                                                                                               metrics.widthPixels,
                                                                                               metrics.heightPixels));
                    }catch (OutOfMemoryError e) {
//                    Toast.makeText(Phone2.this, "Out Of Memory", Toast.LENGTH_SHORT).show();
                    }
                } catch (IOException e) {
//                Toast.makeText(Phone2.this, "File Error", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
                }
            }
    }





--------------------------------------------
3. Sub-Function 
--------------------------------------------

    //--------------------------------------------
    // LoadFileToBitmap and TransFileToBytes
    //--------------------------------------------
    private Bitmap ScaleLoadBitmapByOption(byte[] data, int dspW, int dspH){
//        //Only decode image size. Not whole image
//        BitmapFactory.Options options = new BitmapFactory.Options();
//        options.inJustDecodeBounds = true;
//        BitmapFactory.decodeByteArray(data, 0, data.length, options);
//        //The new size to decode to dspW and dspH
//        //Now we have image width and height. We should find the correct scale value. (power of 2)
//        int width=options.outWidth;   //
//        int height=options.outHeight;
//        float scale = 0;
//        if (width > dspW || height > dspH){
//            if (height > width){
//                scale = height/dspH;
//            }else if (width > height){
//                scale = width/dspW;
//            }
//        }else{
//            scale = 1;
//        }
        //Decode again with inSampleSize
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPurgeable = true;
        options.inInputShareable = true;
//        options.inSampleSize=(int)scale;
        return BitmapFactory.decodeByteArray(data, 0, data.length, options);
    }
    private static byte[] getBytesFromInputStream(InputStream is) throws IOException {
        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024]; //
        int len = -1;
        while ((len = is.read(buffer)) != -1) {
            outstream.write(buffer, 0, len);
        }
        outstream.close();
        return outstream.toByteArray();
    }


參考資料: