2012-08-30

PhoneGap API應用:Camera相機(一) - 用相機拍照後用img顯示出來

最近因為比較忙一些專案,所以比較沒空寫blog文章

因為之前寫Native App(原生應用程式)比較多,Mobile App的部份相對的就比較少

所以今後會先寫一幾篇Mobile App,Android的開發是很廣泛的,不限定一定要用

怎樣的方式開發,像電子報來說,你可以用Native的方式開發,也能用PhoneGap

的Mobile app方式開發,這都是可行的,所以開發是沒有一定的形式,在於使用

者和設計者的喜好和習慣,這兩種開發方式都有其優缺點,優缺點我在這裡有介紹

過了,各位可以參考,好!以上是我的完全和本文無關的碎碎唸,系列文章第一篇的

廢話都是比較多的請見諒,接下來進入主題。

我會針對PhoneGap API的各大項API做各別應用上的大略介紹,實際在開發上各位還

是要針對需求做自我轉變,我不可能都猜到各位實際開發上會怎麼使用它,如果都猜

得到,我就改行當算命的了XD(誤)。

如果建立、安裝及設定Phonegap因為之前我就有介紹過了PhoneGap安裝,所以之後系列

應用上就都直接貼上程式碼,不再重覆介紹了,請見諒!,直接PO上JavaScript程式碼再來說明。


JavaScript程式碼
<script type="text/javascript" charset="utf-8">
       
       //功用和onload相同
       document.addEventListener("deviceready", onDeviceReady, false);
    
    function onDeviceReady() {
        // Empty
    }
 //一個按鈕將調用這個函數
    function capturePhoto() {
       // 取得圖像(成功事件 ,失敗事件,{圖片設定});
      // getpicture(cameraSuccess,cameraError,{cameraOptions});
      navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50 });
    }
    //照片是成功檢索時調用
    function onPhotoDataSuccess(imageData) {
      //取消註釋,以查看base64編碼的圖像數據
      // console.log(imageData);

      //獲取的圖像處理
      var smallImage = document.getElementById('smallImage');

      //取消隱藏的圖像元素
      smallImage.style.display = 'block';

      //顯示拍攝的照片
      //內聯 CSS規則是用來調整圖像的大小
      smallImage.src = "data:image/jpeg;base64," + imageData;
    }

    //錯誤發生時 
    function onFail(message) {
      alert('Failed because: ' + message);
    }
      </script>


html元件
<button onclick="capturePhoto();">Capture Photo</button>
<img style="display:none;width:60px;height:60px;" id="smallImage" src="" />


實作出來的畫面:

跳出來的選取相機和Native中的使用其他服務幫忙拍照類似


拍照後,圖片就直接出現在img內



說明:

看得懂JavaScript的應該自己看程式碼就知道了,全部的重點就是
navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50 });

再來就是顯示圖片 smallImage.src = "data:image/jpeg;base64," + imageData;

以上是為您做的簡單介紹,謝謝。


2012-08-21

Android Adapter家族系列(三) - BaseAdapter

今天介紹Adapter家族內一個本人還蠻常用到的子類別BaseAdapter

幾乎元件在使用自定義的方式呈現時最常出現的一個子類別

因為自定義的view是自由設定的,所以不能像ArrayAdapter只是單純

只帶入資料而已,必須對view內的元件也做設定及加入事件等

也就是說主要的Activity只是建構此子類別,帶入相關需要的參數

其他的自定義view元件想要怎麼加、想要怎麼設定、做什麼事

都是在BaseAdapter內做設定就可以了,這樣說應該聽了還是霧煞煞

我們用實際的程式碼來邊做邊說明好了。

這裡我們用自定義的ListView來做說明:

ListView listView01 = (ListView)findViewById(R.id.listView1); 
     CharSequence[] list = MemorandumDate;
     CharSequence[] list2 = MemorandumNote;
     CharSequence[] list3 = MemorandumPW;
     BaseAdapter adapter = new MyAdapter(this, list, mID, list2, list3, mreminder);  
     listView01.setAdapter(adapter);

說明:
在主要的Activity中,找到ListView元件,然後我們建構一個適配器adapter

CharSequence[]是字元陣列,用來儲存文字用的,我同時在其他地方有宣告三個字元陣列

(list、list2、list3),也分別給於其值(此部份請自己依所需撰寫)及兩個整數陣列(mID、mreminder)

帶入建構子中建構該元件後帶入ListView,要帶入什麼參數和參數的順序是依照規劃MyAdapter這個

BaseAdapter子類別時怎麼開的,這裡就會是需要什麼樣的參數和順序,下面貼出MyAdapter的程式碼。


package jim.memorandum;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class MyAdapter extends BaseAdapter{  
 public LayoutInflater myInflater;
 public Context context;
    CharSequence[] mDate = null;
    CharSequence[] mData = null;
    CharSequence[] mPw = null;
    int[] MID = null;
    int[] mreminder = null;
    
    public MyAdapter(Context ctxt, CharSequence[] mdate,int[] mID,CharSequence[] mdata,CharSequence[] mpw,int[] mreminder){
        myInflater = LayoutInflater.from(ctxt);
        this.mDate = mdate;
        this.MID = mID;
        this.mData = mdata;
        this.context = ctxt;
        this.mPw = mpw;
        this.mreminder = mreminder;
    }

 public int getCount() {
  // TODO Auto-generated method stub
  return MID.length;
 }

 public Object getItem(int position) {
  // TODO Auto-generated method stub
  return MID[position];
 }

 public long getItemId(int position) {
  // TODO Auto-generated method stub
  return position;
 }

 public View getView(int position, View convertView, ViewGroup parent) {
  final int index = position;
         
  ViewTag viewTag;
        
        if(convertView == null){
            
            convertView = myInflater.inflate(R.layout.list_data, null);
            
           
            viewTag = new ViewTag(
                    (TextView)convertView.findViewById(R.id.tv_Date),
                    (TextView)convertView.findViewById(R.id.tv_Data),
                    (ImageButton)convertView.findViewById(R.id.ibtn_edit),
                    (ImageButton)convertView.findViewById(R.id.ibtn_del),
                    (ImageView)convertView.findViewById(R.id.img_remind),
                    (ImageView)convertView.findViewById(R.id.img_lock)
                    );
            
            convertView.setTag(viewTag);
        }
        else{
            viewTag = (ViewTag) convertView.getTag();
        }
        
        //如果有設定密碼就只顯示前五個字
        String stitle =""; 
        if(!mPw[position].toString().equalsIgnoreCase("")){
         stitle = mData[position].toString();
         if(stitle.length() &gt; 3){
         stitle = stitle.subSequence(0, 3) + "...";
         }
         else
         {
          stitle = mData[position].toString();
         }
        }
        else
        {
         stitle = mData[position].toString();
        }
        
        viewTag.tvdata.setText(stitle);
        viewTag.tvdate.setText(mDate[position].toString());    
        
        //提醒
        if(mreminder[index] == 1)
        {
           viewTag.img_reminder.setImageResource(R.drawable.checkbox_on);
        }
        else
        {
          viewTag.img_reminder.setImageResource(R.drawable.checkbox_off);
        }
           
       
        //是否有密碼
        if(!mPw[index].toString().equalsIgnoreCase(""))
        {
           viewTag.img_lock.setImageResource(R.drawable.lock_on);
        }
        else
        {
          viewTag.img_lock.setImageResource(R.drawable.lock_off);
        }
        
        
        //修改按鈕
        final ImageButton btn_edit = (ImageButton) convertView.findViewById(R.id.ibtn_edit);
        btn_edit.setOnClickListener(new View.OnClickListener()  {
          public void onClick(View v)  {
         
         //有密碼時必須輸入密碼
         if(!mPw[index].toString().equalsIgnoreCase(""))
         {
          LayoutInflater factory=LayoutInflater.from(context);
           //得到自定義對話框
                final View DialogView=factory.inflate(R.layout.dialog, null);
                
                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setTitle("請輸入密碼");
                builder.setCancelable(false);
                builder.setView(DialogView); //設置自定義對話框樣式
             builder.setPositiveButton("送出", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                       try
                         {
                            EditText pw = (EditText)DialogView.findViewById(R.id.pw_dialog);//輸入之密碼
                            //驗證密碼是否相同
                            String sPW1 = mPw[index].toString();//原密碼
                            String sPW2 = pw.getText().toString();//驗證密碼
                            if(sPW1.equals(sPW2))
                            {
                             //相同就進入 
                                Intent intent_request = new Intent(context, Edit.class);
                                String val=String.valueOf(MID[index]);
                                intent_request.putExtra("val", val); 
                                context.startActivity(intent_request);    
                              
                            }else
                            {
                             //不相同時顯示密碼錯誤
                                Toast.makeText(context,"密碼錯誤!", Toast.LENGTH_SHORT).show(); 
                            }                   
                          }catch(Exception e)
                          {
                             e.printStackTrace();
                          }
                  }
             });
             
             builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
              }
             });  
                
             AlertDialog alert = builder.create();
             alert.show();
             
         }else
         {
          Intent intent_request = new Intent(context, Edit.class);
             String val=String.valueOf(MID[index]);
             intent_request.putExtra("val", val); 
                context.startActivity(intent_request);
         }
          }
        });
        
        //刪除按鈕
        final ImageButton btn_del = (ImageButton) convertView.findViewById(R.id.ibtn_del);
        btn_del.setTag(position);
        btn_del.setOnClickListener(new View.OnClickListener()  {
         
          public void onClick(View v)  {
           AlertDialog.Builder builder = new AlertDialog.Builder(context);
           
           builder.setMessage("確定要刪除?");
           builder.setCancelable(false);
           
           builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int dialog_id) {
           SQLiteDatabase db;
           NewListDataSQL helper = new NewListDataSQL(context, "MemorandumSQL");
           db = helper.getReadableDatabase();
           long long1 = db.delete("newMemorandum", "_ID=" + MID[index], null);               
        //添加成功後返回行號,失敗後返回-1
      if (long1 == -1) {
       Toast.makeText(context,
         "刪除失敗!", Toast.LENGTH_SHORT)
         .show();
      } else {
       Intent intent = new Intent(context, MemorandumActivity.class);
                context.startActivity(intent);
                quit();//關閉,讓back鍵不會出現上一頁
      }
    
                }
            });
           builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int id) {
          }
         });   
         
         AlertDialog alert = builder.create();
         alert.show();
          }
        });
        
        return convertView;
 }
   
    public class ViewTag{
     TextView tvdate;
        TextView tvdata;
        ImageButton ibtnEdit;
        ImageButton ibtnDel;
        ImageView img_reminder;
        ImageView img_lock;
        
        public ViewTag(TextView date, TextView data, ImageButton edit, ImageButton del, ImageView img1, ImageView img2){
            this.tvdate = date;
            this.tvdata = data;
            this.ibtnEdit = edit;
            this.ibtnDel = del;
            this.img_reminder = img1;
            this.img_lock = img2;
            
        }
    }
    
    public void quit() {
        int pid = android.os.Process.myPid();
        android.os.Process.killProcess(pid);
        System.exit(0);
    }
    
}


說明:
1.MyAdapter是繼承自BaseAdapter這個子類別

2.LayoutInflater myInflater 指的是一種擴充,就是說如果你想用自定的XML配置檔

可以用此擴充把自定的XML置檔加入到現有元件中

3.Activity在建構此類別時,需要帶入什麼參數是在MyAdapter 內設定的
如果這個也不了解請麻煩去翻一下物件導向書籍

4.重點在getView內,所有的自定介面設定、處理都在getView內產生及設定、處理

5.有使用一個viewTag的元件設定類別,要告訴介面自定義的XML內有哪些元件配置


貼出自定義的XML配置檔,讓各位更了解崁在ListView內的是怎麼配置的

list_data.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:descendantFocusability="blocksDescendants"
    android:background="@drawable/button_style" >

    <RelativeLayout
        android:id="@+id/relativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >


        <TextView
            android:id="@+id/tv_Date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textSize="20dp" />
        
        
        <ImageView
        android:id="@+id/img_lock"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/img_remind"
        android:layout_alignParentTop="true"
        android:contentDescription="@string/password"
        />
        
        
        <ImageView
        android:id="@+id/img_remind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/ibtn_edit"
        android:layout_alignParentTop="true"
        android:contentDescription="@string/remind"
        />
        

        <ImageButton
            android:id="@+id/ibtn_del"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:src="@android:drawable/ic_menu_delete"
            android:contentDescription="@string/del" />


        <ImageButton
            android:id="@+id/ibtn_edit"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_alignParentTop="true"
            android:layout_toLeftOf="@+id/ibtn_del"
            android:src="@android:drawable/ic_menu_edit"
            android:contentDescription="@string/edit" />

    </RelativeLayout>

    <TextView
        android:id="@+id/tv_Data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>


實際圖型:



後記:
這個是ListView中的自定義圖型,當然這是有美化過的,所以看起來才會有點不一樣

不過如果你想要做到像這個樣子,就一定要用BaseAdapter,然後套用自定義XML配置檔list_data.xml

不然是做不出這樣很自由的變化配置的,以上介紹,謝謝。

2012-08-13

Android Adapter家族系列(二) - ArrayAdapter

這次開始介紹Adapter的各子類別,因為怕太過深入會不容易了解,所以介紹各子類時

都只介紹一些比較基本的應用,如果有想更深入了解的人可以參考官網上面的介紹

ArrayAdapter上面有很完整的說明,謝謝。


我拿ArrayAdapter來橋接Spinner(下拉選單)做為介紹

直接帶入陣列當資料

//定義adapter為ArrayAdapter
ArrayAdapter<String> adapter ;

//建立陣列
private String[] type = new String[] {"茶類", "果汁類"};

//物件化
android.widget.ArrayAdapter.ArrayAdapter<string>(Context context, int textViewResourceId, String[] objects)
//上面是原式,textViewResourceId是下拉選單的樣式

adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, type); 

//設定下拉選單點選後出現選單的樣式,使用的是內建預設樣式
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 

//下拉選單
private Spinner sp;

sp = (Spinner) findViewById(R.id.type); 

sp.setAdapter(adapter);


重點:
可能你會發現ArrayAdapter在物件化時,有一個樣式textViewResourceId,
然後setDropDownViewResource又再設定一個樣式,為什麼呢?
因為textViewResourceId指的是下拉選單還未點選時的下拉選單樣式
而setDropDownViewResource設定的是點選下拉選單後跳出選單的樣式
這兩者是不一樣的,這樣說各位應該還是一頭霧水,我用圖片說明好了

new物件時樣式用simple_spinner_item

new物件時樣式用simple_spinner_dropdown_item


setDropDownViewResource物件時樣式用simple_spinner_item

setDropDownViewResource物件時樣式用simple_spinner_dropdown_item

有看清楚了嗎?new物件時textViewResourceId的樣式設定指的是下拉選單出現時的樣式
setDropDownViewResource指的是彈出下拉選單時,出現列表的樣式,此兩者是不同的
當然這兩者也都能使用自定義的佈局XML,只要自己新增一個XML,然後就能在textViewResourceId或setDropDownViewResource裡面選取,選單內的樣式也會跟著改變
以上是為你做ArrayAdapter的簡單介紹,謝謝。

2012-08-10

Android Adapter家族系列(一) - Adapter(適配器)

Adapter(適配器)  官方網站上有對它的一些類別概述:
適配器對象作為AdapterView之間的一個橋樑,並為這一觀點的基礎數據。適配器提供的數據項的訪問。適配器也作出負責的數據集給每個項目。

簡單的來說就是資料和元件間溝通的橋樑,Adapter有以下幾種間接子類別:
ArrayAdapterBaseAdapterCursorAdapterHeaderViewListAdapterListAdapterResourceCursorAdapterSimpleAdapter,SimpleCursorAdapterSpinnerAdapterWrapperListAdapter
這些子類別我們在後續章節再做各別的介紹。

我們常會在ListView、Spinner...等看到這一類別,而且也必須使用到它
我們就來看它常用的公用方法:


getCount ()

How many items are in the data set represented by this Adapter.
適配器內的資料個數

程式碼
public  int getCount() {
   return title.length;
}


GetItem (位置)


Get the data item associated with the specified position in the data set.
獲取的數據在指定位置的數據集相關的項目。


程式碼
public Object getItem(int position) {
  return title[position];
}


getItemId (int position)



Get the row id associated with the specified position in the list.

獲取的行ID列表中的指定位置。

Parameters
position  The position of the item within the adapter's data set whose row id we want.
放置在適配器的數據集的行ID,我們希望該項目的位置。

Returns
The id of the item at the specified position.

返回指定位置編號的項目。

程式碼
public long getItemId(int position) {
   return position;
}


getItemViewType (int position)


Get the type of View that will be created by getView(int, View, ViewGroup) for the specified item.
獲取由getView(INT,查看,ViewGroup的)創建的視圖類型的指定項目


參數
position  該項目內適配器的數據集,我們想要的視圖類型的位置


程式碼
public int getItemViewType(int position) {
  return position ;
}


getView int position, View convertView, ViewGroup parent



Get a View that displays the data at the specified position in the data set. You can either create a View manually or inflate it from an XML layout file. When the View is inflated, the parent View (GridView, ListView...) will apply default layout parameters unless you use inflate(int, android.view.ViewGroup, boolean) to specify a root view and to prevent attachment to the root.
得到一個視圖顯示在指定位置的數據集的數據。你可以手動創建一個視圖從一個XML佈局文件
Parameters (參數)
position(位置)The position of the item within the adapter's data set of the item whose view we want.
進入此方法時是數據集的第幾個了,可做為需要不同項目產生不同資料時判別之用

convertView The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).
簡單來說就是一個view的容器,可以引用新的XML佈局資料達到自定義佈局,再載入資料,最後回傳給需要的元件使用。

parent The parent that this view will eventually be attached to
Returns(返回)
  • A View corresponding to the data at the specified position.  
  • 查看相應的數據在指定的位置
程式碼
public View getView(int position, View convertView, ViewGroup parent) {

  //自訂類別,表達個別listItem中的view物件集合。
        ViewTag viewTag;

        if(convertView == null){
            //取得listItem容器 view
            convertView = myInflater.inflate(R.layout.adapter, null);
            
            //建構listItem內容view
            viewTag = new ViewTag(
            (ImageView)convertView.findViewById(R.id.MyAdapter_ImageView_icon),
            (TextView) convertView.findViewById(R.id.MyAdapter_TextView_title),
            (TextView) convertView.findViewById(R.id.MyAdapter_TextView_info)
             );
            
            //設置容器內容
            convertView.setTag(viewTag);
        }
        else{
            viewTag = (ViewTag) convertView.getTag();
        }
        
        //設定內容圖案
        switch(position){
            case 0:
                viewTag.icon.setBackgroundResource(R.drawable.taipei);
                break;
            case 1:
                viewTag.icon.setBackgroundResource(R.drawable.taichung);
                break;
            case 2:
                viewTag.icon.setBackgroundResource(R.drawable.kaohsiung);
                break;
        }
        
        //設定標題文字
        viewTag.title.setText(title[position]);
        //設定內容文字
        viewTag.info.setText(info[position]);
        
        return convertView;
 }

後記:

Adapter(適配器)還蠻常會看到的,因為如果想客製化介面元件的話,一般都需要用到Adapter(適配器)改變元件為自定義形式,最常用的就是BaseAdapter這個子類,一般形態ArrayAdapter也蠻常用的,不過ArrayAdapter都是用在沒什麼改變時調用,如果想自定義一般都會做用到BaseAdapter這個子類,後續我們再逐步介紹這兩個子類別,謝謝。



Android 工具 - 幫Eclipse 換程式碼顏色

開發Android一般都是Eclipse做為開發工具,但每次都看到相同的程式碼顏色還蠻無聊的

某天我就上網找了一下看能不能改變一下程式碼的顏色換換心情也好,很幸運的也讓我

找到了相關網站有在做這種事情,就讓我們來看看怎麼改變Eclipse的程式碼顏色吧!


進入Eclipse Color Themes選擇你想改變的程式碼顏色 - 小弟我用的是"Sunburst"


選取可以直接安裝的EPF檔下載它


下載後會是一個epf檔


進入Eclipse中匯入該檔,[File] →[Import] →[Gerneral] →[Preferences] →[瀏覽剛才下載的檔案] 


選取剛剛的epf檔按下完成(Finish)


回來看看程式碼全變了

後記:

改變後順眼多了,整個心情也跟著變好(有點誇張!),最少覺得不會那麼刺眼,不過要習慣新的

程式碼配色,像註解就變白了,一開始看會有點不習慣,不過久了就覺得還好了,而且每次看

到的程式碼顏色都一樣很無聊,所以有空可以改一下程式碼顏色也是蠻好玩的,分享給大家

謝謝。

2012-08-08

Android Activity、Intent系列(一) - 萬用的Intent(意圖)

一般人都知道Intent(意圖)是用來幫Activity傳遞參數用的,但如果你的觀念只停留在

Intent只能用來傳遞參數用那就大錯特錯了,下面介紹怎麼使用萬能的Intent幫我們

簡單的就能做很多的事情了。


Activity跳轉-無參數時
Intent it = new Intent(Activity1.this, Activity2.class);
startActivity(it); 



Activity跳轉-有參數時
Intent it = new Intent(Activity1.this, Activity2.class);
Bundle bundle=new Bundle();
bundle.putString("ID", "This is Activity1 message!");
it.putExtras(bundle);
startActivity(it);  



參數接取方的資料處理程式碼
Bundle bundle=getIntent().getExtras();
String name=bundle.getString("ID");



向上一個Activity返回結果
Intent intent=getIntent();
Bundle bundle=new Bundle();
bundle.putString("ID", "This is from Activity2!");
intent.putExtras(bundle);
setResult(RESULT_OK, intent);



返回結果的處理函數
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode==REQUEST_CODE){
            if(resultCode==RESULT_CANCELED)
                  setTitle("cancle");
            else if (resultCode==RESULT_OK) {
                 String temp=null;
                 Bundle bundle=data.getExtras();
                 if(bundle!=null)   temp=bundle.getString("ID");
                 setTitle(temp);
            }
        }
    }



瀏覽網頁
Uri uri = Uri.parse("http://jim690701.blogspot.tw/");  
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
startActivity(it);



顯示地圖
//輸入經緯度座標呼叫地圖
Uri uri = Uri.parse("geo:38.899533,-77.036476");  
 Intent it = new Intent(Intent.ACTION_VIEW, uri);   
 startActivity(it); 



路徑規劃
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");  
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
startActivity(it); 



撥打電話
//注意:使用撥號必須在AndroidManifest.xml 中,加上
//<uses-permission id="android.permission.CALL_PHONE" /> 

//呼叫撥號程序
Uri uri = Uri.parse("tel:0800000123");  
Intent it = new Intent(Intent.ACTION_DIAL, uri);  
startActivity(it); 

//直接撥號
Uri uri = Uri.parse("tel:0800000123");  
Intent it = new Intent(Intent.ACTION_CALL, uri);  
startActivity(it);  



寄送SMS/MMS簡訊
//呼叫簡訊程序 
   Intent it = new Intent(Intent.ACTION_VIEW, uri);  
   it.putExtra("sms_body", "The SMS text");   
   it.setType("vnd.android-dir/mms-sms");  
   startActivity(it); 

   //傳送簡訊 
   Uri uri = Uri.parse("smsto://0800000123");  
   Intent it = new Intent(Intent.ACTION_SENDTO, uri);  
   it.putExtra("sms_body", "The SMS text");  
   startActivity(it); 

  //傳送MMS彩訊  
   //取得手機內圖片連結
   Uri uri = Uri.parse("content://media/external/images/media/23");  
   Intent it = new Intent(Intent.ACTION_SEND); 
   //簡訊主題  
   it.putExtra("sms_body", "some text");   
   it.putExtra(Intent.EXTRA_STREAM, uri);  
   it.setType("image/png");   
   startActivity(it); 



傳送E-mail
//呼叫mail程序
Uri uri = Uri.parse("mailto:xxx@abc.com");  
Intent it = new Intent(Intent.ACTION_SENDTO, uri);  
startActivity(it); 


//簡易寄送E-mail
Intent it = new Intent(Intent.ACTION_SEND);  
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");  
it.putExtra(Intent.EXTRA_TEXT, "The email body text");  
it.setType("text/plain");  
startActivity(Intent.createChooser(it, "Choose Email Client")); 


//一般寄送E-mail
Intent it=new Intent(Intent.ACTION_SEND);    
String[] tos={"me@abc.com"};    
String[] ccs={"you@abc.com"};
//主要寄送對象    
it.putExtra(Intent.EXTRA_EMAIL, tos);    
//cc對象
it.putExtra(Intent.EXTRA_CC, ccs);    
//Email內容
it.putExtra(Intent.EXTRA_TEXT, "The email body text");  
//Email主題  
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");    
it.setType("message/rfc822");    
startActivity(Intent.createChooser(it, "選擇電子郵件客戶端"));


//寄送附件
Intent it = new Intent(Intent.ACTION_SEND);  
//Email主題  
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
//附件 
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");
//檔案格式  
sendIntent.setType("audio/mp3");  
startActivity(Intent.createChooser(it, "選擇電子郵件客戶端"));





播放多媒體
//播放手機內的MP3
Uri uri = Uri.parse("file:///sdcard/song.mp3");  
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
it.setType("audio/mp3");  
startActivity(it); 

//播放內存的第一個鈴聲
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");  
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
startActivity(it);




google play應用
//尋找某個應用
Uri uri = Uri.parse("https://play.google.com/store/search?q=jim.memorandum"); 
Intent it = new Intent(Intent.ACTION_VIEW, uri);  
startActivity(it);  
//https://play.google.com/store/search?q=這段都一樣
//主要是q後面的搜尋條件,可以是package也可以是名稱


//顯示某個應用的相關信息 
Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=jim.memorandum");  
Intent it = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(it);  
//https://play.google.com/store/apps/details?id=這段都一樣
//主要是id後面的package




Uninstall應用程式
//反安裝必須知道package name
Uri uri = Uri.fromParts("package", strPackageName, null); 
Intent it = new Intent(Intent.ACTION_DELETE, uri);   
startActivity(it); 



讀取QR Code
叫用條碼掃描器
Intent intent = new Intent("com.google.zxing.client.android.SCAN");//開啟條碼掃描器
intent.putExtra("SCAN_MODE", "QR_CODE_MODE");//設定QR Code參數
startActivityForResult(intent, 1);//要求回傳1,回傳值可以自由設定


接收掃描後的回傳值
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 // TODO Auto-generated method stub
 super.onActivityResult(requestCode, resultCode, data);
 
     if (requestCode == 1) { //startActivityForResult回傳值,回傳值是由叫用時帶入的設定
         if (resultCode == RESULT_OK) {
             String contents = data.getStringExtra("SCAN_RESULT");//取得QR Code內容
          txt_hello.setText(contents);//顯示儲存值
  }
            }
 }



後記:

看完以上的Intent應用是不是覺得Intent可以用到的地方還真不少吧

我個人是覺得Intent超好用的需要什麼都可以用Intent去呼叫就好,

簡單又能節省程式碼,以上是對萬用Intent的介紹,謝謝。

2012-08-07

Android Image應用(五) - 縮放、指定圖片大小

此篇要介紹的是如何縮放圖片,我們都知道圖片大小有時在呈現上讓我們不是那麼的滿意

或是讀取進來的圖片尺寸可能都有各式各樣的,這樣很容易破壞我們原來的版型,怎麼辦呢?

今天就介紹怎麼縮放圖片,讓圖片變大、變小、變成我們想要的。

  為了讓讀者比較容易了解及讀取方便,所以我會故意把三個按鈕的處理程序都拆開來寫

,而不是寫在一起,目的是為了易於讀取,不然用程序 + switch case寫在一起就好了


main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:src="@drawable/ic_launcher" />
    </RelativeLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >




        <Button
            android:id="@+id/btn_Center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:text="@string/button_center" />



        <Button
            android:id="@+id/btn_Right"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="30dp"
            android:layout_toRightOf="@+id/btn_Center"
            android:text="@string/button_right" />


        <Button
            android:id="@+id/btn_Left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_marginRight="30dp"
            android:layout_toLeftOf="@+id/btn_Center"
            android:text="@string/button_left" />

    </RelativeLayout>

</LinearLayout>



strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">圖片縮放</string>
    <string name="button_left">放大</string>
    <string name="button_right">縮小</string>
    <string name="button_center">變為480*480</string>

</resources>


DemoZoomActivity.java
package jim.demo.zoom;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class DemoZoomActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
         //圖片
        final ImageView imageView = (ImageView) findViewById(R.id.imageView1);
        
        //放大
        Button btnLeft = (Button)findViewById(R.id.btn_Left);
        //指定大小
        Button btnCenter = (Button)findViewById(R.id.btn_Center);
        //縮小
        Button btnRight = (Button)findViewById(R.id.btn_Right);
        
        
        //放大按鈕事件
        View.OnClickListener listener_left = new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				
				//imageView轉Bitmap
				  imageView.buildDrawingCache();
		          Bitmap bmp=imageView.getDrawingCache();
		        		
		        //轉換為圖片指定大小
	      	    //獲得圖片的寬高
	      	    int width = bmp.getWidth();
	      	    int height = bmp.getHeight();
	      	   
	      	    //放大為1.2倍
	      	    float scaleWidth = (float) 1.2;
	      	    float scaleHeight = (float) 1.2;
	      	    
	      	    // 取得想要缩放的matrix參數
	      	    Matrix matrix = new Matrix();
	      	    matrix.postScale(scaleWidth, scaleHeight);
	      	    // 得到新的圖片
	      	    Bitmap newbm = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix,true);
	      	    
	      	  //重新載入 imageView
	      	  imageView.setImageBitmap(newbm);
	          
			} 
        	
        };
        btnLeft.setOnClickListener(listener_left); 
        
        //指定大小按鈕事件
        View.OnClickListener listener_center = new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				
				//imageView轉Bitmap
				  imageView.buildDrawingCache();
		          Bitmap bmp=imageView.getDrawingCache();
		        		
		        //轉換為圖片指定大小
	      	    //獲得圖片的寬高
	      	    int width = bmp.getWidth();
	      	    int height = bmp.getHeight();
	      	    // 設置想要的大小
	      	    int newWidth = 480;
	      	    int newHeight = 480;
	      	    // 計算缩放比例
	      	    float scaleWidth = ((float) newWidth) / width;
	      	    float scaleHeight = ((float) newHeight) / height;
	      	    // 取得想要缩放的matrix參數
	      	    Matrix matrix = new Matrix();
	      	    matrix.postScale(scaleWidth, scaleHeight);
	      	    // 得到新的圖片
	      	    Bitmap newbm = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix,true);
	      	    
	      	  //重新載入 imageView
	      	  imageView.setImageBitmap(newbm);
	      	  
			} 
        	
        };
        btnCenter.setOnClickListener(listener_center); 
        
        //縮小按鈕事件
        View.OnClickListener listener_right = new View.OnClickListener() {

			@Override
			public void onClick(View arg0) {
				
				//imageView轉Bitmap
				  imageView.buildDrawingCache();
		          Bitmap bmp=imageView.getDrawingCache();
		        		
		        //轉換為圖片指定大小
	      	    //獲得圖片的寬高
	      	    int width = bmp.getWidth();
	      	    int height = bmp.getHeight();
	      	   
	      	    //縮小為0.8倍
	      	    float scaleWidth = (float) 0.8;
	      	    float scaleHeight = (float) 0.8;
	      	    
	      	    // 取得想要缩放的matrix參數
	      	    Matrix matrix = new Matrix();
	      	    matrix.postScale(scaleWidth, scaleHeight);
	      	    // 得到新的圖片
	      	    Bitmap newbm = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix,true);
	      	    
	      	  //重新載入 imageView
	      	  imageView.setImageBitmap(newbm);
			} 
        	
        };
        btnRight.setOnClickListener(listener_right); 
    }
}


執行畫面





後記:

            如果試著一直放大縮小你會發現一種現象:"失真了",因為把小圖放的太大本來

就會失真,所以最常用的是在讀取圖片後改變圖片比例到我們指定的大小,要不失真也

行,請準備一張大圖,這樣就比較不會失真了,不然系統內的圖片就如同啟始畫面一樣

小小一張而已,放大就會失真,這是圖片一定會有的狀況,謝謝收看。

2012-08-06

Android的DisplayMetrics類別應用 - 取得螢幕尺寸

Android一個最讓開發者頭大的問題,就是手機的螢幕尺寸太雜、大小太多

造成開發者在開發應用程式上的難度,要兼顧每一個尺寸是讓人頗頭大

現在介紹使用DisplayMetrics類別取得手機螢幕尺寸大小,以改變控制元件

來配合螢幕尺寸。

main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:ems="10"
        android:inputType="textMultiLine"
        android:singleLine="false" >

        <requestFocus />

    </EditText>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="60dp"
            android:text="@android:string/cancel" />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="60dp"
            android:text="@android:string/ok" />

    </RelativeLayout>

</LinearLayout>

我先設定螢幕尺寸為2.7寸,中間EditText高度為300dp


執行後的畫面,因為實際螢幕比較大,所以程式小了一號


使用DisplayMetrics類別取得螢幕尺寸大小改變控制項尺寸大小以符合實際螢幕大小

DemoGetScreenActivity.java
package jim.demo.getscreen;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.EditText;
import android.widget.TextView;

public class DemoGetScreenActivity extends Activity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        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);
        
        
        EditText editText1 = (EditText)findViewById(R.id.editText1);
        
        //原QVGA 2.7吋螢幕解析度為240 * 320
        if(metrics.heightPixels > 320)
        {
        	//改變editText1的高度
        	editText1.getLayoutParams().height = 600;
        }
          
    }
}

改變後執行畫面


官方螢幕尺寸和解析度對照表



後記:

          android的螢幕尺寸是個很麻煩的問題,因為不像Apple的iphone一樣只有單一尺寸

每一家Android廠商就有不同的尺寸,所以開發時就只有靠著DisplayMetrics抓取的螢幕

尺寸來做適度的調整,正常來說抓最小尺寸(QVGA)、大尺寸(WVGA)、平板尺寸(WXGA)

三種來做測試就好,只要不會出現按不到鈕的情況就可以了,不然要寫完整的全部尺寸

調整是要花費不少時間的,以上給大家參考,感謝。
       
         

Android 手機資料庫(五) - SQLite之資料庫更新說明篇


如果你對資料庫還完全陌生,請參考之前的三篇文章(第一篇第二篇第三篇)

因為很多人都不了解Android的資料庫更新應該怎麼做,所以在此寫一篇說明文好了

希望不了解的人看完之後能比較有所了解,下面開始解釋:

先貼上資料庫的程式碼,裡面當然也包含一般更新資料庫(onUpgrade)


程式碼
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;

public class NewListDataSQL extends SQLiteOpenHelper {

  private static final int VERSION = 3;//資料庫版本  
  
  public NewListDataSQL(Context context, String name, CursorFactory factory,int version) { //建構子
   super(context, name, factory, version);
  }

  public NewListDataSQL(Context context,String name) { 
   this(context, name, null, VERSION); 
   } 
  
   public NewListDataSQL(Context context, String name, int version) {  
    this(context, name, null, version);  
      }  
   
  //輔助類建立時運行該方法
  @Override
  public void onCreate(SQLiteDatabase db) {
   String DATABASE_CREATE_TABLE =
     "create table newMemorandum("
       + "_ID INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL,"
             + "date VARCHAR,"
             + "note VARCHAR,"
             + "pw VARCHAR,"
             + "reminder INT,"
             + "type VARCHAR,"
             + "memo VARCHAR"
         + ")";
            db.execSQL(DATABASE_CREATE_TABLE);
  }

  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   //oldVersion=舊的資料庫版本;newVersion=新的資料庫版本
     //db.execSQL("DROP TABLE IF EXISTS newMemorandum"); //刪除舊有的資料表
     //onCreate(db);
   
   
   if (newVersion > oldVersion) {
       db.beginTransaction();
    
       boolean success = true;
       
         
         switch (oldVersion) {
           case 2:           
            
            Cursor cursor = db.rawQuery("select _ID,date from newMemorandum", null);
            int[] iID = new int[cursor.getCount()];
            String[] sDate = new String[cursor.getCount()];
            
            int rows_num = cursor.getCount(); //取得資料表列數
            
            if(rows_num != 0) {
            cursor.moveToFirst();   //將指標移至第一筆資料
            for(int i=0; i<rows_num; i++) {
             int iCr = cursor.getInt(0);
             String strCr = cursor.getString(1);
             iID[i]=iCr;
             sDate[i]=strCr.split(" ")[0].split("/")[0] + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[1])) + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[2])) + " " + strCr.split(" ")[2];
             
             //因為日期格式有變,所以重新更新
             //格式改為2012/6/6 12:02
             ContentValues cv = new ContentValues();
             cv.put("date", sDate[i]);
             
             db.update("newMemorandum", cv, "_ID=" + iID[i], null);
             
             cv = null;//消滅物件
             
             
             cursor.moveToNext();  //將指標移至下一筆資料
            }
           }
           cursor.close();  //關閉Cursor
            
           
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN reminder integer DEFAULT 0");
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN type VARCHAR");
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN memo VARCHAR");
            oldVersion++;
            
               success = true;
             break;
           case 1:
                        
            Cursor cursor2 = db.rawQuery("select _ID,date from newMemorandum", null);
            int[] iID2 = new int[cursor2.getCount()];
            String[] sDate2 = new String[cursor2.getCount()];
            
            int rows_num2 = cursor2.getCount(); //取得資料表列數
            
            if(rows_num2 != 0) {
             cursor2.moveToFirst();   //將指標移至第一筆資料
            for(int j=0; j<rows_num2; j++) {
             int iCr2 = cursor2.getInt(0);
             String strCr = cursor2.getString(1);
             iID2[j]=iCr2;
             sDate2[j]=strCr.split(" ")[0].split("/")[0] + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[1])) + "/" + String.valueOf(Integer.valueOf(strCr.split(" ")[0].split("/")[2])) + " " + strCr.split(" ")[2];
             
             //因為日期格式有變,所以重新更新
             //格式改為2012/6/6 12:02
             ContentValues cv2 = new ContentValues();
             cv2.put("date", sDate2[j]);
             
             db.update("newMemorandum", cv2, "_ID=" + iID2[j], null);
             
             cv2 = null;//消滅物件
             
             
             cursor2.moveToNext();  //將指標移至下一筆資料
            }
           }
            cursor2.close();  //關閉Cursor
           
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN pw VARCHAR");
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN reminder integer DEFAULT 0");
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN type VARCHAR");
            db.execSQL("ALTER TABLE newMemorandum ADD COLUMN memo VARCHAR");
            oldVersion = 3;
               success = true;
             break;
         }
           
    
       if (success) {
         db.setTransactionSuccessful();
       }
       db.endTransaction();
     }
     else {
       onCreate(db);
     }
   
  }
  
  @Override    
   public void onOpen(SQLiteDatabase db) {     
           super.onOpen(db);       
           // TODO 每次成功打開數據庫後首先被執行     
       } 

   @Override
        public synchronized void close() {
            super.close();
            // TODO 每次關閉數據庫後被執行     
        }
}


說明:

此為資料庫SQLiteOpenHelper類的程式碼,幾個地方分析

1.資料庫的執行方式  
當系統要new出SQLiteOpenHelper類時,會先去找應用程式的DB資料夾下是否有該資料庫
如果沒有就執行建構子及onCreate建構該類別
如果有就執行onUpgrade更新資料庫

2.private static final int VERSION = 3;//資料庫版本  代表的意義與作用
(1)如果手機中沒有該應用程式,也等於沒有該資料庫(因為資料庫是獨立個體)
就會執行建構子構建該資料庫,建構子會帶入此VERSION,也就是從第3版開始
之後的更新也是從第4版開始,不能再回到第1版開始。

(2)如果有資料庫就會跳到onUpgrade事件中
oldVersion=舊的資料庫版本
newVersion=新的資料庫版本
這兩個是怎麼出現的呢?
在要更新資料庫時,您之前的VERSION一定是寫成這樣VERSION = 2
VERSION = 2 就是  = oldVersion
程式有修改時,資料庫也有修改,這時也會把VERSION改為VERSION = 3
VERSION = 3 就是 = newVersion
當你更新資料庫時,程式判別出VERSION = 3比之前的VERSION = 2大時
就會自動跳到onUpgrade事件中,帶入oldVersion=2、newVersion=3
當然你的舊版也可能是VERSION = 1(因為沒有即時更新)
程式還是會帶入oldVersion=1、newVersion=3

3.onUpgrade資料庫更新
(1)當我們了解了程式是怎麼判別資料庫更新後,再來看資料庫是怎麼更新的
因為舊版本可能不一樣,有可能最新版是第3版,舊版有1、2兩版
所以這裡可以針對不同版本做不同的更新動作,因為各版更新的都不同
所以可以用switch case分開各版本再對各版本做不同的更新動作(如上面程式碼)

(2)更新資料庫不止可以下ALTER的SQL指令而已,因為資料本身是存在的
只要不下Drop,所以可以用Cursor cursor = db.rawQuery把資料撈出來做變更
我個人是把資料撈出來做日期格式的變更,最後再下ALTER新增欄位
注意看程式碼中1版是ALTER了4個欄位,2版是ALTER了3個欄位
所以如果你是放上google play上是要針對每個版本做不同的更新
因為你不知道下載者有沒有即時去更新你的應用程式,所以基本上要保留資料
就要這樣寫把之前的版本做不同的更新,這樣才能確保每一個版本都能更新
到最新的版本而不會出錯。

以上說明希望能幫助你對Android的資料庫有了進一步的了解,謝謝。



2012-08-03

Bitmap、Drawable、byte的轉換

當寫到圖片的處理時,比較常會遇到的是這三種圖片型態的轉換

所以就來介紹一下這三種資料型態該怎麼轉換。


Bitmap 轉 Drawable
Drawable drawable = new BitmapDrawable(Bitmap);




Drawable 轉 Bitmap
Drawable oDrawable = xxx; //xxx根據自己的情況獲取drawable
BitmapDrawable BD = (BitmapDrawable) oDrawable;
Bitmap BM = BD.getBitmap();




實體路徑圖片檔 轉 Drawable
//這句一定要在onCreate()里面調用
File tempFile = = new File("/sdcard/a.jpg");

Drawable drawable = Drawable.createFromPath(tempFile.getAbsolutePath());




從res\drawable中取出內存圖片為Bitmap
Resources res=getResources();

Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.ic_launcher); 
 



imageView 轉 Bitmap
  //圖片
  ImageView imageView_save = (ImageView) findViewById(R.id.img_newphoto);

  //imageView轉Bitmap
  imageView_save.buildDrawingCache();
  Bitmap bmp=imageView_save.getDrawingCache();




bitmap 轉 byte
  Bitmap newbm;

  // 把 bitmap 轉成 byte
  ByteArrayOutputStream stream = new ByteArrayOutputStream();
  newbm.compress(Bitmap.CompressFormat.JPEG, 100, stream );
  byte bytes[] = stream.toByteArray();



後記:

這是我常用到的轉換,還蠻實用的,所以PO出來給需要的人參考,謝謝。

2012-08-01

Android 手機資料庫(四) - 將圖片存入資料庫的方法

我們都知道一般照片都是放在手機的圖片資料夾下,很少會放到資料庫內

不過為了怕應用程式需要的照片不小心被刪了而讓應用程式出錯,所以

就需要把圖片存進資料庫內,這裡我就來介紹怎麼樣把照片存進資料庫和取出

注意:這部份因為有關係到資料庫,所以為了不讓程式碼太多,所以我只show出
如何取出和存入圖片的程式碼,所以對資料庫需要有一定的認識,這部份請參考
前三篇(第一篇第二篇第三篇)的介紹。


存入的程式碼
//圖片
 ImageView imageView_save = (ImageView) findViewById(R.id.img_newphoto);
               
        //imageView轉Bitmap
        //imageView_save.setDrawingCacheEnabled(true);
        //建立圖片的緩存,圖片的緩存本身就是一個Bitmap
        imageView_save.buildDrawingCache();
        //取得緩存圖片的Bitmap檔
        Bitmap bmp=imageView_save.getDrawingCache();
          
            //轉換為圖片指定大小
            //獲得圖片的寬高
            int width = bmp.getWidth();
            int height = bmp.getHeight();
            // 設置想要的大小
            int newWidth = 480;
            int newHeight = 525;
            // 計算缩放比例
            float scaleWidth = ((float) newWidth) / width;
            float scaleHeight = ((float) newHeight) / height;
            // 取得想要缩放的matrix參數
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleHeight);
            // 得到新的圖片
            Bitmap newbm = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix,true);
             
          
            // 先把 bitmap 轉成 byte
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            newbm.compress(Bitmap.CompressFormat.JPEG, 100, stream );
            byte bytes[] = stream.toByteArray();
            // Android 2.2以上才有內建Base64,其他要自已找Libary或是用Blob存入SQLite
            // 把byte變成base64
            String base64 = Base64.encodeToString(bytes, Base64.DEFAULT); 
           
            //放img進去SQLite
            ContentValues cv = new ContentValues();
            cv.put("image", base64);
           //添加方法
           long long1 = db.insert(table_name, "", cv)



取出的程式碼
//取出資料
        Cursor cursor = db.rawQuery("select * from newimg where season = '秋'", null);
        
        //用陣列存圖片,陣列大小 = 取出資料的筆數
 Drawable[] Drawablelist = new Drawable[cursor.getCount()];
 Bitmap[] bmplist = new Bitmap[cursor.getCount()];
        
        //取得資料表筆數
        int rows_num = cursor.getCount(); 
  if(rows_num != 0) {

          //將指標移至第一筆資料
   cursor.moveToFirst(); 
            
   for(int i=0; i<rows_num; i++) {
            // 把Base64變回bytes
     byte bytes[] = Base64.decode(cursor.getString(2), Base64.DEFAULT);

            //用BitmapFactory生成bitmap
     bmplist[i] = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 
       
     //轉換Bitmap為Drawable
            Drawable drawable = new BitmapDrawable(bmplist[i]);

            //存入Drawable陣列中
     Drawablelist[i]=drawable;

            //將指標移至下一筆資料
            cursor.moveToNext();  
          }
        }

        //關閉Cursor
 cursor.close(); 
        //關閉資料庫,釋放記憶體 
 dbHelper.close(); 



後記:

          在存入時我有多用了縮放圖片,而在取出時因程式需要,所以有把Bitmap

再轉換為Drawable,這個可以看個人程式上的需求去做改變,不一定要照copy

程式是死的,人是活的,希望大家都能寫出一支好的程式,感謝。

Android Image應用(四) - 旋轉圖片

如果您有用到拍照或取得圖片功能時應該會知道,得到的照片或圖片會剛好跟我們想要的

差了90度,怎麼辦呢?這裡就為您介紹怎麼把圖片轉向90度的方法


main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="300dp"
            android:layout_height="300dp"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:src="@drawable/ic_launcher" />

    </RelativeLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="60dp"
            android:text="@string/right" />

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="60dp"
            android:text="@string/left" />

    </RelativeLayout>

</LinearLayout>



strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">DemoImageRotation</string>
    <string name="left">左旋90度</string>
    <string name="right">右旋90度</string>
</resources>


DemoImageRotationActivity.java
package jim.demo.ImageRotation;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class DemoImageRotationActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
      //圖片左旋90
        Button button_left = (Button)findViewById(R.id.button1);
        View.OnClickListener listener_left = new View.OnClickListener() {  
         
         public void onClick(View view) { 
         //取得圖片
         ImageView imageView_left = (ImageView) findViewById(R.id.imageView1);
         //imageView_left.setDrawingCacheEnabled(true);
         //建立圖片的緩存,圖片的緩存本身就是一個Bitmap
         imageView_left.buildDrawingCache();
         //取得緩存圖片的Bitmap檔
         Bitmap bmp=imageView_left.getDrawingCache();
         //定義一個矩陣圖
         Matrix m=new Matrix();
         //取得圖片的寬度
                int width=bmp.getWidth();
                //取得圖片的長度
                int height=bmp.getHeight();
                //逆時針旋轉90度
                m.setRotate(-90);
              //產生新的旋轉後Bitmap檔
                Bitmap b=Bitmap.createBitmap(bmp, 0, 0, width, height, m, true);
                
                //顯示圖片
                imageView_left.setImageBitmap(b);
            }  
        };  
        button_left.setOnClickListener(listener_left); 
        
        
      //圖片右旋90
        Button button_right = (Button)findViewById(R.id.button2);
        View.OnClickListener listener_right = new View.OnClickListener() {  
         public void onClick(View view) {  
         //取得圖片
         ImageView imageView_right = (ImageView) findViewById(R.id.imageView1);
         //imageView_right.setDrawingCacheEnabled(true);
         //建立圖片的緩存,圖片的緩存本身就是一個Bitmap
         imageView_right.buildDrawingCache();
         //取得緩存圖片的Bitmap檔
         Bitmap bmp=imageView_right.getDrawingCache();
         //定義一個矩陣圖
         Matrix m=new Matrix();
         //取得圖片的寬度
                int width=bmp.getWidth();
                //取得圖片的長度
                int height=bmp.getHeight();
                //順時針旋轉90度
                m.postRotate(90); 
                //產生新的旋轉後Bitmap檔
                Bitmap b=Bitmap.createBitmap(bmp, 0, 0, width, height, m, true);
                
                //顯示圖片
                imageView_right.setImageBitmap(b);
            
            }  
        };  
        button_right.setOnClickListener(listener_right);
    }   
}


執行畫面



後記:

            旋轉圖片對有用到取得手機內圖片及拍照功能的人應該還蠻需要的

但有一個缺點,就是旋轉必須長寬都一樣時用,如果長和寬是不一樣時,比如說是2:1

會出現一種現象,就是會愈轉愈小-.-",原因是當比較大的長轉到比較小的寬時會因為

放不進去,所以會自動縮小,然後你愈轉它就縮的愈多,所以就會出現愈轉愈小的現象

這是我後來再處理照片時發現的,好了!就為您介紹到這了,感謝。