SlideShare a Scribd company logo
第6節: Android動態UI介面設計
Android動態UI介面設計

  Android動態元件設計
     ListView
     Gallery
     GridView
     ImageSwitch
  Adapter元件
     ArrayAdapter
     SimpleAdapter
     自定Adapter




                      226
進階UI控制元件-Adapter使用
• Android 框架只負責應用程式的流程架構,框架設計師並不會知道最
  終使用框架開發出的Application長的是什麼樣子。
• 應用程式設計師並不能直接去修改Android框架的內容,如此會造成
  相容性問題,因此無法直接透過框架修改來決定應用程式的長相.
• 為解決上述兩個問題,在Android裡設計了Adapter類別來做為
  Android框架與應用程式之間的橋樑


• 為應付各種不同的資料數據來源,與不同的View元件,因此發展出各
  式不同的Adapter元件。




為你把關每一道 學習品質                           227
進階UI控制元件-Adapter使用
                                            Adapter
• 常見的Adapter的類別
                        ListAdapter                     SpinnerAdapter

                                         BaseAdapter


                 ArrayAdapter           CursorAdapter                SimpleAdapter

                                 ResourceCursorAdapter


• 常見Adapter對應到UI端的類別                                     SimpleCursorAdapter
                                    ViewGroup

                                    AdapterView

             AbsListView                                AbsSpinner

      ListView           GridView           Gallery                   Spinner
為你把關每一道 學習品質                                                                         228
進階UI控制元件-Adapter使用

• ArrayAdapter用途
  • 作用為陣列與ListView之間的橋梁
  • 可將陣列中定義的資料逐一的對應到ListView之中顯示
  • 一般ArrayAdapter中顯示的ListView每行通常只有一個TextView

     ArrayList                       ListView
                                      Jarey
       Jarey
                                      TextView-Two
       John
                                      John
                   ArrayAdapter
       May                            TextView-Two

       Ken                            May
                                      TextView-Two

                                      Ken
                                      TextView-Two

為你把關每一道 學習品質                                         229
進階UI控制元件-Adapter使用

• SimpleAdapter用途
  • simpleAdapter可以定製每一列ListView中要顯示的內容
  • 一般ListView中每一列的版面配置(Layout)會撰寫在XML檔中,在
    由SimpleAdapter負責將內容(Data)填入Layout中的元件(View)。

    ArrayList                        ListView

   HashMap                            Jarey
                                      09222222
  Name    Jarey
                                      John
  Phone   0922      SimpleAdapter
                                      09333333

   HashMap                            May
                                      09444444
  Name    John
  Phone   0933                        Ken
                                      095555555

為你把關每一道 學習品質                                       230
進階UI控制元件-Adapter使用
• 建構式ArrayAdapter (Context context, int resource, int textViewResourceId, T[]
   objects)
    •   contex:要顯示的Context容器
    •   resource:layout定義,可以使用Android系統內建,或是自定layout.
    •   textViewResourceId:位於layout中的textView,用來顯示data內容.
    •   data:要顯示的資料內容


• 建構式SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int
   resource, String[] from, int[] to)
    •   contex:要顯示的Context容器
    •   data:基於Map的List. Map中包含了ListView每一列所需要的資料
    •   resource:顯示的Layout版型,此layout中至少要包含在to參數中所出現的
        View。可使系統提供的layout,亦可自行定義
    •   from:名稱陣列,每一個名稝都對應Data中的索引鍵。
    •   to:為TextView類形的陣列,必須要在layout中可以被索引到。

為你把關每一道 學習品質                                                                    231
範例練習
           範例專案名: ex05_01_Spinner

  練習目標:
   學習使用Spinner,利用ArrayAdapter提供
    Spinner內容。
  程式撰寫
   建置Spinner元件,其內容資料於XML中利用
    string array xml標籤編寫內容。
   於Activity中讀入string array內容至記憶體,並套
    用ArrayAdapter提供資料給Spiiner元件。
  操作練習
   模擬器練習,分練習XML方式導入靜態資料,與
    使用Adapter方式動態載入資料兩種應用方式。

為你把關每一道 學習品質                            232
進階UI控制元件-ListView

• ListView為Android中用來顯示大量資
  料的一個很重要的UI介面
• 由於手機受限於螢幕大小,當欲顯示
  的資料數量超過一個頁面可以顯示時,
  就可以利用ListView來做資料顯示
• ListView需搭配Adapter使用,
  ListView會自動依顯示控制的需求透
  過Adapter介面取得資料。

• ListView提供OnItemClickListener()
  方法,可以取得用戶的動件事件(例
  如點選了那一個ListView元件)



為你把關每一道 學習品質                        233
進階UI控制元件-ListView

• ListView使用方式
   • set data source to Adapter
   • get ListView from R.layout
   • set adapter to ListView
   • set click listener for each list item

• ListView Event處理函式
   • onItemClick(AdapterView<?> parent, View view, int position, long id)
   • onItemLongClick(AdapterView<?> parent, View view, int position, long id)
   • onItemSelected(AdapterView<?> parent, View view, int position, long id)




為你把關每一道 學習品質                                                                234
範例練習
           範例專案名: ex05_02_Adapter

  練習目標:
   了解各式adapter的使用
   了解ListView與adapter之間的關係與運作
    流程
  程式撰寫
   設計一ListView元件,並練習接上各式不
    同的adapter與不同的資料來源串接
   SimpleAdapter, ArrayAdapter
  操作練習
   透過模擬器操作不同的Activity,每一個
    Activity代表一個不同Adapter的連接範例。
為你把關每一道 學習品質                        235
進階UI控制元件-ListActivity

• ListActivity使用時機
  • 當一個Activity中只有顯示ListView,而且此ListView又會填滿整
    個螢幕,此時可以直接使用ListActivity來代替Activity。
  • ListActivity為一個包含了ListView的Activity,以wrapper的方式將
    ListVIew包裝起來,方便更容易與直接的控制。

• ListActivity 預設ID元件
   • ListActivity使用的layout檔中必須定義一個ListView,且此
      ListView的id必須固定為[ @id/android:list ]

  • 另外可定義一個TextView當ListView裡沒有資料時可以顯示,此
    TextView的id必須固定為[ @id/android:empty]




為你把關每一道 學習品質                                           236
進階UI控制元件-ListView

• ListActivity使用方式
   • Application extended ListActivity
   • set data source to Adapter
   • get ListView from ListActivity
   • set adapter to ListView
   • set click listener for each list item

• ListView Event處理函式
   • 在ListActivity中不用註冊Listener,而是直接以覆寫
      (Override)來進行事件處理
   • 可處理的Event函式與ListView相同

為你把關每一道 學習品質                                 237
範例練習
          範例專案名: ex05_03_ListActivity

  練習目標:
   了解ListActivity的應用
  程式撰寫
   修改前一隻範例程式,試著將其改寫成
    ListActivity
   Activity直接繼承自ListActivity
  操作練習
   透過模擬器操作,注意ListActivity與ListView在對
    於listener event 處理的寫法是否有所不同?


為你把關每一道 學習品質                            238
進階UI控制元件-Adapter使用
• 自行定義Adapter內容
  • 繼承(extended)BaseAdapter
  • 於建構式接收要處理的資料(Data)來源
  • 覆寫(Override)以下四個Method
     •   public int getCount() ;
          •   傳回Data的數量.(ListView的列數)
     •   public Object getItem(int position);
          •   傳回指定的Data元件.
     •   public long getItemId(int position);
          •   傳回Data的識別ID
     •   public View getView(int position, View convertView, ViewGroup
         parent)
          •   傳回Layout與Data組合後的View元件(顯示於畫面上)
  • ※當Data內容有變更時,必須呼叫notifyDataSetChanged才會更新
    ListView中的內容。
                                                                         239
為你把關每一道 學習品質
進階UI控制元件-Adapter使用
• Adapter與Android框架運作流程

Android
                 Activity                AdapterView                   Adapter
 框架


                                                        3.getCount()        4.getView()
Application         2.setContentView()

          1.onCreate()
                                           Map                    MyAdapter
                ListActivity
                                 Array             Data

                                                               Layout
                                    Cursor                                       View

                                                       XML
為你把關每一道 學習品質                                                                            240
範例練習
         範例專案名: ex05_04_ImageAdapter

  練習目標:
   了解如何自行擴充Adapter類別
   學習如何以高效率,最佳化記憶體方式設計
    Adapter
  程式撰寫
   設計一個ImageAdapter類別,繼承至BaseAdapter
    抽像類別
   實作BaseAdapter的四個抽像函式
   利用系統快取與ViewHolder提高Adapter的效能
  操作練習
   透過模擬器操作
為你把關每一道 學習品質                            241
進階UI控制元件-ListView資料快取問題

• ListView為了節省記憶體與提高顯示的效能,會利用快取
 機制,在ListView滑動時會重覆利用己使用過,目前不在
 畫面上的View元件。

               ConvertView


               ConvertView

    重覆利用
               ConvertView   由下往上滑動

               ConvertView


               ConvertView
為你把關每一道 學習品質                          242
進階UI控制元件-ListView內元件如何監聽事件

• ListView本身可以透過註冊setOnItemSelectListener來監
 聽用戶點擊了那一條List Item。

• 若希望能為List Item中的每一個View元件單獨的設置
 Listener事件,那麼需要注意以下二個問題:

  • ListView本身具有快取,List Item是重覆利用的,這將
    導致用戶滑動List後,所點擊的元件可能與你當初註冊
    的Listener元件不一致(如點了第5個Item中的一個
    Button,但實際上第5個Item等同於重覆利用的第1個
    Item)
為你把關每一道 學習品質
                                    243
進階UI控制元件-ListView內元件如何監聽事件

  • 由於Item元件是重覆利用,因此你將無法判斷用戶點
    擊的Button為第幾個Item選項的Button,同時若你在每
    次getView時都為新的Item重新設置新的Listener那麼
    將會造成記憶體大量的浪費,同時也會降低顯示的效
    能。



    重覆利用

                      點擊第4個Item內的checkbox,
                      但呼叫的listener將與第1個
                      item相同。
為你把關每一道 學習品質
                                  244
進階UI控制元件-ListView內元件如何監聽事件

• 解決LIstView 內Item元件的監聽事件的方法,可以透過
  View.setTag方式,為將該List   Item的資料快取在要被監
  聽的View元件身上。如此當用戶點擊了CheckBox後,可
  以在透過getTag的方式取得該List Item的資料做為判斷。
                                            List Data Set
                          setTag(Object);
                                                Profile1

                                                Profile2
   重覆利用
                                                Profile3

                                                Profile4



為你把關每一道 學習品質
                                                245
進階UI控制元件-ListView資料快取問題

• 重覆使用的View元件會造成顯示不一致的問題,由其是當
 View元件中有使用到如CheckBox這類的選單元件。

                  雖然只勾了一個選項。但往
                  上滑動時會造成第五個選項
                  看起來也是被勾選的


  重覆利用
                    由下往上滑動




為你把關每一道 學習品質                     246
進階UI控制元件-ListView資料快取問題

• 解決View元件顯示不一致的狀況,必須將ListView中每一
 條的UI狀態記錄起來,在每次呼叫getView時去重新設定
 UI狀態。                        List Data狀態表

                                     勾選

                     由下往上滑動          未勾選

重覆利用                                 未勾選

                                     未勾選

                                     未勾選

                   在準備顯示到畫面上前,重新將
                   View元件上的UI狀態做更新,將
                   勾選取消掉。
為你把關每一道 學習品質
                               247
範例練習
         範例專案名: ex05_04_ImageAdapter

  練習目標:
   直接修改ImageAdapter範例,加入刪除模式功能
   於刪除模式下顯示CheckBox元件提供用戶勾選。
  程式撰寫
   建置ListData 狀態表記錄每個ListView中每個元件的UI
    狀態。
   將ListView中的Layout所有的元件forcues狀能設為false
    以避免遮避到ListView本身的onItemSelect事件。
   註冊CheckBox的Onclick事件,並將狀態資料帶入至
    Tag中提供供識別所點選的元件。
  操作練習
   透過模擬器操作

為你把關每一道 學習品質                                 248
進階UI控制元件-ImageSwitch&Gallery

• ImageSwitch                  ViewGroup


   • 主要用來做圖片切換與自動播放用.          AdapterView

     可支援不同的進場與退場動畫特效
                               AbsSpinner


• Gallery                        Gallery

  • 提供一個拖拉式圖片瀏覽與選擇介面
  • 僅支援水平擺設方式
  • 通常搭配ImageSwitch可用來做成簡
     易的圖片瀏覽器。




為你把關每一道 學習品質                                 249
進階UI控制元件-ImageSwitch&Gallery

• ImageSwitch元件
   • XML宣告方式



  • 程式碼使用方式
       功能                                程式碼
 package     Import android.widget.ImageSwitch;
 Reference   ImageSwitch sw1 = (ImageSwitch) findViewById(R.id.imsw1);
 set         sw1.setFactory(ViewSwitch.ViewFactory factory)
             sw1.setInAnimation(Animation inAnimation)
             sw1.setOutAnimation(Animation outAnimation)
             sw1.setImageResource (int resid)


為你把關每一道 學習品質                                                             250
進階UI控制元件-ImageSwitch&Gallery

• Gallery元件
  • XML宣告方式




  • 程式碼使用方式
               功能                              程式碼
   package          Import android.widget.Gallery;
   Reference        Gallery gal1 = (Gallery) findViewById(R.id.gallery);
   set              gal1.setAdapter(SpinnerAdapter adapter);
   Call back        gal1.setOnItemSelectedListener(AdapterView.OnItemSelect
                    edListener listener);

為你把關每一道 學習品質                                                               251
範例練習
           範例專案名: ex05_05_Gallery

  練習目標:
   透過Gallery與ImageSwitch設計一個簡易的相片
    瀏覽器
   復習先前教過的Adapter的應用
  程式撰寫
   撰寫一個Activity包含ImageSwitch與Gallery元件。
   撰寫一個ImageAdapter提供給Gallery。
  操作練習
   透過模擬器操作

為你把關每一道 學習品質                               252
進階UI控制元件-GridView


• GridView為網格檢視元件,可以將很很多圖片以         ViewGroup

  固定的大小排列顯示在畫面上可用來做為相簿與圖
  片瀏覽等應用                            AdapterView


• GridView的資料取至於ListAdapter,一般要用做
                                    AbsListView
  相簿使用需要自行實作ImageAdapter(繼承至
  BaseAdapter).                      GridView




為你把關每一道 學習品質                                      253
進階UI控制元件-GridView

• GridView元件
  • XML宣告方式




  • 程式碼使用方式
              功能                            程式碼
  package          Import android.widget.GridView;
  Reference        GridView grid= (GridView ) findViewById(R.id.grid);
  set              grid.setAdapter(BaseAdapter adapter);
  Call back        grid.setOnItemSelectedListener(AdapterView.OnItemSele
                   ctedListener listener);
為你把關每一道 學習品質                                                             254
第7節: Android 通知元件設計
  Android Widget開發
Android 通知元件設計

  Android Menu元件設計
     Option Menu
     Context Menu
  Android通知元件設計
     Dialog
     Toast
     Notification
     Menu
  AppWidget桌面元件設計
     Widget開發上的限制
     Remove View的互動方式



                         256
進階UI控制元件-Menu選單

• Menu選單操作元件
  • Option Menu
    • 按下menu建後顯
      示
  • Context Menu
    • 長時間按下一個視
      窗後顯示
  • Submenu
    • 子選單,可被
      option或context
      Menu所呼叫

為你把關每一道 學習品質           257
進階UI控制元件-Option Menu

• Option Menu
  • 選單位於整體畫面的下方,透過按下手機上的
    Menu按鈕顯示
  • 一個畫面最多可以安置6個選單項目,不支援
    Checkbox及RadioButton
  • 超過6個選單的項目將會以擴充列的方式顯示。
• Option Menu 使用XML宣告




為你把關每一道 學習品質            258
進階UI控制元件-Option Menu

• Inflating Option Menu Resource File
   • 透過MenuInflater.inflate() 協助載入xml資源檔
       • public void inflate (int menuRes, Menu menu)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.game_menu, menu);
      return true;
    }




為你把關每一道 學習品質                                            259
進階UI控制元件-Option Menu

• 建立Option Menu 使用MenuItem add函式
   Public boolean onCreateOptionsMenu(Menu menu){
     menu.add(0,MENU_ITEM_ID1, 0 “ MENU_ITEM_1”);
     menu.add(0,MENU_ITEM_ID2, 0 “ MENU_ITEM_2”);
     return true;
   }

• MenuItem add函式
  • public abstract MenuItem add (int groupId, int
    itemId, int order, int titleRes)
     • groupid:群組ID
     • itemid:項目ID
     • order:排序方式
     • titleRes:每一個Item上的標題
為你把關每一道 學習品質                                         260
進階UI控制元件-Option Menu

• 建立Menu




• Call Back
  Function




為你把關每一道 學習品質           261
進階UI控制元件-Context Menu

• Context Menu
  • 與在PC上的滑鼠右鍵功能類似,當按位某一
    個View 2秒鐘,就會出現一個浮動式的
    Context Menu。
  • 較常使用在ListView上。
• 建立Option Menu 使用MenuItem add函式




為你把關每一道 學習品質                       262
進階UI控制元件-Context Menu

• Context Menu的callback函式




為你把關每一道 學習品質                263
進階UI控制元件-Submenu

• Submenu
  • Context Menu與Option Menu可以在內嵌一個
    子選單(Submenu)做為擴充。
  • 子選單(Submenu)不能在擴充子選單
• 建立Submenu 使用xml




為你把關每一道 學習品質                          264
進階UI控制元件-Submenu

 • 建立Submenu 使用SubMenu addSubMenu函式
 @Override
public boolean onCreateOptionsMenu(Menu menu) {
  super.onCreateOptionsMenu(menu);
  SubMenu fileMenu = menu.addSubMenu(GALLERY, SUBMANU01, Menu.NONE, "File");
  SubMenu editMenu = menu.addSubMenu(GALLERY, SUBMANU02, Menu.NONE, "Edit");
  fileMenu.add(GALLERY, MANU01, Menu.NONE, "new");
  fileMenu.add(GALLERY, MANU02, Menu.NONE, "open");
  fileMenu.add(GALLERY, MANU03, Menu.NONE, "save");
  editMenu.add(GALLERY, MANU04, Menu.NONE, "undo");
  editMenu.add(GALLERY, MANU05, Menu.NONE, "redo");
  return true;
}




 為你把關每一道 學習品質                                                                  265
進階UI控制元件-Submenu

      • 處理Callback函式
@Override
 public boolean onOptionsItemSelected(MenuItem item) {
       switch (item.getItemId()) {
            case MANU01:
            case MANU02:
            case MANU03:
            case MANU04:
            case MANU05:
            String itemid = Integer.toString(item.getItemId());
            String title = item.getTitle().toString();
            showAlertDialog("項目ID = " + itemid + "n" +
            "標題 = " + title);
            return true;
       }
       return super.onOptionsItemSelected(item);
 }




 為你把關每一道 學習品質                                                     266
範例練習
        範例專案名: ex06_01_01_OptionsMenu
            ex06_01_02_ContextMenu
             ex06_01_03_Submenu
  練習目標:
   學習各種Menu的應用場合與撰寫方式
  程式撰寫
   透過覆寫onCreateOptionsMenu函式來加入
    Menu選單
   透過覆寫onOptionsItemSelected來接收使用者的
    選擇
  操作練習
   透過模擬器操作,透過按下手機上的Menu鍵來
    呼叫出Menu選單。

為你把關每一道 學習品質                            267
Android通知元件-Notifications
• Android提供三種不同的通知元件
   • Toast
      • 短暫警示與通知,顯示數秒後會
        自動消失                      Toast Notification

   • Dialog
      • 對話窗可與使用者做簡單交談式
        互動,一般用來做進度提示或確
        認使用者的需求。                  Dialog Notification

   • Status Bar Notification
      • 位於訊息列,訊息會長註於狀態
        列,點擊後可啟動Activity。一般
        Services會透過此通知用戶有事件
        發生需返回Activity處理        Status Bar Notification
                                                         268
為你把關每一道 學習品質
Android通知元件-Dialog元件
• Dialog是一切對話框基本類別,並非繼承於View類別.
• Dialog也具有生命週期,其生命週期由Activity來誰護。

• 開發者可主動呼叫的函式                                       Activity

  • showDialog(int id)                        showDialog(int id)
  • dismissDialog(int id)        Andr
                                  oid        onCreateDialog(int id)
                                 框架
                                             onPreparDialog(int id,
                                                Dialog dialog)
• 框架控制Dialog生命週期函式
  • onCreateDialog(int id)
  • onPrepareDialog(int id, Dialog dialog)

                                                                      269
 為你把關每一道 學習品質
Android通知元件-Dialog元件
• Dialog於Activity中的建立流程
  • Step1: 呼叫Activity的showDialog(id)
            Button1.setOnClickListener(new OnClickListener(){
                     public void on click(View v){
                               showDialog(DIALOG1);
                     }
            }
            );

  • Step2: 覆寫(override)onCreateDialog(int id)函式
            Protected Dialog onCreateDialog(int id){
                 switch(id){
                      Case DIALOG1:
                      return buildDialog1(this);
                 }
                 return null;
            }
                                                                270
為你把關每一道 學習品質
Android通知元件-Dialog元件
 • Step3:建立需要的Dialog類別,將其返return回
         Android框架
     Private Dialog buildDialog1(Context context){
           AlertDialog.Builder builder = new AlertDialog.Builder(context);
           builder.setIcon(R.drawable.alert_dialog_icon);
           builder.setTitle(R.string.alert_dialog_two_buttons_title);
           builder.setPositiveButton(R.string.alert_dialog_ok,new
                 DialogInterface.OnClickListener(){
                 public void onClick(DialogInterface dialog, int whichButton){
                             setTitle(“確認鈕”);
                 }
                 });
           return builder.create();
     }

 • Step4:覆寫onPrepareDialog(int id, Dialog dialog)
      protected void onPrepareDialog (int id, Dialog dialog, Bundle args){
               return dialog;
      }
                                                                                 271
為你把關每一道 學習品質
Android通知元件-Dialog元件
• AlertDialog
   • AlertDialog是Dialog的子類別,為最常使用的對話框
   • 一個AlertDialog可以有二個至三個按鈕
   • 不能直接以建構函式來產生AlertDialog物件,必須透過
     AlertDialog.Builder來建構。
private Dialog buildDialog2(Context context) {
      AlertDialog.Builder builder = new AlertDialog.Builder(context);
      builder.setIcon(R.drawable.alert_dialog_icon);
      builder.setTitle(R.string.alert_dialog_two_buttons_msg);
      builder.setMessage(R.string.alert_dialog_two_buttons2_msg);
      builder.setPositiveButton(R.string.alert_dialog_ok,
             new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int whichButton) {
                    setTitle("點選了對話框上的確定按鈕");
             }});
      builder.setNeutralButton(略.同上);
      builder.setNegativeButton(略,同上;
      return builder.create();
}
                                                                              272
為你把關每一道 學習品質
Android通知元件-Dialog元件

• 具有View元件的對話框
private Dialog buildDialog3(Context context) {
      LayoutInflater inflater = LayoutInflater.from(this);
      final View textEntryView = inflater.inflate(
      R.layout.alert_dialog_text_entry, null);
                       略
     AlertDialog.Builder builder = new AlertDialog.Builder(context);
     builder.setView(textEntryView);
     builder.setPositiveButton(R.string.alert_dialog_ok,
     new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int whichButton) {
           setTitle("點選了對話框上的確定按鈕:"
           + ((TextView) textEntryView.findViewById(R.id.username_edit)).getText());
     }});
     builder.setNegativeButton(略…….);
     return builder.create();
}




為你把關每一道 學習品質                                                                           273
Android通知元件-Dialog元件

• 進度對話框
private Dialog buildDialog4(Context context) {
      ProgressDialog dialog = new ProgressDialog(context);
      dialog.setTitle("正在下載歌曲");
      dialog.setMessage("請稍候……-");
      return dialog;
}




為你把關每一道 學習品質                                                 274
範例練習
               範例專案名: ex06_02_Dialog

  練習目標:
   學習操作Android各種不同的Dialog對話視窗
   學習如何將Dialog改成可以自定Layout元件
    的對訊窗
  程式撰寫
   覆寫onCreateDialog函式,負責管理Activity
    中呼叫的Dialog.
   透過AlertDialog.Builder建立Dialog物件
  操作練習
   透過模擬器操作。


為你把關每一道 學習品質                           275
Android通知元件-Notification

• Notification通知元件
  • 不會打斷目前使用者的操作,訊息會長註於訊
    息列中,待用戶有空時在進行處理,並可直接
    啟動對應的Activity.
  • Notification可加入振動或聲音通知,以加強引
    起用戶的注意。




為你把關每一道 學習品質                      276
Android通知元件-Notification

• 如何撰寫Notification事件
  • Step1:取得NotificationManager管理元件
             mNotificationManager = (NotificationManager)
                        getSystemService(NOTIFICATION_SERVICE);


  • Step2:建構Notification物件
       •   第一個參數:要顯示的圖片ID
       •   第二個參數:要顯示的文字
       •   第三個參數:顯示的時間,System.currentTimeMillis()代表立
           即顯示

            Notification notification = new Notification(drawable,
            tickerText,System.currentTimeMillis());




為你把關每一道 學習品質                                                         277
Android通知元件-Notification

  • Step3:決定Notification如何呈現與處理事件
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
        new Intent(this, ActivityMain.class), 0);

    •   Context:作用於那一個Activity的Context
    •   requestCode:目前無使用到
    •   Intent:要被啟動的Activity Intent
    •   Flags: 細部的Intent操作控制,如 FLAG_CANCEL_CURRENT
        notification.setLatestEventInfo(this, title, content, contentIntent);


  • Step4:設定Notification預設的表現形式
    •   Notification.DEFAULT_VIBRATE 振動
    •   Notification.DEFAULT_SOUND 聲音
    •   Notification.DEFAULT_ALL 聲音+振動
    •   需加入權限才能使用振動功能:Android.permission.VIBRATE
        notification.defaults = Notification.DEFAULT_ALL;
        mNotificationManager.notify(NOTIFICATIONS_ID, notification);
為你把關每一道 學習品質                                                                    278
Android通知元件-Notification

• Notification通知更新
   • 透過notify()函式來更新通知,可以避免一直不斷產生新的
     Notify訊息通知而導致塞滿了用戶的通知視窗
  mNotificationManager.notify(NOTIFICATIONS_ID, notification);

• 加入自定音效
  • 系統預設音效
     • notification.defaults |= Notification.DEFAULT_SOUND;
  • 讀取SD卡的mp3
     • notification.sound =Uri.parse("file:///sdcard/notification/test.mp3");
  • 從MediaStore的ContentProvider取得
     • notification.sound =
       Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6");
為你把關每一道 學習品質                                                              279
Android通知元件-Notification

• Notification相關FLAG設定
  • FLAG_AUTO_CANCEL:
     • 用戶點了該通知後,系統便會自動清除該訊息
  • FLAG_INSISTENT:
     • 重複發出響聲,直到使用者點選該訊息
  • FLAG_ONGOING_EVENT:
     • 將該訊息放置放”進行中”群組,一般用來代表背景
       Service還有在運行中。
  • FLAG_NO_CLEAR:
     • 使用者就算點選了清除訊息,系統也不會把該訊息清
       除,必須待應用程式自己發出清除的指令。

為你把關每一道 學習品質                 280
Android通知元件-Notification

 • 自定Notification顯示UI元件
    • Step1: 利用RemoveView定義元件內容
RemoteViews contentView = new RemoteViews(getPackageName(),
R.layout.custom_notification_layout);

contentView.setImageViewResource(R.id.imageIcon,
R.drawable.notification_image);

contentView.setTextViewText(R.id.textView, "Hello Notify");

notification.contentView = contentView;


 為你把關每一道 學習品質                                                 281
Android通知元件-Notification

• Step2: 發出通知訊息
   • 使用contentIntent設置pendingIntent元件

Intent notificationIntent = new Intent(this, MyClass.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.contentIntent = contentIntent;
mNotificationManager.notify(0, notification);




為你把關每一道 學習品質                                                       282
Android通知元件-Notification

• Notification相關FLAG設定
  • FLAG_AUTO_CANCEL:
     • 用戶點了該通知後,系統便會自動清除該訊息
  • FLAG_INSISTENT:
     • 重複發出響聲,直到使用者點選該訊息
  • FLAG_ONGOING_EVENT:
     • 將該訊息放置放”進行中”群組,一般用來代表背景
       Service還有在運行中。
  • FLAG_NO_CLEAR:
     • 使用者就算點選了清除訊息,系統也不會把該訊息清
       除,必須待應用程式自己發出清除的指令。

為你把關每一道 學習品質                 283
Android通知元件-Tost通知元件

• Tost通知元件
   • 為一個短暫提示元件,Toast會直接顯示於螢
     幕下方.
   • Tost內容可以直接為描述一串文字,也可以帶
     入View元件。
   • Toast的顯示時間長度分為長與短兩種
      • Toast.LENGTH_LONG
      • Toast.LENGTH_SHORT



為你把關每一道 學習品質                  284
Android通知元件-Tost通知元件

• 如何撰寫Tost通知
  • Step1:實體化Toast物件
           Toast toast = new Toast(this);

  • Step2:設定Toast內容
    • setText(CharSequence s)
    • setView(View view)
           LayoutInflater vi = (LayoutInflater)
           getSystemService(Context.LAYOUT_INFLATER_SERVICE);
           View view = vi.inflate(R.layout.toast,null);
           TextView tv = (TextView) view.findViewById(R.id.content);
           tv.setText("加入艾鍗,迅速提昇你的開發能力");
           toast.setView(view);
  • Step3:設定顯示時間
           toast.setDuration(Toast.LENGTH_SHORT);
           toast.show();

為你把關每一道 學習品質                                                           285
範例練習
        範例專案名: ex06_03_Toast_and_Notification

  練習目標:
   學習如何建立Notification與Toast通知事件
  程式撰寫
     透過getSystemService(NOTIFICATION_SERVICE)取得
      NotificationManager物件
     建立PendingIntent物件,供用戶執選通知後返回Activity
     透過notification.defaults決定通知時是否要加振動與音效
     建立Toast物件,並傳送一簡單字串於畫面上
  操作練習
   透過模擬器練習,練習時可注意畫面的最上頂狀態列
    收到Notification時的程現與執行後的處理方式

為你把關每一道 學習品質                                       286
Android Widget開發

   Widget程式開發
      開發上的限制
      Widget組成方式
      如何設置組態設定Activity
   Remove View的互動方式




                          287
Android Widget程式開發

• APP Widget為Android 1.5之後所提
  供的功能。提供於Android桌面程式
  (Home Screen)上安置各式各樣的
  常註程式,例如小時鐘、Google
  Search...



• 常註程式新增方式
  • 在主畫面上按下觸控面版約2秒,
    即會彈出Add to Home Screen
    選單,選擇Widget後即會顯現
    目前系統所安裝的各式Widget



為你把關每一道 學習品質                   288
Android Widget程式開發-使用限制

• Android Widget可以使用的功能
   • 可加載於主畫面(Home Screen)
   • 同一個常駐程式可以多次啟動
   • 常註程式啟動時不會採用全畫面(Full Screen)
• Android Widget中不能使用的功能
   • Event的呼叫。
   • 有限的Layout使用,有限的GUI元件使用。
   • 可使用的Layout類別:
      • Frame Layout
      • Linear Layout
      • Relative Layout
   • 可使用的GUI元件
      • AnalogClock     ImageButton
      • Button       ProgressBar
      • Chronometer      TextView


為你把關每一道 學習品質                          289
Android Widget程式開發-使用限制

• Android系統對Widget程式的處理方式會有所限制,
  Widget可以處理的方式選擇
       處理方式              說明
   指定執行間隔時間    於widget的資訊檔中設置定期執行的時間週期
   指定執行時間      於Widget的資訊檔裡設定執行的時間
   按下按鈕後才執行    常GUI介面被用戶按下時才執行

• Widget由於長駐於主畫面,且會不定時在背景運作,
  因此設計時要特別注意評估電池與處理器的消耗狀況。

• Widget與Activity還有Services一般,皆有其獨自的生
  命週期



為你把關每一道 學習品質                             290
Android Widget程式開發-生命週期

• Widget生命週期

       開始
                  onDelete()

    onEnabled()
                  onDisabled()

    onUpdate()

                  App Widget
      執行中            關閉




為你把關每一道 學習品質                     291
Android Widget程式開發-組成結構

    • Android Widget應用程式組成結構
                                   BroadcastReceiver                           AppWidgetManaget


                                   AppWidgetProvider
   實作生命週期函式                                                    廣播呼叫
  onEnable,onUpdate,
                                                               APPWIDGET_UPDATE
  onUpdate,onDelete
  d,
                               myAppWidgetProvider
  onDisabled


Android應用程式設定檔                       Metadata設定           Widget資訊設定檔            Layout畫面布局檔
    AndroidManifest.xml              Name:名稱需為            Appwidget_info.xml      Layout_sample.xml
                                     android.appwidget.
建立BroadcastReceiver                  provider              定義Layout布局            有限的layout元件使用
<action>欄位需明確定義為                                           畫面大小:74倍數-2
android.appwidget.action.APPWIDG                                                 有限的GUI元件使用
                                     Resource:指定           執行時間週期設定
ET_UPDATE
                                     information檔的來
                                     源
    為你把關每一道 學習品質                                                                                  292
Android Widget資料更新

• AppWidget主要是依建置在Home Launcher APP之上,
  因此Widget畫面的更新與Event互動皆必須透過一個
  Proxy來代為處理,而此Proxy就是AppWidgetManager
  元件。
• 所有待更新的Widget元件,皆必須透過RemoteViews
  元件封裝,所有的互動事件則必須透過pending Intent
  註冊於RemoteViews中。                 Home Launcher
• AppWidget元件updateAppWidget函式協助將
  RemoteViews更新於Widget元件上。            Widget
setTextViewText   setImageViewResource   AppWidget
                                          Manager
        setOnClickPendingIntent

           RemoteViews

為你把關每一道 學習品質                                         293
範例練習
          範例專案名: ex06_04_MyWidget

  練習目標:
   了解如何建置Widget元件
   學習如何為Widget加入listener與更新UI
  程式撰寫
   實作一個Widget 的receiver元件,並實作組態設定
    Activity,Widget啟動前會現顯示Activity應用程式。
   撰寫Appwidget_info.xml檔,決定Widget顯示方式
   撰寫Layout_sample.xml,決定Widget顯示的UI樣式。
   撰寫RemoteView更新函式,取得Widget觸發事件,
    並依事件狀態更新WidgetUI
  操作練習
   透過模擬器操作
為你把關每一道 學習品質                               294
Android Widget程式開發-組態設定Activity

• AppWidget組態設定Activity
  • 當用戶新增一個Widget時,系統可以呼叫一個組態設定
    Activity,提供用戶對該Widgegt進行設定,如改變顏色,顯示
    大小,執行週期..等等資訊。

• 如何為AppWidget配置組態設定Activity
  • AndroidManifest.xml中定義Activity,<action>需定義為:
    ACTION_APPWIDGET_CONFIGURE
     <activity android:name="myAppWidgetConfigure">
     <intent-filter>
     <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
     </intent-filter>
     </activity>
  • 於appwidget_info.xml中指定要呼叫的Activity
     <appwidget-provider
     ....
     android:configure= " com.example.android.appwidget.myAppwidgetConfigures"
     />
為你把關每一道 學習品質                                                                     295
Android Widget程式開發-組態設定Activity

• AppWidget呼叫組態設定Activity時注意事項
  • AppWidget呼叫執行Activity後,此Activity必須要返回一個結果,
    而此結果必須要包含Widget ID(存在EXTRA_APPWIDGET_ID)
  • Activity被建立時,AppWidget中的onUpdate方法將不會被呼叫
    到,因此Activity完成組態設定後一定要負責更新AppWidget程式
    (可以透過請求AppWIdgetManager協助更新)

• 組態設定Activity實作方式
  • Step1:透過Intent取得AppWidget ID

     final Bundle extras = getIntent().getExtras();
     If(extras != null){
           int mAppWidgetId = extras.getInt(
                   AppWidgetManager.EXTRA_APPWIDGET_ID,
                   AppWidgetManager.INVALID_APPWIDGET_ID);
     }


為你把關每一道 學習品質                                                 296
Android Widget程式開發-組態設定Activity

• Step2:執行組態設定,等待用戶設定操作
• Step3:設定完成後,更新AppWidget UI畫面
       AppWidgetManager appWidgetManager =
       AppWidgetManager.getInstance(LifeCycleConfigure.this);
       RemoteViews views = new RemoteViews(getPackageName(), R.layout.life_cycle);
       appWidgetManager.updateAppWidget(mAppWidgetId, views);




• Step4:最後建立一個Intent返回結果,並結束Activity
       Intent resultValue = new Intent();
       resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
       mAppWidgetId);
       setResult(RESULT_OK, resultValue);
       finish();




為你把關每一道 學習品質                                                                         297
範例練習
          範例專案名: ex06_05_Appwidget

  練習目標:
   了解桌面Widget應用程式的撰寫方式與生命流程
   學習如何為Widget加入組態設定用Activity
  程式撰寫
   實作一個Widget 的receiver元件,並實作組態設定
    Activity,Widget啟動前會現顯示Activity應用程式。
   撰寫Appwidget_info.xml檔,決定Widget顯示方式
   撰寫Layout_sample.xml,決定Widget顯示的UI樣式。
  操作練習
   透過模擬器操作

為你把關每一道 學習品質                               298
第8節: Broadcast Receiver元件
       Services元件
Broadcast Receiver與Service元件

  BroadCastReceiver元件
     廣播的用途與種類
     如何發送廣播封包
     如何註冊接收廣播封包
     廣播封包加入自定權限
  Services 元件應用
     Local 與 Remote Services
     Services生命週期
     如何與Services進行溝通
     Remote Services設計實作
     如何與RemoteServices溝通
     Services與Activity通訊架構
      設計

                                300
BroadCast Receiver元件

• 廣播接收程式可用來接收其他應用程式所發出的訊息。
• 許多的廣播通知訊息都是來自於Android作業系統
  • 電池電量快用盡
  • 網路連線變化
  • 有來電或簡訊通知

• 應用程式本身也可以發出廣播訊息,可做為與其他應用程
  式互動溝通的管道。
  • 需注意的是廣播訊息是公開的,任何應用程式都可以
    透過註冊BraodCast Receiver來接收到你所廣播的訊
    息。

• 一般常用來做為Services應用程式與Activity應用程式溝通
  使用。

為你把關每一道 學習品質                           301
BroadCast Receiver元件

• 如何發送廣播
  • 在程式中透過Intent建立好希望被那些action filter所接
    收,接著透過sendBroadcast函式發送出去。
     public static final String NEW_BROADCAST=
     " com.ittraining.action.NEW_BROADCAST ";

     Intent intent = new Intent(NEWO_BROADCAST);
     intent.putExtra(" data1",someData);
     intent.putExtra(" data2",someData);
     sendBroadcast(intent);




為你把關每一道 學習品質                                       302
BroadCast Receiver元件
• 如何接收廣播
   • 想接收並且處理廣播的Intent,就必需要註冊一個
     BroadcastReciever,並且設定一個Intent Filter以將不需
     要監聽的訊息過慮掉,最後在將其註冊到Android框架
     中。

• Step1: 繼承BroadcastReceiver類別,並覆寫
  onReceive(Context context, Intent intetn)函式
   • 需注意onReceive函式內的處理不宜超過5秒,長時間
     的處理建議移到Thread中執行。

    public class IttrainingAndroidReceiver extends BroadcastReceiver{
         @override
         Public void onReceive(Context context, Intent intent){
              //接收後的處理
         }
    }
為你把關每一道 學習品質                                                            303
BroadCast Receiver元件

• Step2: 註冊BroadCastReceiver
   • 透過XML註冊
  <receiver android:name= " IttrainingAndroidReceiver " >
       <intent-filter>
         <action android:name= " com.ittraining.action.NEW_BROADCAST " />
       </intent-filter>
  </receiver>

    • 透過程式碼註冊
  IntentFilter filter =new IntentFilter(NEW_BROADCAST);
  IttrainingAndroidReceiver receiver=new IttrainingAndroidReceiver();
  registerReceiver(receiver , filter);
  unregisterReceiver(receiver);
    • 取消註冊
  unregisterReceiver(receiver);

為你把關每一道 學習品質                                                                304
範例練習
        範例專案名: ex07_01_Broadcastreceiver

  練習目標:
   學習如何發送廣播訊息
   了解如何接收其它應用程式所發出的廣播訊息
  程式撰寫
   建立一個Activity應用程式與二個Recever程式
   由Activity發送broadcast至Recever程式
  操作練習
   透過模擬器操作。注意兩個receiver的<intent-
    filter>action name並不相同,透過Activity可透過
    不同的action決定要將訊息broadcast至指定的
    receiver.
為你把關每一道 學習品質                               305
BroadCast Receiver元件-安全性管理

• Android廣播服務安全性漏洞
  • 主要利用Intent Filter做為過濾,任何其它應用
    程式只要得知廣播的Action Name就可以註冊
    取得該廣播的資料。這將存在一個安全性的漏
    洞,若你的廣播中所傳遞的是很重要的資料,
    這將有可能被其它惡意軟體給監聽取得。

• 增加自訂權限傳送與接收廣播
  • 開發者可為自己的APP程式加入自訂權限,任
    何的應用程式如果要接收該廣播資料,則必須
    宣告取得相關的權限。


為你把關每一道 學習品質                       306
BroadCast Receiver元件-安全性管理

• 增加權限到AndroidManifest.xml定義描述檔
  <permission
          android:name="com.ittraining.ex07_02.SEND_DATA"
          android:description="@string/permission_aceess_deta"
          android:label="@string/permission_aceess"
          android:protectionLevel="normal" >
   </permission>

• name:權限名稱,請求權限與執行權限時使用,必須為唯
  一的值。
• description:提供詳細說明為何需要此權限,與如何使用
• lable:用戶安裝軟體時顯示給使用者看,以提供用戶進行
  授權,此字串不應太長。
• protectionLevel:權限等級,normal為最基本等級。

為你把關每一道 學習品質                                                     307
BroadCast Receiver元件-安全性管理

• 於AndroidManifest.xml宣告請求使用者授權
  <uses-permission android:name="com.ittraining.ex07_02.SEND_DATA"/>


• 發送廣播時於sendBroadcast第二個參數帶入權
  限名稱
  sendBroadcast(intent, "com.ittraining.ex07_02.SEND_DATA“);


• 接收端在註冊Receiver元件時,第三個參數需帶
  入權限名稱
  registerReceiver(receiver,filter, "com.ittraining.ex07_02.SEND_DATA“,null);




為你把關每一道 學習品質                                                                    308
Services元件
 • Services是在背景運作,不直接與使用者互動,因此並無
   UI畫面
 • Services無法獨立自行運作,而必須透過Activity或其它
   Context物件來呼叫啟動
   • Context.startService()
   • Context.binService()
 • 若Services的onCreate(),onStart()內需執行一些耗時的處
   理,請使用Thread處理,以避免造成UI操件lock.
 • 使用Services的好處,在於Activity結束後其Services元件
   依然會在背景做運行,Services有其獨立的生命週期不會
   受Activity生命週期影影。
   – 播放音樂
   – 背景接收網路訊息
為你把關每一道 學習品質                              309
Services元件
 • Android Services的使用方式可區分為二類
    • Local Services (操作自己應用程式的Services)
    • Remote Services (操作其它應用程式的Services)

 • 與Services溝通方式
   • 透過BroadCast傳送Intent至Services
   • 透過Binder與Services做Local Services連結
   • 透過IPC(interprocess communication)與Remote
     Services做連結
   • 透過Contex.getSystemService(String name),函
     式可取得Android預設的Services元件.


為你把關每一道 學習品質                                    310
Services元件-與Activity溝通方式
 • Services元件與前景的Activity元件之間的溝通架構設
   計模式




為你把關每一道 學習品質                          311
Services元件
 • Android系統內提供的一些Services服務
             Services代碼        對應Manager 物件               說明
  WINDOW_SERVICE            WindowManager         管理視窗畫面
  LAYOUT_INFLATER_SERVICE   LayoutInflater        載入xml檔所定義的View元件
  ACTIVITY_SERVICE          ActivityManager       管理應用程式的系統狀態
  POWER_SERVICE             PowerManger           電源管理
  ALARM_SERVICE             AlarmManager          鬧鐘管理
  NOTIFICATION_SERVICE      NotificationManager   狀態列訊息通知服務
  KEYGUARD_SERVICE          KeyguardManager       鍵盤鎖管理
  LOCATION_SERVICE          LocationManager       位置服務管理,GPS
  SEARCH_SERVICE            SearchManager         搜尋服務管理
  VEBRATOR_SERVICE          Vebrator              振動服務管理
  CONNECTIVITY_SERVICE      Connectivity          網路連線服務管理
  WIFI_SERVICE              WifiManager           WIFI連線服務管理
  TELEPHONY_SERVICE         TeleponyManager       電話服務管理


為你把關每一道 學習品質                                                         312
Services元件-與Activity繼承關係




為你把關每一道 學習品質               313
Services元件-生命週期
 • Services元件有其獨
   立的生命週期
    • onCreate()
    • onStart()
    • onDestroy()
 • 啟動Services的方式
   不同,對應的生命
   週期也不同。
    • startServices()
    • bindServices()




為你把關每一道 學習品質            314
Services元件-啟動Services
 • Step1: 於AndroidManifest.xml中加入Services宣告
    <service android:enabled="true" android:name=".TestService" />

 • Step2:覆寫Services函式-處理生命週期
    public class TestService extends Service {
           @Override
           public void onCreate() {
                  Log.e(TAG, "============> TestService.onCreate");
           }
           @Override
           public void onStart(Intent intent, int startId) {
                  Log.e(TAG, "============> TestService.onStart");
           }
           @Override
           public void onDestroy() {
                  Log.e(TAG, "============> TestService.onDestroy");
           }
    }




為你把關每一道 學習品質                                                           315
Services元件-啟動Services
 • Step3:覆寫Services函式-提供Bind接口
          @Override
          public IBinder onBind(Intent i) {
                 return new LocalBinder();;
          }
          public class LocalBinder extends Binder {
                 TestService getService() {
                        return TestService.this;
                 }
          }
          @Override
          public boolean onUnbind(Intent i) {
                 Log.e(TAG, "============> TestService.onUnbind");
                 Return true;
          }
          @Override
          public void onRebind(Intent i) {
                 Log.e(TAG, "============> TestService.onRebind");
          }




為你把關每一道 學習品質                                                         316
Services元件-啟動Service
 • Step4:透過Activity啟動Service-使用startService()
             private void startService() {
                  Intent i = new Intent(this, TestService.class);
                  this.startService(i);
             }
             private void stopService() {
                  Intent i = new Intent(this, TestService.class);
                  this.stopService(i);
             }

 • Step4:透過Activity啟動Services-使用bindService()
       private void bindService() {
            Intent it = new Intent(this, TestService.class);
             bindService(it , _connection, Context.BIND_AUTO_CREATE);
             _isBound = true;
         }
        private void unbindService() {
            if (_isBound) {
               unbindService(_connection);
               _isBound = false;
            }
為你把關每一道}學習品質                                                            317
Services元件-啟動Service
 • Step6:SerrviceConnection元件建立-透過bindService()
  private ServiceConnection _connection = new ServiceConnection() {
      public void onServiceConnected(ComponentName className, IBinder service){
             _boundService = ((TestService.LocalBinder)service).getService();
             Toast.makeText(TestServiceHolder.this, "Service connected:",
             Toast.LENGTH_SHORT).show();
      }

        public void onServiceDisconnected(ComponentName className) {
               _boundService = null;
               Toast.makeText(TestServiceHolder.this, "Service connected",
               Toast.LENGTH_SHORT).show();
        }
   };




為你把關每一道 學習品質                                                                      318
BroadcastReceiver與Services綜合演練

 • 結合Services服與程式與BroadcastReceiver,實作
   一鬧鐘計時器。

提供UI畫面讓User設定鬧鐘時                              Services在背景進行時間排程倒
間設定完成後會通知背景                                   數,當時間到時透過broadcast訊
Services進行倒數計時,並註冊                            息,傳送回主程式,並播放一段鬧鐘
一個BroadcastReceiver類別                         音效與Toast訊息

           KitchenTimer.java                     KitchenTimerService.java
              KitchenTimer                       Schedule(long delay)
 KitchenTimerSdervice.shecule(alarmtimer)    Timer.shedule(timerTask,delay)

               KitchenTimer                            TimerTask()
       KitchenTimerReceiver-receiver        sendBroadcast(new Intent(ACTION))




為你把關每一道 學習品質                                                                    319
BroadcastReceiver與Services綜合演練

 • Step1:建立Services宣告
   <service android:enabled="true" android:name=".KitchenTimerService" />

 • Step2:主程式onCreate()
   //啓動服務程式KitchenTimerService
   Intent intent = new Intent(this, KitchenTimerService.class);
   startService(intent);
   //註冊廣播接收receiver
   IntentFilter filter = new IntentFilter(KitchenTimerService.ACTION);
   registerReceiver(receiver, filter);
   //(Bind)服務程式KitchenTimerService
   bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);




為你把關每一道 學習品質                                                                320
BroadcastReceiver與Services綜合演練

  • Step3:主程式onDestroy()
       //Activity結束時,要將Service相關資源一並結束
       @Override
       public void onDestroy() {
              super.onDestroy();
              unbindService(serviceConnection); //Unbind service
              unregisterReceiver(receiver); //Unregister Receiver
              kitchenTimerService.stopSelf(); //Stop Service
       }

  • Step4:定義接收廣播類別KitchTimerReceiver
   private class KitchenTimerReceiver extends BroadcastReceiver {
         public void onReceive(Context context, Intent intent) {
                 Toast toast = Toast.makeText(getApplicationContext(), "Time over!",
                 Toast.LENGTH_LONG);
                 toast.show();
                 MediaPlayer mp = MediaPlayer.create(KitchenTimer.this, R.raw.alarm);
                 try {
                              mp.start();
                 } catch (Exception e) {
                 }
                 kitchenTimerService.schedule(alarmtimer);
         }
為你把關每一道 學習品質
   }                                                                                    321
BroadcastReceiver與Services綜合演練

 • Step5:定義與Service bind的ServiceConnection
   private ServiceConnection serviceConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
               kitchenTimerService =
               ((KitchenTimerService.KitchenTimerBinder)service).getService();
         }
         public void onServiceDisconnected(ComponentName className) {
               kitchenTimerService = null;
         }
   };




為你把關每一道 學習品質                                                                          322
BroadcastReceiver與Services綜合演練

 • Step6:建立Services類:KitchenTimerService
  public void onCreate() {
         super.onCreate();
         Toast toast = Toast.makeText(getApplicationContext(), "onCreate()", Toast.LENGTH_SHORT);
         toast.show();
  }
  public void onStart(Intent intent, int startId) {
         super.onStart(intent, startId);
         Toast toast = Toast.makeText(getApplicationContext(), "onStart()", Toast.LENGTH_SHORT);
         toast.show();
  }
  public void onDestroy() {
         super.onDestroy();
         Toast toast = Toast.makeText(getApplicationContext(), "onDestroy()", Toast.LENGTH_SHORT);
         toast.show();
         if (timer != null) {
                timer.cancel();
                timer = null;
         }
  }




為你把關每一道 學習品質                                                                                         323
BroadcastReceiver與Services綜合演練

 • Step7:覆寫Services Bind相關函式
  @Override
  public IBinder onBind(Intent intent) {
         Toast toast = Toast.makeText(getApplicationContext(), "onBind()", Toast.LENGTH_SHORT);
         toast.show();
         return new KitchenTimerBinder();
  }
  @Override
  public void onRebind(Intent intent) {
         Toast toast = Toast.makeText(getApplicationContext(), "onRebind()", Toast.LENGTH_SHORT);
         toast.show();
  }
  @Override
  public boolean onUnbind(Intent intent) {
         Toast toast = Toast.makeText(getApplicationContext(), "onUnbind()", Toast.LENGTH_SHORT);
         toast.show();
         return true; //當再度自Client接口時,呼叫 onRebind的場合會回覆 true
  }




為你把關每一道 學習品質                                                                                        324
BroadcastReceiver與Services綜合演練

 • Step8:Service發送廣播訊息至主程式
         public void schedule(long delay) {
              if (timer != null) {
                     timer.cancel();
              }
              timer = new Timer();
              TimerTask timerTask = new TimerTask() {
                     public void run() {
                                 //送出信息給廣播接收程式
                                 sendBroadcast(new Intent(ACTION));
                     }
              };
              //設定Alarm time,且Time out時會執行timerTask送出信息
              timer.schedule(timerTask, delay);
         }




為你把關每一道 學習品質                                                          325
範例練習

          範例專案名: ex07_02_Kitchentimer

  練習目標:
   學習如何結合BroadCastReceiver與Services的應用
  程式撰寫
   實作一個Activity並內置一個Receiver類別,當用設定
    好時間後將啟動一個Services在背景做倒數計時的動
    作。
   實作一個Services應用程式,由Activity所呼叫建立,
    當指定的計時工作結束後將透過broadcast方式通知
    Activity的receiver類別。
  操作練習
   透過模擬器操作,倒數計時的單位為分鐘。時間到後
    會發出聲響,並顯示一段Toast字串於畫面上。
為你把關每一道 學習品質                              326
Remote Services應用

• 要將Services元件跑在獨立的Processe中可透過在
  AndroidMainfest.xml中,宣告services元件加上
  android:process=":remote"
    <service android:name=".services.TrackerServices"
    android:process=":remote">


• Services中設置Messenger可以提供與遠端Services元件進
  行雙向溝通。
  private Handler mHandler = new Handler() {
       @Override
       public void handleMessage(Message msg) {
              /*接收來自client傳來的訊息*/
       }
     }
  private Messenger mMessenger = new Messenger(mHandler);
  @Override
  public IBinder onBind(Intent intent) {
       return mMessenger.getBinder();
  }
為你把關每一道 學習品質                                                327
Remote Services應用

• Client端在利用Bind與遠端Services連接,並取得
  Messenger元件。
 private Messenger remoteMessenger;
 private ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
          remoteMessenger = new Messenger(service);
        }
        public void onServiceDisconnected(ComponentName name) {
          remoteMessenger = null;
        }
     };

• 傳送訊息至Remote Services
 Private Message localMessenger;
 private void sendMessage() {
       Message message = Message.obtain(null, 0);
       message.replyTo = localMessenger;
       try {
          rMessenger.send(message);
       } catch (RemoteException e) {
         e.printStackTrace(); }
 }
為你把關每一道 學習品質                                                                    328
範例練習

         範例專案名: ex07_03_RemoteService

  練習目標:
   了解RemoteServices與Local Services的差別
   學習如何使用Messenger進行IPC跨Process通訊
  程式撰寫
   撰寫一個Services元件,並將process tag設為:remote
   設置Messenger 物件做為IPC通訊管道。
   撰寫Activity 元件,利用Bind 與remote services 通
    訊。
  操作練習
   透過模擬


為你把關每一道 學習品質                                  329
IntentService應用

• Android預設所有的四大元件都是運行在主執行緒中,包含
  Service也是運行在主執行緒中,因此若在Service執行耗時
  的工作則將會導致UI lock。避免UI Lock的方式為將Service
  設置為remote,或是透過IntentService。

• IntentService 為一次性使用的Service元件,並且會自動運
  行在子執行緒中,使用者可以免除複雜的Message、Loop
  與Handler設計,透過Intentservice可以快速的處理一次性
  耗時的工作。

• 將工作放置於IntentService的優勢
  • 比較不容易被系統Kill
  • 工作於子執行緒中,不會導致UI Thread Lock
  • 非常容易使用,使用完即自動回收,不佔用記憶體。

為你把關每一道 學習品質                          330
範例練習

          範例專案名: ex07_04_IntentService

  練習目標:
   了解Intent Service、Thread與Service的差別
   學習如何利用Intent Service 在背景處理耗時的工作
  程式撰寫
   繼承IntentService類別,並實作onHandleIntent函式
   將耗時的工作寫在onHandleIntent函式中。
   撰寫Activity頁面,利用startService函式呼叫
    IntentService工作。
  操作練習
   透過模擬
為你把關每一道 學習品質                                331
第9節: SQLite DataBase開發技巧
SQLite DataBase開發技巧

  SQLite Database存取技巧
     SQLite語言定義與建置工具
     SQLiteOpenHelp類別實作
     資料庫的基本IO操作方式
     設計DataBase Adapter架構




                             333
SQLite DataBase

• SQLite是Android內建的一個輕量化的嵌入式資料庫,可使
  用SQL語法進行控制存取。

• SQLite的優點
   • 免費,無需授權
   • 輕量,約150KB左右,很適在嵌入式手機領域使用
   • 無需設定、安裝與管理,沒有伺服器,不需組態檔,無
     需資料庫管理員
   • SQLite只是一個檔案,可以很方便的移動或複製到另一
     系統,也能運作的很良好。

• Android將SQLite檔案存放於下列路徑中
   • /data/data/packagename/databases
   • 可以使用adb或File Explorer來觀移存取資料庫檔案

為你把關每一道 學習品質                            334
SQLite DataBase

• SQL入門
   • SQL描述語法主要包含三種類型
      • DLL(資料定義語言)
      • 修改
      • 查尋
• DLL資料定義語言:
   • 資料庫的組成由多個資料表(table)多個資料列(Row)
     若干資料欄(column)所組成。
   • 每個資料欄具有欄位名稱與資料類形(文字,數字…)
   Create table mytalbe(
   _id integer primary key autoincrement,
   Name text,
   Phone text)

  • 第一個欄位指定為主鍵(PRIMARY KEY)
為你把關每一道 學習品質                                335
SQLite DataBase
• 安裝Questoid SQLite Browser Eclipse Plugin,協助以圖形化方式觀看
  Android內的SQLite資料表
   • http://www.questoid.net/Tools/QuestoidSQLiteBrowser.aspx
   • 將com.questoid.sqlitebrowser_1.1.0.jar Copy至Eclipse的plugins目
     錄中,並重新啟動Eclipse.
   • 切換至DDMS視圖,利用File Explorer工具找到要查看的SQLite
     data base檔案.




• SQL語法指令查尋與學習資源
   • http://www.1keydata.com/tw/sql/sqlhaving.html

為你把關每一道 學習品質                                                  336
SQLite DataBase-SQLiteOpenHelper

• Android應用程式中提供了SQLiteOpenHelper類別來協助操
  作SQLite資料庫並,提供產生與管理資料庫的版本

• SQLiteOpenHelper為一抽像類別,需繼承並實作三個函式
  • onCreate(SQLiteDatabase db)
     • 資料庫第一次產生時呼叫。
  • onUpdate(SQLiteDatabase db,int oldVersion,int newVersion)
     • 當資料庫需要升級時,由系統主動呼叫。一般用來刪除舊資料
       表,並建立新的資料表
  • onOpen(SQLiteDatabase db)
     • 當資料庫被開啟時的Callback函式,由系統呼叫,一般不會使用到。




為你把關每一道 學習品質                                                    337
SQLite DataBase-SQLiteOpenHelper

• 如何建立SQLiteOpenHelper類別
  private static final String DATABASE_NAME = "dbForTest.db";
  private static final int DATABASE_VERSION = 1;
  private static final String TABLE_NAME = "diary";
  private static final String TITLE = "title";
  private static final String BODY = "body";
  private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
              super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        @Override
        public void onCreate(SQLiteDatabase db) {
              String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE
              + " text not null, " + BODY + " text not null " + ");";
              db.execSQL(sql);
        }
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
  }
為你把關每一道 學習品質                                                                         338
SQLite DataBase-SQLiteOpenHelper

• 取得透過SQLiteOpenHelper取得SQLiteDatabase類別
  Public Methods
  synchronized SQLiteDatabase           getReadableDatabase()Create and/or open a database.


  synchronized SQLiteDatabase           getWritableDatabase()Create and/or open a database
                                        that will be used for reading and writing.



• 利用SQLiteDatabase提供的函式可以存取操作資料庫
  •   public Cursor rawQuery (String sql, String[] selectionArgs)
        •   最低階的操作函式,可以直接接受標準SQL語法
  • 為方便不熟SQL語法的開發者,另外有提供一系列的API函式,系統
    會將API指令自動轉換成標準的SQL語法呼叫資料庫。
        •   pubilc delete(….)
        •   pubilc insert(….)
        •   pubilc update(….)
        •   public Cursor query (….)
為你把關每一道 學習品質                                                                                  339
SQLite DataBase-資料庫操作

• 如何插入資料庫記錄
  private void insertItem() {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        String sql1 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY
        + ") values('haiyang', 'android的發展真是迅速');";
        String sql2 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY
        + ") values('icesky', 'android的發展真是迅速');";
        try {
              db.execSQL(sql1);
              db.execSQL(sql2);
              setTitle("插入兩條數據成功");
        } catch (SQLException e) {
              setTitle("插入兩條數據失敗");
        }
  }




為你把關每一道 學習品質                                                                     340
SQLite DataBase-資料庫操作

• 如何刪除資料記錄
  private void deleteItem() {
        try {
              SQLiteDatabase db = mOpenHelper.getWritableDatabase();
              db.delete(TABLE_NAME, " title = 'haiyang'", null);
              setTitle("刪除title為haiyang的一條記錄");
        } catch (SQLException e) {
        }
  }

• 查尋資料
  private void showItems() {
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        String col[] = { TITLE, BODY };
        Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null);
        Integer num = cur.getCount();
        setTitle(Integer.toString(num) + " 條記錄");
  }


為你把關每一道 學習品質                                                                    341
SQLite DataBase-資料庫操作
• 刪除整個Table
    private void dropTable() {
          SQLiteDatabase db = mOpenHelper.getWritableDatabase();
          String sql = "drop table " + TABLE_NAME;
          try {
                 db.execSQL(sql);
                 setTitle("數據表成功刪除︰" + sql);
          } catch (SQLException e) {
                 setTitle("數據表刪除錯誤");
          }
    }

• 建立新的Table
  private void CreateTable() {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE
        + " text not null, " + BODY + " text not null " + ");";
        try {
               db.execSQL("DROP TABLE IF EXISTS diary");
               db.execSQL(sql);
               setTitle("數據表成功重建");
        } catch (SQLException e) {
               setTitle("數據表重建錯誤");
        }
為你把關每一道 學習品質
  }                                                                342
範例練習
               範例專案名: ex08_01_Sqlite

  練習目標:
   學習如何建立與使用SQLite資料庫
  程式撰寫
     撰寫DataBaseHelper 繼承SQLiteOpenHelper
     透過DataBaseHelper取得SQLiteDatabase物件,並實作新
      增、刪除、查尋、建立資料表等函式
  操作練習
   透過模擬器操作,可以藉由DDMS的檔案瀏覽器
    將SQLite資料庫檔滙出,或滙入現有的SQLite資
    料庫至手機上。

為你把關每一道 學習品質                                    343
SQLite DataBase-Query函式
• SQLiteDatabase的query方法
   • Cursor query (boolean distinct, String table, String[] columns,
                   String selection, String[] selectionArgs, String groupBy,
                   String having, String orderBy, String limit)
    • distinct : 是否希望每一row都是唯一的
    • table:要查尋的資料表(Table)
    • columns:回傳資料包含的訊息列。不在清單中的其它列將不會取得。
    • selection:相當於SQL中的where,如想傳回所有資料請用null
    • selectionArgs:如select中有使用到[?]變數,此字串將用來取代[?]
    • groupBy:查尋得到的資料是否要分群組
    • having:相當於SQL中的having
    • orderBy:是否需要排序,若設定為null代表不排序
    • limit:限制查尋回的資料組數上限


為你把關每一道 學習品質                                                                   344
SQLite DataBase-Cursor介面
• android.database.Cursor介面
   • 由query方法查尋到資料後,將會回傳Cursor物件。
   • 透過Cursor可以將資料庫查出來的資料進行讀寫操作。
   • Cursor可以連結CursorAdapter並覆寫其bindView()和newView()兩
     抽像方法來達到更豐富的顯示方式


                               Activity

                                          SQLiteOpenHelper



         Cursor      Query結果

                                           SQLiteDatabase



為你把關每一道 學習品質                                                 345
SQLite DataBase-Cursor介面
• Cursor常用的函式
                        函式                      說明
      movetoPosition(int pos)        移動Cursor到指定位置
      Move(int offset)               向前或向後位移:正數向前,負責向後
      moveToFirst()                  移動Cursor到最前或最後位置
      moveToLast()
      moveToNext()                   將Cursor向前或向後移動一格
      moveToLast()
      isBeforeFirst()                判斷Cursor是否指向第一個數據之前,或最
      isAfterLast()                  後一個數據之後
      isFirst()                      判斷Cursor是否指向第一行或最後一行
      isLast()
      getColumnCount()               取得行(列)數目
      getCount()
      getColumnIndexOrThrow(String   根據列的名稱取得索引值(以0開始)
      columnName)
   getBlob(int index)                依據資料型別取回Cursor目前所指的資料。
   getInt(int index)
   getLong(int index)
   getShort(int index)
   getFloat(int index)
為你把關每一道 學習品質
   getString(int index)                                       346
SQLite DataBase-Cursor介面
• Cursor與CursorAdapter連接
  • public SimpleCursorAdapter (Context contex, int layout, Cursor c,
    String[]from, int[] to)
       • context:作用於那個Context物件上
       • layout:顯示介面layout樣版,需包含to所指定的View id
       • c: cursor資料來源
       • from:需要從cursor取出的列名稱索引值
       • to:layout中需要作用對應於from值的View元件id

 s = (Spinner)findViewById(R.id.spinner);
 display = (TextView)findViewById(R.id.display);
 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
 android.R.layout.simple_spinner_item,c,new String[] { MyHelper.COUNTRY},
 new int[] {android.R.id.text1});
 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_it
 em);
 s.setAdapter(adapter);
 為你把關每一道 學習品質                                                                  347
SQLite DataBase-日記簿運作流程
         ActivityDiaryEdit
                                                DiaryDbAdapter
   onCreate ()
   onClick()                                    deleteDiary()
                                                createDiary()
                                                getAllNotes()
 EditText    EditText        Button             getDiary()
                                                updateDiary()
 ActivityMain extends ListActivity
  onMenuItemSelected()
  onCreateOptionsMenu()                         DatabaseHelper
  createDiary()
  onListItemClick()
  onCreate ()

     SimpleCursorAdapter                        NAME:database
                                                TABLE: diary
                                       Query結
                              Cursor     果
為你把關每一道 學習品質                                                     348
範例練習
           範例專案名: ex08_02_Sqldiary

  練習目標:
   學習如何利用SQLite開發一個簡單的日記本
   學習SimpleCursorAdapter的使用
  程式撰寫
   實作一個ListActivity,並將SQLite讀取得到的資料透
    過SimpleCursorAdapter顯示於ListActivity上.
   實作一個DiaryDbAdapter,協助處理與SQLite資料庫
    存取有關的所有操作
   設計一個日記輸入與編輯的UI頁面
  操作練習
   透過模擬器進行操作。
為你把關每一道 學習品質                                349
DataBaseAdapter架構實作

 • 設計DataBaseAdapter可提供Activity頁面一個統
   一且一致的存取資料庫的介面,並且將SQL語法
   隱藏在Adapter內,對外只提供高階的存取介面。


                                  SqlObject
                                    SqlObject
               DataBaseAdapter        SqlObject

                  IOInterface
                                                  Activity
  SQLite

               DataBaseOpenHelp




為你把關每一道 學習品質                                                 350
DataBaseAdapter架構實作

 • 資料庫表單常數定義介面
   • DataBaseColumnDefine
     public interface DataBaseColumnDefine {
           /* 表單名稱 */
           public static final String USERPROFILE_TABLE_NAME = "UserProfileDB";
           /* 欄位名稱 */
           public static final String USERPROFILE_KEY_ID = "_id";
           /*SQL指令*/
           public static final String SQL_CREATE="CREATE TABLE ";
           public static final String SQL_DATA_AUTO=" integer primary key autoincrement";
           public static final String SQL_DATA_NUMERIC=" NUMERIC";
           public static final String SQL_DATA_TEXT=" TEXT";

           /*建立table的sql語法*/
           public static final String CREATE_USERPROFILE_TABLE = SQL_CREATE +
           USERPROFILE_TABLE_NAME+ " ("
           + USERPROFILE_KEY_ID + SQL_DATA_AUTO+");";

           /*Query回來資料的欄位範圍*/
           public static String[] userProfileDataSet = { USERPROFILE_KEY_ID,};
     }

為你把關每一道 學習品質                                                                                351
DataBaseAdapter架構實作

 • SqlObject抽像介面設計
   • 抽像的功能
     /**
      * 取得privateKey值
      */
     abstract int getPrivateKey();
     /**
      * 設定privateKey值
      */
     abstract void setPrivateKey(int privateKey);
     /**
      * 從資料庫中讀入資料
      * @param cursor
      */
     abstract void readProfile(Cursor cursor);
     /**
      * 將資料轉換成ContentValues以供資料庫做後操作
      */
     abstract ContentValues getContentValues();




為你把關每一道 學習品質                                        352
DataBaseAdapter架構實作

 • SqlObject抽像介面
   • 產生SqlObject的建構工廠
     /**
      * 依需求取得不同型態的SQL Object
      * @param type
      * @return
      */
     public static SqlObject createUserDataObject(SqlType type){
           switch(type){
           }
           return null;
     }




為你把關每一道 學習品質                                                       353
DataBaseAdapter架構實作

 • DataBaseAdapter實作方式
   • 使用Singleton架構
     private SQLiteDatabase sqlDataBase;
     private static DataBaseAdapter dbAdapter;
     private DataBaseAdapter(Context context){
     DataBaseHelp dataBaseHelp= new DataBaseHelp(context);
           try {
                  dataBaseHelp.createDataBase();
           } catch (IOException e) {
                  e.printStackTrace();
           }
           sqlDataBase=dataBaseHelp.getWritableDatabase();
     }

     public synchronized static DataBaseInterface getInstence(Context context){
           if(dbAdapter==null)
                 dbAdapter=new DataBaseAdapter(context.getApplicationContext());
           return dbAdapter;
     }



為你把關每一道 學習品質                                                                       354
DataBaseAdapter架構實作

 • 透過DataBaseOpenHelp讀寫資料庫(SqlObject)
   • 新增
        mDb.insert(USERPROFILE_TABLE_NAME, null, initialValues);


   • 刪除
        mDb.delete(USERPROFILE_TABLE_NAME, USERPROFILE_KEY_ID + "=" +
        sqlObject.getPrivateKey(), null);

   • 修改
        mDb.update(USERPROFILE_TABLE_NAME, initialValues, USERPROFILE_KEY_ID + "="
        + sqlObject.getPrivateKey(0, null) > 0;



   • 查尋
        Cursor mCursor=mDb.query(USERPROFILE_TABLE_NAME, userProfileDataSet, null, null, null,
        null,null);

為你把關每一道 學習品質                                                                                 355
DataBaseAdapter架構實作

   • 上層Activity使用DataBaseAdapter方式
     • 取得DataBaseAdapter物件實體
        DataBaseAdapter dbAdapter=DataBaseAdapter.getInstence(this);


      • 讀取資料
        ArrayList<UserProfile>allUser= (ArrayList<UserProfile>) dbAdapter.getAllUser(null);



        ArrayList<UserProfile>allUser=dbAdapter.getAllUser(allUser); //參照更新



      • 新建資料
        profile.setPhotoType(1);
        profile.setUserCompony("test");
        profile.setUserName("Jarey");
        profile.setUserPhone("09xxx");
        long privateKey=dbAdapter.addUserProfile(profile);

為你把關每一道 學習品質                                                                                  356
範例練習
          範例專案名: ex08_03_SqlTemplet

  練習目標:
   學習如何設計DataBase Adapter
   透過DataBase Adapter層將應用層與資料存取層分
  程式撰寫
   設計一簡單的資料庫表單,並實作DataBase Adapter
    元件。
   Activity層透過DataBase Adapter對資料庫進行資料存
    取。
   實作一個BaseAdapter元件,將從DataBaseAdapter
    讀出的資料透過BaseAdapter顯示於ListView上。
  操作練習
   透過模擬器進行操作。

為你把關每一道 學習品質                               357
第10節: Content Provider元件
 Android Thread程式設計
Content Provider元件

  ContentProvider元件設計
     ContentProvider應用時機
     與系統ContentProvider連接
     自建ContentProvider




                             359
Content Provider元件

• ContentProvider作用
  • Android程式中所有的資料(包含檔案,資料庫)全都是Private的,不同
    的應用程式之間不能直接存取
  • ContentProvider提供解決不同應用程式之間交換資料的需求

• ContentProvider提供一組標準介面
  • query(Uri uri,String[] projection,String selection,String[]
    selectionArgs,String sortOrder)
     • 透過Uri進行查尋,結果將透過傳回的Cursor物件進行存取.
  • insert(Uri url,ContentValues values)
     • 將一組資料插入到Uri指定的位置
  • update(Uri url,ContentValues values,String where,String[]
    selectionArgs)
     • 更新Uri指定位置的資料
  • delete(Uri url,String where,String[] selectionArgs)
     • 刪除Uri指定並符合條件的資料

為你把關每一道 學習品質                                                      360
Content Provider元件

• ContentResolver
  • 外部應用程式可以透過ContentResolver介面來存取
    ContentProvider所提供的資料
  • ContentResolver物件是透過Activity.getContentResolver()取得
• ContentResolver所提供的存取介面
  • query(Uri uri,String[] projection,String selection,String[]
    selectionArgs,String sortOrder)
  • insert(Uri url,ContentValues values)
  • update(Uri url,ContentValues values,String where,String[]
    selectionArgs)
  • delete(Uri url,String where,String[] selectionArgs)

          Application                                 Application
                                  URI
                    Content                    Content
   Activity                                                         Data
                    Resolver    query          Provider
                                insert
                                update
為你把關每一道 學習品質                    delett                                     361
Content Provider元件

• ContentProvider 中使用的Uri形式
  • content://contacts/people/  代表全部聯絡人資料
  • content://contacts/people/1 代表ID為1的連絡人資料
• Uri的組成結構:
    content://authority/path/id

  • 第一部份:content://
    • 必要的標準前置碼(prefix)
  • 第二部份:authority
    • 提供者的名稱,在此建使用完全套件名稱定義以避免名稱出現衝
      突狀況
  • 第三部份:path
    • 為提供者內部的虛擬目錄路徑
  • 第四部份:id
    • 請求之特定記錄的主鍵ID,若要請求所有記錄可以直接以/結尾

為你把關每一道 學習品質                                   362
ContentProvider元件-讀取連絡人資料

• Android內建的ContentProvider
   • content://browser
   • content://contacts
   • content://media
   • content://settings
• Step1:於AndroidManifest.xml中加入權限
  <uses-permission android:name="android.permission.READ_CONTACTS" />

• Step2:取得ContentResolver物件,query連絡人資料
 import android.provider.ContactsContract;
 import android.content.ContentResolver;

 ContentResolver cr = getContentResolver();
 Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null,
 null, null);

為你把關每一道 學習品質                                                                363
Content Provider元件-讀取連絡人資料

• Step3:取得連絡人姓名
  String name = cur.getString(cur.getColumnIndex("display_name"));

• Ste4:取得連絡人ID (2.0.1後改版,Phone移至不同URI)
  long id = cur.getLong(cur.getColumnIndex(" _id"));


• Step5:透過ID重新查尋得使用者電話
  Cursor pcur = getContentResolver().query(
  ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
  null ,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "="
  + Long.toString(id), null, null);


  String strPhoneNumber = pcur.getString(
  pcur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));


為你把關每一道 學習品質                                                             364
範例練習
         範例專案名: ex08_04_Contentprovider

  練習目標:
   學習如何建立ContentResolver並連接至Android
    的連絡人Content Povider,取得用戶的連絡人清
    單資料
  程式撰寫
   透過getContentResolver ()取得ContentResolver
    物件
   連接至Android CONTENT_URI ,並將資料透過
    adapter顯示於ListView上
  操作練習
   透過模擬器操作

為你把關每一道 學習品質                                   365
ContentProvider元件-自建ContentProvider
• 修改先前的日記簿範列,將新增、刪除、修改與查尋操作改以
  ContentProvider的方式來實作。
           ActivityDiaryEdit
     EditText    EditText    Button
                                                    DiaryContentProvider
     insertDiary()          Content                extend ContentProvider
     updateDiary()          Resolver
                                                    Content    query()
                                                    Provider   Insert()
                                                               delete()
  ActivityMain extends ListActivity                            update()
 onMenuItemSelected()
 onCreateOptionsMenu()         Content
 onOptionsItemSelected()       Resolver
 onListItemClick()                                   SQLiteOpenHelper

       SimpleCursorAdapter

       Diary
                                          Query結     NAME:database
                                 Cursor
   BaseColumns
為你把關每一道 學習品質
                                            果        TABLE: diary
                                                                            366
ContentProvider元件-自建ContentProvider

• Diary類別實作
public final class Diary {
//這裡的 AUTHORITY 要求是唯一,而且和Manifest當中provider標籤的AUTHORITY內容一致
  public static final String AUTHORITY = "com.ex09_2_contentprovider.diarycontentprovider";
  private Diary() {}
  public static final class DiaryColumns implements BaseColumns {
    // This class cannot be instantiated
    private DiaryColumns() {}
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/diaries");
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.diary";
    public static final String CONTENT_ITEM_TYPE =
            "vnd.android.cursor.item/vnd.google.diary";
    public static final String DEFAULT_SORT_ORDER = "created DESC";
    public static final String TITLE = "title";
    public static final String BODY = "body";                    _id      title  body        create
    public static final String CREATED = "created";
                                                              unique-id 標題        內文        建立時間
  }
}                                                             unique-id 標題        內文        建立時間



 為你把關每一道 學習品質                                                                                    367
ContentProvider元件-自建ContentProvider

• DiaryContentProvider類別實作
  • 繼承自ContentProvider類別
  • 定義Uri類別變數:
      content://com.ex09_2_contentprovider.diarycontentprovider/diaries
       • content:固定的開頭不用更改
       • AUTHORITY:授權字串必須是唯一的,宣告告於AndroidManifest.xml
       • request: 資料型別,在此只定義一個型別,對應資料表名稱。也可以設
          計成兩個公開的資料表例如 diaries/my ,diaries/other.
       • id:代表要存取那一筆資料
  • 建構資料儲存系統,在此使用的是SQLite資料庫
  • 實作ContentProvider抽像方法
    • oncreate();query();inster();delete();update();getType();
  • 於AndroidManifest.xml中加入<provider>標籤
   <provider android:name="DiaryContentProvider"
   android:authorities="com.ex09_2_contentprovider.diarycontentprovider" />



為你把關每一道 學習品質                                                                  368
ContentProvider元件-自建ContentProvider

• android.database.sqlite.SQLiteQueryBuilder類別介紹
   • 建構SQL查尋語法的輔助類別
      SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

   • qb.query(SQLiteDatabase db,String[] projectionIn,String selection,String[]
     selectionArgs,String groupBy,String having,String sortOrder,String limit);




為你把關每一道 學習品質                                                                369
ContentProvider元件-自建ContentProvider

• android.content.ContentUris類別介紹
   • URI的一個補助類別,包含了二個函式
      • Public static Uri withAppendedId(Uri contentUri,long
        id)
         • 負責將id和Uri串接在一起成新的Uri。
             Uri diaryUri = ContentUris.withAppendedId(
             Diary.DiaryColumns.CONTENT_URI, rowId)

      • Public static long parseId(Uri contentUri)
         • 負責把Uri後的id解析出來。
         • 例如com.ex09_2_contentprovider.diarycontentprovider/100
           透過parseId後回傳值為100




為你把關每一道 學習品質                                                  370
ContentProvider元件-自建ContentProvider

• android.content.UriMatcher類別介紹
   • 為用來判斷Uri的一個補助類別
   • 提供方便的判斷Uri是針對單一資料的要求,或是針對全部
     資料的要求
   • 建立比對條件式
    sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    sUriMatcher.addURI(Diary.AUTHORITY, "diaries", DIARIES);
    sUriMatcher.addURI(Diary.AUTHORITY, "diaries/#", DIARY_ID);


  • 進行比對
    sUriMatcher.match(uri)




為你把關每一道 學習品質                                                      371
範例練習
       範例專案名: ex08_05_Contentprovider_Diary

  練習目標:
   學習如何自行建立一個ContentProvider
   學習如何透過ConentResolver與ContentProvider
    連接存取資料。
  程式撰寫
   將前一個範例中的DiaryDbAdapter改繼承至
    ContentProvider,並提供一個URI接口,讓其他
    應用程式可以連接存取資料。
  操作練習
   透過模擬器操作,觀查使用ContentProvider實作
    的不同處

為你把關每一道 學習品質                                  372
Android Thread程式設計
 Android Thread運作機制
    認識Looper與Message Queue
    Handler
 如何進入UI Thread變更UI內容
    Handler
    Activity.runOnUiThread
    View.post(Runnable)
    AsyncTask




                          373
Android Thread運作機制-Looper與MQ

• 在Android中Thread分為有Message Queue的循環Thread
  與沒有Message Queue的循環Thread兩種。

• 有Message Queue的循環Thread
  • 主執行緒(UI Thread)為有包含Message Queue的
    Thread.
  • Looper會不斷循環的確認Message Queue裡是否有要
    處理的Event.
  • 可透過Handler物件來將訊息丟到MQ中
                                             Looper

• 無Message Queue的循環Thread
  • 由主執行緒產生的子執行緒並不                            MQ
    會具有Looper與MQ物件                    Push

                            Handler
為你把關每一道 學習品質          374                             374
Android Thread運作機制-Looper與MQ

• MQ可做為執行緒之間的溝通管道
  • 子執行緒可透過Handler Push Message至主執行緒的MQ中來與
    主執行緒溝通。
  • 透過MQ傳遞Message為非同步方式,呼叫者並不會因此而被
    Lock住,Message Push至MQ後函式會立即返回。
  • 子執行緒本身不具有Looper與MQ,落其他執行緒(如主執行緒)
    需要與子執行緒溝通時,必須先為子執行緒建立Looper與MQ物
    件。

 message
                    主執行緒                              message
           Looper   UI Thread         子執行緒   Looper
   MQ                                                  MQ




為你把關每一道 學習品質                    375                         375
Android Thread運作機制-Looper與MQ

   • UI(主)執行緒
         • UI Thread中所有的操作必須在5秒內回應,
           否則系統會因愈時而強制關閉應用程式。
         • 關於UI的操作只能在主執行緒(UI Thread)中處理,
           子執行緒中只能進行數據資料等其他非UI的操作。
         • 子執行緒若有需要做UI的控制,必須將需求傳送
           給主執行緒的MQ,在由主執行緒負責做UI的變更。
                                  主(UI)Thread
                     onClick(View V){
                        new Thread().start();
                     }                                       message
                     handlerMessage(Message msg){
File Text Data                                      Looper
                       textView.setText(“…”);
                     }                                        MQ
                                  子Thread
                     搜尋讀取檔案中的文字,並顯示於UI
                        textView.setText(“”);
   為你把關每一道 學習品質         handler.sendMessage(m);
                                   376                            376
Android Thread運作機制-Looper與MQ

• Handler物件
  • Handler是由Android框架所提供的類別,用來協助將
    Message物件送到MQ中。當Looper發現MQ中有
    Message,便會呼叫handleMessage方法進行處理。

  • Handler除了傳送Message物件外,也可以傳送實作
    Runnable的介面的物件到MQ上。

• Handler宣告方式
        Handler h = new Handler(){
                 @override
                 public void handleMessage(Message msg){
                           //處理message
                 }
        }


為你把關每一道 學習品質                      377                      377
Android Thread運作機制-Looper與MQ

• Handler建構與Callback方式(框架原始碼)
   public Handler(Looper looper, Callback callback) {
     mLooper = looper;
     mQueue = looper.mQueue;
     mCallback = callback;
   }
   public interface Callback {
     public boolean handleMessage(Message msg);
   }

   public void dispatchMessage(Message msg) {
     if (msg.callback != null) {
         handleCallback(msg);
     } else {
         if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
               return;
            }
         }
         handleMessage(msg);
     }}
為你把關每一道 學習品質                                    378     378
Android Thread運作機制-Looper與MQ


• 透過obtainMessage可取得Message物件
     • public final Message obtainMessage (int what, int arg1, int
       arg2, Object obj)

• 取得Message與傳送Message至MQ中
    Handler h = new Handler(){
             public void handleMessage(Message msg){
                       //處理message
             }
    }
    h.removeMessage(0);
    h.obtainMessage(1,1,1,”my message);
    h.sendMessage(m);




為你把關每一道 學習品質                         379                             379
Android Thread運作機制-Looper與MQ
                                            public static final void prepare() {
• 替子執行緒產生Looper與MQ if (sThreadLocal.get() != null) {
                                                 throw new RuntimeException(
Class subThread implements Runnable{             "Only one Looper may be created
  public void run(){                              per thread");
                                               }
    Looper.prepare();          框架原始碼
                                               sThreadLocal.set(new Looper());
                                             }
    h = new Handler(){
        public handlerMessage(Message msg){
            //處理message
        }
     };
                                            private Looper() {
    Looper.loop();             框架原始碼           mQueue = new MessageQueue();
                                               mRun = true;
  }                                            mThread = Thread.currentThread();
}                                           }


為你把關每一道 學習品質                              380                                      380
Android Thread運作機制-Looper與MQ

• 如何取得執行緒的Looper物件
    • Looper.myLooper () 可用來取得目前執行緒的Looper
    • Looper. getMainLooper() 可用來取得主執行緒的Looper
• 如何控制Handler所要接收的Looper?
  • 指定接收處理子執行緒Message
        Handler mHandler = new Handler(Looper.myLooper()){
                  public void handleMessage(Message msg){
                            //不可控制UI
                }
        };

    • 指定接收處理主執行緒Message(Current Thread)
     Handler mHandler = new Handler(Looper.getMainLooper()){
               public void handleMessage(Message msg){
                         //可控制UI
             }
     };
為你把關每一道 學習品質                          381                      381
範例練習
          範例專案名: ex09_01_LooperMQ

  練習目標:
   了解Android Thread的運作流程原理
   了解UI Thread的操作方式
   學習使用Handler操作
  程式撰寫
   建立Thread並指定給Looper與MQ,主執行緒透
    過Looper與MQ與子執行緒進行雙向溝通
  操作練習
   透過模擬器操作練習

為你把關每一道 學習品質            382         382
如何變更UI Thread內容

• 在Android中非UI Thread是不能直接去控制UI,一但違反此
條件,系統將會強制將應用程式結束。
• UI Thread應盡量保持暢通,User所有的操作處理皆必須在
五秒之內回應,若有超過5秒的處理需求,必須使用Thread將
其切割出去處理。
• 在Android子執行緒要進入UI Thread去變更UI內容,有以下
的四種方法
• 透過掛Handler Push Message/Runnable於UI Thread 處理UI內容
• 透過Activity.runOnUIThread(),直接指定進入UI Thread內處理
• 透過View.Post(Runnable)介面處理
• 透過AsncTask類別協助處理,此為Android官方建議的最佳方案,需
  1.5版後的Android才有支援。
為你把關每一道 學習品質               383                        383
如何變更UI Thread內容-使用Handler

• 透過Handler Push訊息至UI Thread
  • Handler.post(Runnable r);
  • Handler.postDelayed(Runnable r,
    long uptimeMillis)
  • Handler.sendMessage(Message msg);
  • Handler.sendMessageDelayed(Message msg,
    long delayMillis)

• Handler可Post Runnable介面
   • 在此指的Runnable介面與Thread無關,只是單純的
     CallBack Function.




為你把關每一道 學習品質             384                  384
如何變更UI Thread內容-使用Handler

Public void onClick(View V){                       Public class mainHandler extends
  switch(v.getId()){                               Handler{
    case 101:                                        public mainHandler() {
     Handler sh = new subHandler(mLooper);           super(Looper.getMainLooper());}
     Message m=sh.obtainMessage(1,33,1,null);        public void handleMessage(
     sh.sendMessage(m);                                          Message msg){
     break;                                            setTitle(" " +msg.arg1);
   }                                                 }
}                                                  }

Class myThread extends Thread{          Public class subHandler extends Handler{
  pubic void run(){                       public subHandler( Looper lp)
    Looper.prepare();                       { super(lp); }
    mLooper = Looper.myLooper();          public void handleMessage(Message msg){
    Looper.loop();                          value += msg.arg1;
  }                                         Handler ha = new mainHandler();
}                                           Message m =
                                            ha.obtainMessage(1,value,1,null)
                                            ha.sendMessage(m);
    為你把關每一道 學習品質
                                          }    385                                  385
                                        }
如何變更UI Thread內容-使用Activity.runOnUIThread

    使用Activity.runOnUIThread實作閃爍文字
   TimerTask taskcc = new TimerTask() {
          public void run() {
            runOnUiThread(new Runnable() {
                public void run() {
                    if (clo == 1) {
                         clo = 0;
                         touchScreen.setTextColor(Color.RED);
                      } else {
                         clo = 1;
                         touchScreen.setTextColor(Color.GREEN);
                      }
                  }
                }
            });
          }
       };
       //第二個參數代表的是delay, 第三個則是間隔多久
       timer.schedule(taskcc, 1, 300);
為你把關每一道 學習品質                                 386                  386
如何變更UI Thread內容-使用View.post

• public classView extends Object
   • public boolean post (Runnable action)
   • 此函式會將Runnable物件Push至main Thread的MQ中
   • Runnable的run method將會在UI Thread被呼叫執行
 public void onClick(View v) {
    new Thread(new Runnable() {
       public void run() {
          //子執行緒進行長時間的 io讀取圖片
          final Bitmap bmap = loadImageFromNetwork();
          mImageView.post(new Runnable() {
             public void run() {
               mImageView.setImageBitmap(bmap);
          }
      });
    }
 }).start();}

為你把關每一道 學習品質                              387           387
如何變更UI Thread內容-使用AsyncTask類別

• AsyncTask 為Google在Android 1.5所提供的類別。
• 使用AsyncTask必須使用繼承的方式,物件的必須在UI
  Thread中被建立,並且只能使用一次。
• 可用泛型指定Params,Progress,Result三個主要參數的型別
• AsyncTask可覆寫的方法
   • protected abstract Result doInBackground (Params...
     params)
   • protected final void publishProgress (Progress... values)
   • protected void onPostExecute (Result result)
   • protected void onPreExecute ()
   • protected void onProgressUpdate (Progress... values)


為你把關每一道 學習品質                    388                          388
如何變更UI Thread內容-使用AsyncTask類別

• AsyncTask 與框架之間的運作流程圖
 publishProgress(Progress... values)           onProgressUpdate(Progress... values)



 doInBackground(Params... params)                        onPostExecute(Result result)


                                                               onPreExecute()
                                 1
                                        Activity
                                                                Main Thread
           Work Thread          new AsyncTask().execute();       UI Thread



                                Android 框架層

為你把關每一道 學習品質                                 389                                        389
如何變更UI Thread內容-使用asyncTask類別

public void onClick(View v) {
  new DownloadFilesTask().execute(url1, url2, url3)
}
 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
   protected Long doInBackground(URL... urls) {
      int count = urls.length;
      long totalSize = 0;
      for (int i = 0; i < count; i++) {
         totalSize += Downloader.downloadFile(urls[i]);
         publishProgress((int) ((i / (float) count) * 100));
      }
      return totalSize;
   }
   protected void onProgressUpdate(Integer... progress) {
      setProgressPercent(progress[0]);
   }
   protected void onPostExecute(Long result) {
      showDialog("Downloaded " + result + " bytes");
   }
 }
為你把關每一道 學習品質                                390                            390
正確的Thread使用觀念
• AsyncTask 於API中提到的四個注意事項
  • The task instance must be created on the UI thread.
  • execute(Params…) must be invoked on the UI thread.
  • Do not call onPreExecute(),onPostExecute(Result),
    doInBackground(Params…), onProgressUpdate(Progress…)
    manually.
  • The task can be executed only once (an exception will be thrown
    if a second execution is attempted.)
• Thread並非萬靈丹
   • Thread並不能取代Services元件
   • 在背景的Activity隨時都有可能被系統Kill掉,但Thread
     可能還在繼續跑。
   • Thread適用於短時間,一次性處理函式。
   • 一般系統層級,需要長時間服務,與穩定性的,請使用
     Services元件來 (IntentServices)
為你把關每一道 學習品質                      391                                 391
範例練習
        範例專案名: ex09_02_AsyncTaskExample

    練習目標:
     設計一個AsyncTask,可以協助背景處理網路下載網路
      圖片。
    程式撰寫
     繼承AsyncTask類別,並覆寫底下的所有函式
     撰寫一個Activity,並新增一個Button與ImageView元
      件,點擊Button後會建立AsyncTask物件協助從網路
      上下載一張圖片,在下載過程中於UI Thread顯示進度
      完成後顯示於ImageView
    操作練習
     透過模擬器操作,練習時需連上Internet,並記得於
      androidManifest.xml中加入Internet的使用權限


為你把關每一道 學習品質              392               392
第11節: Android 系統元件應用
Android 系統元件應用

  Android系統元件應用
     感測器元件應用
     GPS定位元件應用
  網路元件應用
     Http Client




                    394
Android系統元件應用(GPS、感測器)

• Android GPS定位服務位於android.location套件中,定位
  服務元件為LocationManager。

• Android.location套件包含的類別
   • Criteria (依條件動態選擇最佳化定位資料源)
   • LocationManager類別 (定位服務)
   • LocationProvider類別 (定位的資料源)
   • LocationListener介面 (定期接收回報)
   • Location類別 (回報的定位資料封裝)




為你把關每一道 學習品質         395                    395
Android系統元件應用(GPS、感測器)

• Criteria (依條件動態選擇最佳化定位資料源)
   • Criteria建構方式
     Criteria criteria = new Criteria();


  • 設定定位精確度
    • Criteria. ACCURACY_FINE   精確
    • Criteria. ACCURACY_COARSE 模糊
     public void setAccuracy (int accuracy)

  • 是否提供高度資訊
     public void setAltitudeRequired (boolean altitudeRequired)

  • 是否提供方向資訊
     public void setBearingRequired (boolean bearingRequired)



為你把關每一道 學習品質                                  396                 396
Android系統元件應用(GPS、感測器)

• Criteria (依條件動態選擇最佳化定位資料源)
   • 是否允許使用付費的服務
    public void setCostAllowed (boolean costAllowed)


  • 限定電池的消耗量
    public void setPowerRequirement (int level)

    • Criteria. NO_REQUIREMENT 無
    • Criteria. POWER_LOW       低
    • Criteria.POWER_MEDIUM    中
    • Criteria. POWER_HIGH     高
  • 是否提供速度資訊
    public void setSpeedRequired (boolean speedRequired)


為你把關每一道 學習品質                                397            397
Android系統元件應用(GPS、感測器)

• LocationManager類別 (定位服務)
   • 取得LocationManagement元件
   /*於Activity中呼叫*/
   LocationManager lg=getSystemServices(Context.LOCATION_SERVICE);



  • 取得最佳的LocationProvier元件
    public String getBestProvider (Criteria criteria, boolean enabledOnly)




  • 取得最後己知的GPS位址
    public Location getLastKnownLocation (String provider)




為你把關每一道 學習品質                                  398                            398
Android系統元件應用(GPS、感測器)

• LocationManager類別 (定位服務)
   • 依取得週期性回報GPS坐標
     public void requestLocationUpdates (long minTime, float
     minDistance, Criteria criteria, LocationListener listener, Looper looper)

    • miniTime:最小回報間隔時間(毫秒)

    • miniDistance:最小回報距離間隔(公尺)

    • criteria:自動挑選最適當的Location Provider

    • Listener:接收回報座標資料的介面

    • Looper:決定回報的函式要跑的Thread,若指定
        null,則回報函式將跑在main Thread上。
為你把關每一道 學習品質                                 399                                 399
Android系統元件應用(GPS、感測器)

• LocationManager類別 (定位服務)
   • 只要求提供一次GPS座標回報
public void requestSingleUpdate (Criteria criteria, LocationListener listener, Looper looper)


         • criteria:自動挑選最適當的Location Provider

         • Listener:接收回報座標資料的介面

         • Looper:決定回報的函式要跑的Thread,若指定
             null,則回報函式將跑在main Thread上。




為你把關每一道 學習品質                                       400                                          400
Android系統元件應用(GPS、感測器)

• LocationProvider類別 (定位的資料源)
   • 抽像類別,無法自行以new建構,一般透過Criteria
     類別來協助做最佳化的provider選擇。

• LocationListener介面 (定期接收回報)
   • 一組抽像的介面,用來接收來自LocationManager
     的通知回報。此介面實作後需被註冊至
     requestLocationUpdates(…);

  • 當服務被關閉
    public abstract void onProviderDisabled (String provider)




為你把關每一道 學習品質                                401                 401
Android系統元件應用(GPS、感測器)

• LocationListener介面 (定期接收回報)
   • 當座標變更
    public abstract void onLocationChanged (Location location)


                   函式                                            功能
   location.getLatitude()                    取得緯度

   location.getlongitude()                   取得經度

   location.getAltitude()                    取得高度

   location.getAccuracy()                    取得精確度

   location.getTime()                        取得時間

   location.getSpeed()                       取得速度

   location.getBearing()                     取得方向

為你把關每一道 學習品質                                 402                      402
Android系統元件應用(GPS、感測器)

• LocationListener介面 (定期接收回報)
   • 當服務被打開
    public abstract void onProviderEnabled (String provider)


  • 當服服狀態改變(如無法提供服務,或己回複服務)
   public abstract void onStatusChanged (String provider, int status, Bundle extras)

     • AVAILABLE
     • OUT_OF_SERVICE
     • TEMPORARILY_UNAVAILABLE




為你把關每一道 學習品質                                  403                                      403
範例練習
         範例專案名: ex10_01_GPS定位服務

  練習目標:
   了解GPS定位服務的使用方式
   了解如何設定自動最佳化的定位回報
  程式撰寫
   取得LocationManager元件
   設置GPS Provider選擇條件,並依最佳化原則自
    動選用
   實作LocationListener 介面
   向LocationManager註冊LocationListener
   依回報座標所取得的資料,顯示於UI上
為你把關每一道 學習品質                             404
Sensor感測器使用
• Android提供了許多Sensor的支援,不同的手機所支援的
  Sensor H/W會有所不同。
    TYPE_ACCELEROMETER         加速度測器
    TYPE_AMBIENT_TEMPERATURE   環境溫度感測器
    TYPE_GRAVITY               重力感測器
    TYPE_GYROSCOPE             陀螺儀感測器
    TYPE_LIGHT                 亮度感測器
    TYPE_LINEAR_ACCELERATION   線性加速感測器
    TYPE_MAGNETIC_FIELD        磁場感測器
    TYPE_ORIENTATION           方位感測器
    TYPE_PRESSURE              壓力感測器
    TYPE_PROXIMITY             接近感測器
    TYPE_RELATIVE_HUMIDITY     濕度感測器
    TYPE_ROTATION_VECTOR       旋轉向量感測器
    TYPE_TEMPERATURE           溫度感測器



為你把關每一道 學習品質                    405      405
Sensor感測器使用
• 感測器的資料欄位
  • 加速感測器 TYPE_ACCELEROMETER
    • values[0]:Gx
    • values[1]:Gy
    • values[2]:Gz Z軸


               Y軸
                          X軸




為你把關每一道 學習品質        406        406
Sensor感測器使用
• 感測器的資料欄位
  • 磁場感應器 TYPE_MAGNETIC_FIELD
    • values[0]:x軸
    • values[1]:y軸
    • values[2]:z軸
  • 方向感測器 TYPE_ORIENTATION
    • values[0]:依Z軸旋轉與Y軸的夾角大小(度)
    • values[1]:依X軸旋轉與Z軸的夾角大小(度)
    • values[2]:依Y軸旋轉與Z軸的夾角大小(度)
                    Z
                    軸
               Y軸       X軸




為你把關每一道 學習品質                       407
Sensor感測器使用
• 感測器的資料欄位
  • 溫度感測器 TYPE_TEMPERATURE
    • values[0]:溫度
    • values[1]:無作用
    • values[2]:無作用




為你把關每一道 學習品質                 408
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);



  Sensor感測器使用
    • 感測器API的使用操作流程
      • 取得SensorManager系統服務元件
           SensorManager manager=(SensorManager)getSystemServices(SENSER_SERVICE);


          • 實作SensorEventListener以取得感測器回報資料
            • 當感測器精確度發生變化時呼叫
                   public abstract void onAccuracyChanged (int sensor, int accuracy)


                • 當感測器資料有變化時呼叫
                   public abstract void onSensorChanged (int sensor, float[] values)


          • 決定要使用的感測器種類
                mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

    為你把關每一道 學習品質                                           409                             409
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);



  Sensor感測器使用
    • 感測器API的使用操作流程
      • 註冊Sensor監聽事件
           public boolean registerListener (SensorEventListener listener, Sensor sensor, int rate)


                • listener: 監聽的事件介面
                • sensor: 要監聽的sensor
                • rate: 延遲時間的精確度
                                     rate 常數                                     延遲時間長度
          SensorManager. SENSOR_DELAY_FASTEST                                  0ms
          SensorManager. SENSOR_DELAY_GAME                                     20ms
          SensorManager. SENSOR_DELAY_UI                                       60ms
          SensorManager. SENSOR_DELAY_NORMAL                                   200ms



    為你把關每一道 學習品質                                           410                                       410
範例練習
            範例專案名: ex10_02_Sensor

  練習目標:
   了解Sensor感測器的設定與取得資料的方式
   了解不同感測器所代表的資料函義
  程式撰寫
     取得SensorManager元件
     實作SensorEventListener介面
     決定Sensor型態
     註冊監聽的Sensor
     取得回報的資料並顯示於UI上

為你把關每一道 學習品質                        411
Http client介紹
• GET 方法的實作範例
  /*建立HttpClient物件*/
  httpClient = new DefaultHttpClient();
  UsernamePasswordCredentials creds = new
  UsernamePasswordCredentials(userName, password);
  httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);

  /* 建立HTTP Get連線 */
  HttpGet httpRequest = new HttpGet("http://url");

  /* 發出HTTP request */
  HttpResponse httpResponse = httpClient.execute(httpRequest);

  /* 確認response是否ok,狀態碼為200 ,並取得資料*/
  if (httpResponse.getStatusLine().getStatusCode() == 200) {
            return httpResponse.getEntity().getContent();
  }


為你把關每一道 學習品質                             412                                  412
Http client介紹
• POST 方法介紹
  • POST方法用來向目的服務器發出請求,要求它接受被
    附在請求後的物件。
  • 呼叫HttpClient中的HttpPost與HttpGet類似,除了設置
    HttpPost的物件與HttpGet有些不同之外,剩下的步驟
    都差不多

• POST實作功能:
  • 向留言版或類似討論組發送訊息
  • 提交數據資料,如將HTML表單的結果提交給Server
  • 透過附加操作來擴展資料庫內容



為你把關每一道 學習品質         413                413
Http client介紹
• Post建置流程:
  • 建立HttpClient 的物件
  • 依照連接方式建立連接物件(HttpPost)。在構造函數中傳入待連接
    的URL位址。
  • 利用NameValuePair類別來建立參數表單,該類別的建構式第一個
    參數是參數名稱,第二參數是該參數的值
  • 呼叫HttpPost的setEntity函式,將參數表單(NameValuePair)附加
    上去。
  • 呼叫第一步中創建好的HttpClient物件的execute 方法,並帶入第
    二步中建立的HttpPost或HttpGet物件,以發送需求至Server端。
  • HttpClient.execute會回傳HttpResponse物件,可用來判斷是否傳
    送成功。




為你把關每一道 學習品質            414                     414
Http client介紹
• Post方法的實作範例:
/*建立HttpClient物件*/
/* 建立HTTP PhttpClient = new DefaultHttpClient();
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, password);
httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
ost連線 */
HttpPost httpRequest = new HttpPost("http://url");
/* 建立NameValuePair[]陣列儲存傳送參數*/
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("Name", "Value"));
/* 將參數加載於HttpPost物件中 */
httpRequest.setEntity(new UrlEncodedFormEntity(params,
HTTP.UTF_8));
/* 發出HTTP request */
HttpResponse httpResponse = httpClient.execute(httpRequest);
/* 確認response是否ok,狀態碼為200 ,並取得資料*/
if (httpResponse.getStatusLine().getStatusCode() == 200) {
           return httpResponse.getEntity().getContent();
}


為你把關每一道 學習品質                                  415                                      415
Android應用程式設計

• 透過HttpClient取得BmipImage
  public Bitmap getURLBitmap(URL imageUrl , ) {
         URL imageUrl = null;
         Bitmap bitmap = null;
         try {
                imageUrl = new URL("http://" + ipAddress + cgiImageCommand);
         } catch (MalformedURLException e) {
                e.printStackTrace();
         }
         try {
                HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
                conn.setRequestMethod("GET");
                conn.setDoInput(true);
                conn.setRequestProperty("Authorization", "Basic "+
                Base64Coder.encodeString(userName + ":" + password));
                conn.connect();
                InputStream is = conn.getInputStream();
                bitmap = BitmapFactory.decodeStream(is);
                is.close();
         } catch (IOException e) {
                e.printStackTrace();
         }
         return bitmap;
  }
為你把關每一道 學習品質                                      416                                     416
Http client介紹
• Http Cliet常見編碼問題:
  • Post Entity時需指定編碼格式為HTTP.UTF_8,因為預
    設的編碼格式為ISO-8859-1在處理中文時會有亂碼狀況。
    post.setEntity(new UrlEncodedFormEntity(nvps,
    HTTP.UTF_8));
  • 接收response 資料時使用EntityUtils.toString()來進行
    轉串轉換,該函式會依照Server回傳的header 資料來
    判判需使用何種解碼類型。
    String str = EntityUtils.toString(rp.getEntity());




為你把關每一道 學習品質              417                      417
範例練習
           範例專案名: ex10_03 DroidCam

  練習目標:
   了解如何使用HttpClient存取網路資料
   了解如何使用HttpClient與Servier進行認證動作
  程式撰寫
   透過HttpClient與IPCam進行連線登入
   透過Http Get取得圖片
   透過Http Post發送控制指令




為你把關每一道 學習品質             418         418
Android應用程式設計

• IPCam Viewer   工作流程
  • 建立新增編輯IPCam Viewer的Activity頁面
  • 建立觀看IPcam Viwer的Activity頁面
  • 撰寫AsyncTask類別,協助處理下載IPcam影像圖片的
    工作
  • 撰寫AsyncTask類別協助處理IPcam PT控制指令
  • 整合頁面操作流程(開機進入Viewer頁面,透過Menu
    新增Ipcam)
  • 撰寫程式邏輯,透過httpclient與ipcam進行連接,收送
    ipcam cgi command。




為你把關每一道 學習品質        419                419
Android遊戲設計
• 播放影像程式流程架構圖
 將bitmapImage顯示於ImaveView                         連至IPcam下載圖片更新

 onProgressUpdate(Bitmap bitmap)               publishProgress(Progress... values)



                                              doInBackground(Params... params)

                                                               Httclient連線
                                                       onPreExecute()



                                   onDraw()
            Activity                                    AsyncTask

為你把關每一道 學習品質                            420                                      420
Android遊戲設計
• 控制IPCam的流程架構

傳送控制PT 的CGI Command

  onPostExecute(Result result)              doInBackground(Params... params)

                                                            Httclient連線
                                                     onPreExecute()



                                 Excute()
            Activity                                 AsyncTask




為你把關每一道 學習品質                          421                                      421
Http Client介紹
• Http Client主要提供的功能
  •   實現了所有HTTP 的方法(GET,POST,PUT,HEAD )
  •   支持自動轉向
  •   支持HTTPS 協議
  •   支持代理服務器等

• GET 方法的實作流程
  • 建立HttpClient 的物件
  • 依照連接方式建立連接物件(HttpGet)。 在構造函數中傳入待連接
    的URL位址。
  • 呼叫第一步中創建好的HttpClient物件的execute 方法,並帶入第
    二步中建立的HttpPost或HttpGet物件,以發送需求至Server端。
  • HttpClient.execute會回傳HttpResponse物件,可用來判斷是否傳
    送成功。
  • 對得到後的內容進行處理

為你把關每一道 學習品質             422                   422
第12節:多媒體元件應用
Android 系統元件應用

  Android多媒體元件
     Camera元件應用
     MediaPlay元件應用
     VideoView元件應用
     相片瀏覽與多點縮放實作




                      424
多媒體元件-Camera元件應用

• 使用Android相機功能主要由以下三個功能所組成
   • 預覽
   • 對焦
   • 取得相片
• Camera預覽
   • 利用android.hardware.Camera設定相機參數
   • 以SurfaceView做為相機的preview繪圖區塊
     • 需注意SurfaceView 不會直接處理 Surface 物件,
       必須經過 SurfaceHolder 處理。
   • 透過Camera.open()開啟camera並取得camer物件.



為你把關每一道 學習品質         425                   425
多媒體元件-Camera元件應用

• 初始化SurfaceView
  private SurfaceHolder surfaceHolder;
  private SurfaceView surfacePreview;
  /* 取得SurfaceView元件實體物件 */
  surfacePreview = (SurfaceView) findViewById(R.id.surfacePreview);
  /*取得surfaceHolder物件*/
  surfaceHolder = surfacePreview.getHolder();
  /* 註冊Surface.Callback函式實作 */
  surfaceHolder.addCallback(this);
  /* 代表此surface不包含資料,資料將透過其它物件提供(Camera),在預覽較為流暢 */
  surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);




為你把關每一道 學習品質                              426                         426
多媒體元件-Camera元件應用

• 實作SurfaceHolder.Callback介面
  /* 當Surface大小發生改變時被呼叫 */
  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width,int height);

  /*Surface建立成功後會呼叫,在此進行Camera的初始化*/
  @Override
  public void surfaceCreated(SurfaceHolder holder)

  /* SurfaceView元件被銷毀前進行資源的釋放回收 */
  @Override
  public void surfaceDestroyed(SurfaceHolder holder)




為你把關每一道 學習品質                                 427                                        427
多媒體元件-Camera元件應用

• 開啟相機,並設定相機相關參數
  /* 利用camera的靜態方法open取得camera物件 */
  camera = Camera.open();
  /* 取得Camera的設定參數物件 */
  Camera.Parameters cameraParameters = camera.getParameters();
  /* 照片的格式 */
  cameraParameters.setPictureFormat(PixelFormat.JPEG);
  /* 設置為可自動對焦,只有在相機開啟時對一次焦 */
  cameraParameters.setFocusMode("auto");
  /* 將新的參數質設定到Camera物件中 */
  camera.setParameters(cameraParameters);
  /* 調整鏡頭的方向*/
  camera.setDisplayOrientation(90);




為你把關每一道 學習品質                                      428            428
多媒體元件-Camera元件應用

• 進行相機畫面預覽

  camera.setPreviewDisplay(surfaceHolder);
  /* 開始預覽 */
  camera.startPreview();



• 實作AutoFocusCallback (對焦成功時呼叫)
  /* 對焦Call back函式實作 */
  autoFocusCallBack = new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean paramBoolean, Camera paramCamera) {
              /* 如果對到焦了 */
              if (paramBoolean) {
                     /* 拍照 */
                     tackPicture();
              }
        }
  };
為你把關每一道 學習品質                                    429                           429
多媒體元件-Camera元件應用

• 實作PictureCallback介面 (照相完成後由系統呼叫)
  /* JPEG格式相片,call back實作 */
  private PictureCallback jpegPicturecallBack = new PictureCallback() {
        @Override
        public void onPictureTaken(byte[] paramArrayOfByte,
        Camera paramCamera) {
              Bitmap bm = BitmapFactory.decodeByteArray(paramArrayOfByte, 0,
              paramArrayOfByte.length);
              try {
                    /* 建立IO串流 */
                    BufferedOutputStream bufferOutPut = new BufferedOutputStream(
                    new FileOutputStream(PICTURE_SAVE_DIR));
                    /* 壓縮並儲存圖檔,壓縮轉檔 */
                    bm.compress(Bitmap.CompressFormat.JPEG, 80, bufferOutPut);
                    bufferOutPut.flush();
                    bufferOutPut.close();
              } catch (FileNotFoundException e) {
                    e.printStackTrace();
              } catch (IOException e) {
                    e.printStackTrace();
              }
        }
  };
為你把關每一道 學習品質                          430                                           430
多媒體元件-Camera元件應用

• 呼叫拍照功能
  camera.takePicture(shutterCallBack, rawPictureCallBack,jpegPicturecallBack);



• 呼叫對焦功能
  camera.autoFocus(autoFocusCallBack);




為你把關每一道 學習品質                          431                                        431
範例練習
           範例專案名: ex011_01_Camera

  練習目標:
   學習如何建立使用Camera元件進行預覽
    、對焦、照相
  程式撰寫
     了解如何取得與使用camera物物進行相機參數設定。
     了解如何建置SurfaceView進行快進繪圖,並做為相機預覽
      繪圖區
     了解如何使用AutoFocusCallback來進行對焦。




為你把關每一道 學習品質        432                 432
多媒體元件-VideoView

• Android提供了VideoView元件,透過它可以播放許多不同
  格式的影片

• 於Layout XML中定義VideoView元件




為你把關每一道 學習品質         433              433
多媒體元件-VideoView

• 指定來源的影片URI
  • 來至網路
       Uri mUri = Uri.parse(editTextRtspUrl.getText().toString())

   • 來至SD卡
       Uri mUri=Uri.parse(Environment.getExternalStorageDirectory()+ "/xxxx.3gp");

   • 來至系統索引的多媒體資料庫
 Cursor cursor = this.getContentResolver().query(
 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null, null,null);
 cursor.moveToFirst();
 int videoID = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.VideoColumns._ID));
 Uri playVideo = Uri.withAppendedPath(
 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, String
 .valueOf(videoID));
為你把關每一道 學習品質                                        434                                   434
多媒體元件-VideoView

• 開始播放影片
  private void playVideo(Uri uri) {
        /* 設定VideoView的來源片位址 */
        videoView.setVideoURI(uri);
        /* 設定控制器掛載在Activity上 */
        videoView.setMediaController(new MediaController(this));
        /* 開始播放 */
        videoView.start();
  }

• 取得播放開始事件
  videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
       @Override
       public void onPrepared(MediaPlayer mp) {

        }
  });



為你把關每一道 學習品質                                 435                           435
多媒體元件-VideoView

• 取得播放結束事件
  videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
       @Override
       public void onCompletion(MediaPlayer mp) {

        }
  });




為你把關每一道 學習品質                               436                                 436
範例練習
           範例專案名: ex011_02_VideoView

  練習目標:
   學習如何建立使用VideoView元件進行影片播放
   學習如何在VideoView上播放不同資料來源的影
    片(網路、SD卡、系統資料庫索引的資料)
  程式撰寫
     於Layout中放置VideoView元件。
     指定URI影片資料來源
     設置MediaController控制器
   註冊監聽以得知影片開始與播放完畢事件


為你把關每一道 學習品質         437               437
多媒體元件-MediaPlayer元件

• MediaPlayer元件同時提供了Video與Audio解碼功能,許
  多Android高階的多媒體元件(如VideoView)其底層皆是使
  用MediaPlayer。

• Android MediaPlayer元件在2.0以前使用的是OpenCORE
  多媒體框架,但由於其架構系統過於龐大複雜,因此在
  2.0之開始改以架構較簡潔的Stagefright取代之。

• 相較於高階的元件(如VideoView),使用MediaPlayer元件
  將可以有較高的自由控制性,MediaPlayer提供了許多的
  事件,包含播放、停止、暫停、重置、指定影片大小.等
  功能。

為你把關每一道 學習品質         438                    438
多媒體元件-MediaPlayer元件

• MediaPlayer的建構方式
  • 利用靜態create函式建構
   public static MediaPlayer create (Context context, Uri uri)
   public static MediaPlayer create (Context context, int resid)
   public static MediaPlayer create (Context context, Uri uri, SurfaceHolder holder)

  • 透過new建構
   MediaPlayer mediaPlayer = new MediaPlayer();



   public void setDataSource (String path)
   public void setDataSource (FileDescriptor fd, long offset, long length)
   public void setDataSource (FileDescriptor fd)
   public void setDataSource (Context context, Uri uri)



為你把關每一道 學習品質                                    439                                    439
多媒體元件-MediaPlayer元件

• MediaPlayer播放控制流程
                               prepare()
  setDataSource()                                      start()      pause()
                            prepareAsync()



                               reset()                stop()


• MediaPlayer的Video畫面顯示
  /* 設定SufaceView Callback介面 */
  surfaceHolder = surfaceView.getHolder();
  surfaceHolder.addCallback(this);
  surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  /* 設定mediaplayer參數 */
  mediaPlayer = new MediaPlayer();
  mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  mediaPlayer.setDisplay(surfaceHolder);
為你把關每一道 學習品質                              440                                 440
多媒體元件-MediaPlayer元件

• MediaPlayer的監聽事件
  • OnCompletionListener
  • OnPrepareListener
  • OnErrorListener
  • OnBufferingUpdateListener
  • OnInfoListener
  • OnVideoSizeChangedListener
  • OnSeekCompleteListener
• 播放進度的取得
   /*取得總長度*/
   mediaPlayer.getDuration();
   /*取得目前播放的長度*/
   mediaPlayer.getCurrentPosition();

為你把關每一道 學習品質                           441   441
範例練習
          範例專案名: ex11_03_MediaPlayer


   練習目標:
    學習如何建立使用MediaPlayer元件進行影片播放
    學習如何自行設置MediaControl元件
    學習如何自行設置播放進度條
   程式撰寫
    設置Layout xml檔,自行定義播放控制元件與顯示元
     件
    設置Mediplayer所要播放的影片來源
    播放影片控制
    設置Thread進行播放進度更新.


為你把關每一道 學習品質             442           442
相片瀏覽器

• 相片瀏覽器基本功能需求
  • 可支援多點觸控縮放
  • 放大後可以移動圖片觀看局部部位
  • 具等比例放大縮小圖片功能
  • 具單點圖片二下自動進行局部放大或縮小
• 實作方式
  • 使用WebView方式實作
  • 使用ImageView方式實作




為你把關每一道 學習品質   443       443
相片瀏覽器

• 繼承ImageView元件,撰寫一隻具有touch與縮放功能的
  ImageViewTouch元件

• 於XML Layout中放置ImageViewTouch元件
  <?xml version="1.0" encoding="utf-8"?>
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <it.sephiroth.android.library.imagezoom.ImageViewTouch
  android:id="@+id/imageView1"
  android:scaleType="fitCenter"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />
  </LinearLayout>


為你把關每一道 學習品質                                444                              444
相片瀏覽器

• 於Activity中透過findViewbyID取得ImageViewTouch物件
  參照
  ImageViewTouch mImageView = (ImageViewTouch)findViewById( R.id.imageView1 );



• 設置要覽瀏的相片資料,(Bitmap物件)
  mImageView.setImageBitmapReset( bitmap, orientation, true );




為你把關每一道 學習品質                                445                                  445
範例練習
               範例專案名: ex11_04_


   練習目標:
      學習如何建立使用相片瀏覽元件
      支援多點縮放
      支援單點縮放
      支援拖拉移動
      自動置中與等比例縮放




為你把關每一道 學習品質            446      446
第13節:Google API套件應用
Google API套件應用

  Gppgle Map API Key申請
  Google Map 應用程式開發
  如何為APP簽署憑證
  如何申請成為Google開發者




                     448
如何使用Google MAP
• Google MAP API為一個獨立的add-on API,並沒
  有直接被包含在Android Platform中.

• 該API中主要由MapView與MapController組合而成,而由
  於MapView會取得私人的地圖位置,因此在使用時需先於
  Google上註冊取得APIKey才得以顯示出地圖畫面。




為你把關每一道 學習品質       449                   449
申請Google Map API Key.
• 要使用GoogleMaps必須先與Google申請一組經驗
  證的API Key.一組Key可以同時應用在多個應用程
  式。
• Step 1: 找到模擬器的金鑰 debug.keystore
  C:Documents and SettingsYour_PC_Name.android debug.keystore


           喜好設定AndroidBuild




• Step2: 利用keytool產生keystore與MD5編碼
  keytool -list -alias androiddebugkey -keystore "C:Documents and
  SettingsYour_PC_Name.androiddebug.keystore" -storepass android -
    keypass android



為你把關每一道 學習品質                            450                             450
申請Google Map API Key.
• Step3: 利用MD5取得Google API 金鑰
  http://code.google.com/intl/zh-TW/android/maps-api-signup.html




  輸入MD5編碼: 1C:6B:27:C8:B6:42:5B:BF:0C:DD:xx:xx:xx:xx:xx:xx



為你把關每一道 學習品質                           451                         451
申請Google Map API Key.
• Step4: 登入google 帳號後取得API金鑰




為你把關每一道 學習品質       452         452
申請Google Map API Key.
• Step5: 建立Google Map Android專案

  • Step1 首先需要要先建立一個含Google Map API的模擬器



                                    2.




                                     3.
           1.



為你把關每一道 學習品質          453                 453
申請Google Map API Key.
  • Step2 建立新專案使用Google API Target



                    AndroidMap




                    選擇Android API Target


                    AndroidMap
                    com.ittraining.gmap
                    AndroidMap
                    7


為你把關每一道 學習品質            454                454
申請Google Map API Key.
  • Step3 修改Activity,改繼承至MapActivity

                                    2.


                                   1.




                              3.




為你把關每一道 學習品質           455               455
申請Google Map API Key.
  • Step4 修改AndroidManfest.xml 滙入套件與開放權限

                                    2.        4.




                    3.

   1.


                                         2.
                                                   4.


                         3.

               1.
為你把關每一道 學習品質                  456                       456
申請Google Map API Key.
  • Step5 加入MapView元件於main.xml layout中




為你把關每一道 學習品質
                      457                457
申請Google Map API Key.
  • Step7 執行測試




為你把關每一道 學習品質       458   458
Google Map API應用

 • 利用GPS座標取得地址

 private String getLocationAddress(GeoPoint point){
    String add = "";
    Geocoder geoCoder = new Geocoder(getBaseContext(),Locale.getDefault());
    try {
       List<Address> addresses = geoCoder.getFromLocation(
            point.getLatitudeE6() / 1E6, point.getLongitudeE6() / 1E6, 1);
       Address address = addresses.get(0);
       int maxLine = address.getMaxAddressLineIndex();
       if(maxLine >= 2){
          add = address.getAddressLine(1) + address.getAddressLine(2);
       }else { add = address.getAddressLine(1);     }
    } catch (IOException e) {
       e.printStackTrace();
    }
    return add;
 }
為你把關每一道 學習品質                            459                                   459
範例練習
          範例專案名: ex12_01 GoogleMap

  練習目標:
   了解如何使用使用GoogleMap API
   學習如何使將圖層繪製在Google Map地圖上
  程式撰寫
   設計Layout XML,使用GoogleMapView元件.
   取得loactionGPS服務,並註冊定期接收定位回
    報資料。
   實作ItemizedOverlay介面,並新增OverlayIte於
    MAP中


為你把關每一道 學習品質            460              460
申請成為Android開發人員

 • Step 01:
   進入Android Developer網站,並點擊右側Publish底下的
   Learn more連結。




為你把關每一道 學習品質         461                   461
申請成為Android開發人員

 • Step 02:
   利用Google 帳號登入,並填寫個人資料




為你把關每一道 學習品質     462       462
申請成為Android開發人員

 • Step 03:
   註冊費用為25美金,並提供Google Checkout付費方式。
   請點繼續進鈕進入付費流程




為你把關每一道 學習品質      463              463
申請成為Android開發人員

 • Step 04:
   確認帳單資料,並再次輸入Google密碼登入




為你把關每一道 學習品質    464         464
申請成為Android開發人員

 • Step 05:
   新增信用卡付款,輸入卡號與個人資料,完成付款流程。




為你把關每一道 學習品質   465         465
申請成為Android開發人員

 • Step 06:
   確認付款完成,點選Andorid Market開發人員網站,以完
   成註冊手續。。




為你把關每一道 學習品質      466             466
申請成為Android開發人員

 • Step 07:
   同發人員協議書確認,請扣選同意,並點選繼續鈕。




為你把關每一道 學習品質   467           467
申請成為Android開發人員

 • Step 08:
   完成註冊,點選上傳應用程式,開始上傳你的APP軟體。




為你把關每一道 學習品質   468          468
申請成為Android開發人員

 • Step 09:
   上傳發布應用程:




為你把關每一道 學習品質   469   469
申請成為Android開發人員




為你把關每一道 學習品質   470   470
申請成為Android開發人員




為你把關每一道 學習品質   471   471
如何為APP申簽署憑證
• Step 1: 利用keytool產生憑證檔
 keytool -genkey -v -keystore JareyMobile.keystore -alias JareyMobile -keyalg RSA -
 validity 10000




為你把關每一道 學習品質                                472                                       472
如何為APP申簽署憑證
• Step 2:
  於Eclipse中選擇要簽署憑證的專案,於功能選單
  中執行Export Signed Application Package.




為你把關每一道 學習品質        473                   473
如何為APP申簽署憑證
• Step 3:
  確認專案名稱,並指定keystore檔檔路徑與密碼




為你把關每一道 學習品質   474            474
如何為APP申簽署憑證
• Step 4:
  選擇Key Alias名稱並輸入密碼。最後指定滙出的
  具有簽署憑證的APK檔路徑。




為你把關每一道 學習品質   475             475
第14節: Android UI設計模式
    第三方套件應用
Google API套件應用

  Gppgle Map API Key申請
  Google Map 應用程式開發
  如何為APP簽署憑證
  如何申請成為Google開發者




                     477
Android 專案設計方向

• 手機受限於螢布大小限制,不如PC般適合透過Browser頁
  面來存取吸收豐富的網路資源。
• 手機應用程式主要的工作就是在於重新收集整理網路上的
  資料,並在重新排版成適合手機操作與瀏覽的介面。
• 手機應用程式的組成結構
   • 經組織整理過的Content資料內容
   • Internet Services
   • 良好的使用者介面
• Content
   • 一個好的應用程式,Content可以說是很重要的關鍵,
     由於一般的網路資訊是過於雜亂的,用戶透過手機必
     須要經過很多道關卡步聚才能取得想要的資訊。因此
     將Content重新組織整理將可以提供更穩定與有價質的
     資訊給手機用戶。
為你把關每一道 學習品質     478               478
Android 專案設計方向

• Internet Services
   • 網路是手機與外界溝通最佳的管道,而目前網路資訊
      最豐富的莫過於www,透過http可以取得網路上各式
      各樣的資訊與資料,但要手機同時對外去與那麼多的
      services做連線與存取資料,其穩定性與效能是有問題
      的。因此一般需要自己建立一個雲端的Services來提
      供單一有效率的連線服務。而自建的services在與自己
      整理的content資料做連接。
• 使用介面
   • 手機的操作介面與一般的應用程式設計不同,良好的
      操作介面將有助於使用者更方便快速的取得所要的資
      訊。手機的操作介面將盡量保持與Android系統相近的
      操作風格,這將有助於減少用戶重新學習與猜惻新UI
      的使用方式。

為你把關每一道 學習品質      479                479
Android 專案設計方向

• 設計實用的應用程式的思考方向
  • 原始資料來源是否雜亂且沒有標準?
  • 是否能為資料重新整理出一套新標準?
  • 是不需要使用到雲端伺服器?
  • 是否需要使用到大量資料的Query與分析?
  • 是否為生常生活中經常需要使用到的應用?




為你把關每一道 學習品質     480        480
Android 專案設計方向

• 手機應用程式基本開發步驟
  • 功能定義
  • UI介面設計
  • 資料操作和儲存結構
  • UI頁面切換流程動線規劃
  • 程式架構設計規劃
  • 考量是否需要Services與APPWidget應用程式
  • 後端Server應用程式建置
  • 完成程式細節功能調整
  • 測試與驗證程式
  • 發布到Android Market


為你把關每一道 學習品質       481             481
Android的UI設計模式

• Android UI Design Pattern
   • 為Google在2010的GoogleIO中所提出的概念
• Android UI設計的原則
   • Clear vs.“simple”
   • Content vs. chrome
   • Consistent yet engaging (elegant variation)
   • Enhanced by cloud
• 5種UI Pattern
   • Dashboard
   • Action Bar
   • Search Bar
   • Quick Actions
   • Companion Widget
為你把關每一道 學習品質                 482                   482
Android的UI設計模式


• Dashboard
   • A quick intro to an app, revealing capabilities and
     proactively highlighting new content
   • Full-screen
   • Can be organized by:
      • Features
      • Categories
      • Accounts
   • Recommendations
      • DO highlight what’s new
      • DO focus on 3-6 most important choices
      • DO be flavorful

                                    483                    483
Android的UI設計模式
• Action Bar
   • Dedicated real estate at top of the screen to support navigation and
     frequently used operations
   • Replaces title bar
   • Best for actions common across your app
      • Search
      • Refresh
      • Compose (new)
   • Can provide a quick link back to dashboard
     (or other app home)
• Recommendations
   •   DO use to bring key actions onscreen
   •   DO help to convey a sense of place
   •   DO use consistently within your app
   •   DON’T use for contextual actions

                                       484
Android的UI設計模式

• Quick Actions
   •   Action popup triggered from distinct visual target
   •   Minimally disruptive to screen context
   •   Actions are straightforward
   •   Fast & fun
• Recommendations
   • DO use when items have competing internal
     targets
   • DO present only the for most important and
     obvious actions
   • DO use when the item doesn’t have a meaningful
     detail view
   • DON’T use in contexts which support multiple
     selection


                                         485                485
Android的UI設計模式
• Search Bar
   • Consistent pop-in search form anchored to top of
     screen
   • Replaces action bar (if present)
   • Support suggestions
   • Can use corpora selector to alter search mode
     Alternately, can offer suggestions for primary
     search mode,and additional items for triggering
     other modes
• Recommendations
   • DO use for simple searches
   • DO present rich suggestions
   • DO use the same behavior




                                       486
Android的UI設計模式

• Companion Widget
   • Supports the app by displaying its content and   capabilities on the
     Home screen
   • Makes Home feel more custom, personalized
• Recommendations
   • DO provide value above a simple app icon (content)
   • DON’TDO handoff to the full app for real tasks
   • DO be space efficient
   • just provide a larger app launcher




                                       487                                  487
Android的UI設計模式


• 完整的應用程式UI流程圖




• Android UI Desgin Pattern的線上學習網站
   • http://www.androidpatterns.com/
                          488          488
Android的UI設計模式
• 線上資源參考
• Iconfinder :Icon 圖檔搜尋引擎
   • http://www.iconfinder.com/
• Android UI Desgin Pattern的線上學習網站
   • http://www.androidpatterns.com/
• balsamiq mockups:UI模式設計器
   • http://www.balsamiq.com/
• 大予創意部落格:GUI多媒體互動設計
   • http://aja-creative.blogspot.com/
• UIPatterns:專業UI配色與模版設計
   • http://ui-patterns.com/explore



                           489           489
第三方套件應用

 Android 相關第三方Lib應用
    GreenDroid
    Asmack
    Viewflow
    ViewBadger
    Pulltorefresh
    Android-uitableview
    ActionBarSherlock
    NewQuickAction3D
    ListViewTipsAndTicks
    cwac-touchlist
    Shared_DragAndDrop
    cwac-AdapterWrapper

                            490
開發式UI函式庫-Asmack

• Asmack為XMPP應用於android的client端
  函式庫,XMPP為一套標準的IM通訊協定,
  包含Google Talk在內有許多IM即時通訊軟
  體皆支援XMPP協定。

• XMPP連線
public static XMPPConnection getConnection(String domain,int port) throws XMPPExcep
tion {
   ConnectionConfiguration config = new ConnectionConfiguration(domain,port);
   XMPPConnection connection = new XMPPConnection(config);
   connection.connect();
   return connection;
}
                                           491
開發式UI函式庫-Asmack

• XMPP登入
 XMPPConnection connection=getConnection();
 connection.login("jareyxxxx@gmail.com", "*****");


• XMPP斷線
 XMPPConnection connection=getConnection();
 connection.disconnect();


• 發送訊息
 Message msg = new Message(“xxxxx@gmail.com”, Message.Type.chat);
 msg.setBody(“Hello”);
 connection.sendPacket(msg);


                                        492
開發式UI函式庫-Asmack

 • XMPP接收訊息監聽
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
      connection.addPacketListener(new PacketListener() {
         public void processPacket(Packet packet) {
             Message message = (Message) packet;
             if (message.getBody() != null) {
                String fromName = StringUtils.parseBareAddress(message.getFrom());
                   messages.add(fromName + ":");
                messages.add(message.getBody());
                   mHandler.post(new Runnable() {
                    public void run() {
                      setListAdapter();
                    }
                });
             }
         }
      }, filter);

                                                493                                  493
範例練習
          範例專案名: ex13_01 GoogleTalk

  練習目標:
   了解如何使用Asmack套件
   利用Asmack與GoogleTalk        Server連線
  程式撰寫
   使用Asmack撰寫一簡易的聊天程式,兩個用戶
    可以透過Google Talk傳送訊息。




為你把關每一道 學習品質             494              494
開發式UI函式庫-GreenDroid

• GitHub位址
  • https://github.com/cyrilmottier/GreenDroid

• UI畫面截圖




                            495                  495
開發式UI函式庫-GreenDroid

•
    • GreenDroid為一個開放式的Android UI函
      式庫,主要提供許多標準的UI Pattern應
      用模組,可以簡化許多UI開發的繁鎖的工
      作。

•                可提供的模組
    •   SegmentedBar
    •   ActionBarActivity
    •   QuickAction
    •   AsyncImageView
    •   Tweaked ItemViews
                        496          496
範例練習
          範例專案名: ex13_02 GreenDroid

  練習目標:
   了解如何使用GreenDroid套件
   練習ActionBar的建立與使用方式
  程式撰寫
   開新專案並指定使用GreenDroid為其外部函式庫
    連結
   練習撰寫使用ActionBard




為你把關每一道 學習品質             497          497
開發式UI函式庫-Viewflow

• GitHub位址
  • https://github.com/pakerfeldt/android-viewflow

• UI畫面截圖




                            498                      498
開發式UI函式庫-Viewflow

• Viewflow函式庫提供一個可以水平左右
  滑動的頁面切換器
 • 於Layout XML中加入Viewflow元件
  <org.taptwo.android.widget.ViewFlow
     android:duplicateParentState="true"
     android:id="@+id/viewflow"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     />

  <org.taptwo.android.widget.TitleFlowIndicator
         android:id="@+id/viewflowindic"
         android:layout_height="wrap_content"
         android:layout_width="fill_parent"
         app:footerLineHeight="2"
         app:footerTriangleHeight="10"
         app:textColor="#FFFFFFFF"
         app:selectedColor="#FFFFC445"
         app:footerColor="#FFFFC445"
         app:titlePadding="10"
         app:textSize="13"
         android:layout_marginTop="10dip"
                                                  499   499
         />
開發式UI函式庫-Viewflow

• 使用ViewFlow
  ViewFlow viewFlow = (ViewFlow) findViewById(R.id.viewflow);
  AndroidVersionAdapter adapter = new AndroidVersionAdapter(this);
  viewFlow.setAdapter(adapter);
  TitleFlowIndicator indicator = (TitleFlowIndicator) findViewById(R.id.viewflowindic);
  indicator.setTitleProvider(adapter);
  viewFlow.setFlowIndicator(indicator);




                                                        500                               500
範例練習
           範例專案名: ex13_03 Viewflow

  練習目標:
   了解如何使用Viewflow套件
  程式撰寫
   使用Viewflow套件導入UI設計。




為你把關每一道 學習品質             501         501
開發式UI函式庫-Viewbadger

• GitHub位址
  • https://github.com/thiagolocatelli/android-
     uitableview

• UI畫面截圖




                             502                  502
開發式UI函式庫-Pulltorefresh

• GitHub位址
  • https://github.com/johannilsson/android-
     pulltorefresh

• UI畫面截圖




                            503                503
開發式UI函式庫-uitableview

• GitHub位址
  • https://github.com/thiagolocatelli/android-
     uitableview

• UI畫面截圖




                             504                  504
開發式UI函式庫-ActionBarSherlock

• GitHub位址
  • https://github.com/lorensiuswlt/ActionBarS
     herlock

• UI畫面截圖




                            505                  505
開發式UI函式庫-NewQuickAction3D

• GitHub位址
  • https://github.com/lorensiuswlt/NewQuickA
     ction3D

• UI畫面截圖




                           506                  506
開發式UI函式庫-ListViewTipsAndTicks

• GitHub位址
  • https://github.com/cyrilmottier/ListViewTipsA
     ndTricks

• UI畫面截圖




                            507                     507
開發式UI函式庫-cwac-touchlist

• GitHub位址
  • https://github.com/commonsguy/cwac-
     touchlist

• UI畫面截圖




                          508             508
開發式UI函式庫-Shared_DragAndDrop

• GitHub位址
  • https://github.com/teslacoil/Shared_DragAnd
     Drop

• UI畫面截圖




                           509                    509
開發式UI函式庫-cwac-AdapterWrapper

• GitHub位址
  • https://github.com/commonsguy/cwac-
     adapter

• UI畫面截圖




                          510             510
開發式UI函式庫-Workspace Widget

• 下載網址
  • http://blog.sephiroth.it/2011/11/01/android-
    workspace-widget/

• UI畫面截圖




                            511                    511

More Related Content

PDF
React Context API
PPTX
Refelction의 개념과 RTTR 라이브러리
PPTX
[Final] ReactJS presentation
PPTX
Introduction to react_js
PDF
Oracle Cloud Infrastructure:2023年5月度サービス・アップデート
PPTX
Hook me UP ( React Hooks Introduction)
PDF
In-Depth Model/View with QML
 
React Context API
Refelction의 개념과 RTTR 라이브러리
[Final] ReactJS presentation
Introduction to react_js
Oracle Cloud Infrastructure:2023年5月度サービス・アップデート
Hook me UP ( React Hooks Introduction)
In-Depth Model/View with QML
 

What's hot (16)

PDF
마이크로서비스 아키텍처와 DevOps 기술 - Amazon 사례를 중심으로 (윤석찬)
PPTX
Its time to React.js
PPTX
PDF
C++ BUILDER APUNTES .pdf
PDF
Android Jetpack Compose - Turkey 2021
PPTX
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
PPTX
C++ Builder 程式撰寫基礎 / C++ Builder Basic
PDF
Android Jetpack
PPTX
정해균 포트폴리오
PPTX
코딩클럽 왕초보 아두이노따라잡기 1탄
PDF
iOS architecture patterns
PDF
Microservice Architecture using Spring Boot with React & Redux
PDF
What are Microservices | Microservices Architecture Training | Microservices ...
PDF
Clean architecture
PPTX
Jetpack Compose - Android’s modern toolkit for building native UI
PPTX
Angular kickstart slideshare
마이크로서비스 아키텍처와 DevOps 기술 - Amazon 사례를 중심으로 (윤석찬)
Its time to React.js
C++ BUILDER APUNTES .pdf
Android Jetpack Compose - Turkey 2021
Qlik Sense マッシュアップ開発 - SaaS版とWindows版でJWTによる認証
C++ Builder 程式撰寫基礎 / C++ Builder Basic
Android Jetpack
정해균 포트폴리오
코딩클럽 왕초보 아두이노따라잡기 1탄
iOS architecture patterns
Microservice Architecture using Spring Boot with React & Redux
What are Microservices | Microservices Architecture Training | Microservices ...
Clean architecture
Jetpack Compose - Android’s modern toolkit for building native UI
Angular kickstart slideshare
Ad

Similar to Android動態ui介面設計 (9)

PDF
Android進階UI控制元件
PDF
Android 開發學習 (1)
PPTX
Android 程式設計(3)
PDF
Android 介面實作
PDF
UIKit Framework
PPTX
LabView with Lego NXT
PPT
Andorid程式開發(銘傳)
DOCX
14天學會安卓開發(完整版)
Android進階UI控制元件
Android 開發學習 (1)
Android 程式設計(3)
Android 介面實作
UIKit Framework
LabView with Lego NXT
Andorid程式開發(銘傳)
14天學會安卓開發(完整版)
Ad

More from 艾鍗科技 (20)

PPTX
AI 技術浪潮, 什麼是機器學習? 什麼是深度學習, 什麼是生成式AI, AI 能力認證
PDF
TinyML - 4 speech recognition
PPTX
Appendix 1 Goolge colab
PPTX
Project-IOT於餐館系統的應用
PPTX
02 IoT implementation
PPTX
Tiny ML for spark Fun Edge
PDF
Openvino ncs2
PDF
Step motor
PDF
2. 機器學習簡介
PDF
5.MLP(Multi-Layer Perceptron)
PDF
3. data features
PPTX
心率血氧檢測與運動促進
PPTX
利用音樂&情境燈幫助放鬆
PPTX
IoT感測器驅動程式 在樹莓派上實作
PPTX
無線聲控遙控車
PPT
最佳光源的研究和實作
PPTX
無線監控網路攝影機與控制自走車
PPTX
Reinforcement Learning
PPTX
Linux Device Tree
PPTX
人臉辨識考勤系統
AI 技術浪潮, 什麼是機器學習? 什麼是深度學習, 什麼是生成式AI, AI 能力認證
TinyML - 4 speech recognition
Appendix 1 Goolge colab
Project-IOT於餐館系統的應用
02 IoT implementation
Tiny ML for spark Fun Edge
Openvino ncs2
Step motor
2. 機器學習簡介
5.MLP(Multi-Layer Perceptron)
3. data features
心率血氧檢測與運動促進
利用音樂&情境燈幫助放鬆
IoT感測器驅動程式 在樹莓派上實作
無線聲控遙控車
最佳光源的研究和實作
無線監控網路攝影機與控制自走車
Reinforcement Learning
Linux Device Tree
人臉辨識考勤系統

Recently uploaded (16)

PDF
學會學LHTL榮譽作業:結合實驗與理論學習(製作者:陽明交通大學醫學二年級馬品婷)
PDF
黑客技术,安全提分不是梦!我们采用最新的数据破解和隐藏技术,精准定位并修改你的成绩,同时采用深度隐藏技术确保你的操作不被发现。价格实惠,流程快速,事后无痕...
PPTX
3分钟读懂佩珀代因大学毕业证Pepperdine毕业证学历认证
PPTX
ONU and OLT from Baudcom Jenny training PPT
PPTX
3分钟读懂滑铁卢大学毕业证Waterloo毕业证学历认证
PDF
想要安全提高成绩?我们的黑客技术采用深度伪装和多层加密手段,确保你的信息安全无忧。价格公道,流程简单,同时提供全面的信息保护和事后痕迹清理,让你轻松提升G...
PPTX
A Digital Transformation Methodology.pptx
PPTX
《HSK标准教程4下》第15课课件new.pptx HSK chapter 15 pptx
PDF
01_Course_Introduction(20210916課後更新).pdf
PPTX
3分钟读懂加州大学欧文分校毕业证UCI毕业证学历认证
DOCX
ALISON -COURSE ADVANCED CHEMISTRY -POLIMERIZATION 2025.docx
PPTX
3分钟读懂圭尔夫大学毕业证U of G毕业证学历认证
PPTX
3分钟读懂肯塔基大学毕业证UK毕业证学历认证
PPTX
3分钟读懂渥太华大学毕业证UO毕业证学历认证
PPTX
3分钟读懂贵湖大学毕业证U of G毕业证学历认证
PPTX
3分钟读懂福特汉姆大学毕业证Fordham毕业证学历认证
學會學LHTL榮譽作業:結合實驗與理論學習(製作者:陽明交通大學醫學二年級馬品婷)
黑客技术,安全提分不是梦!我们采用最新的数据破解和隐藏技术,精准定位并修改你的成绩,同时采用深度隐藏技术确保你的操作不被发现。价格实惠,流程快速,事后无痕...
3分钟读懂佩珀代因大学毕业证Pepperdine毕业证学历认证
ONU and OLT from Baudcom Jenny training PPT
3分钟读懂滑铁卢大学毕业证Waterloo毕业证学历认证
想要安全提高成绩?我们的黑客技术采用深度伪装和多层加密手段,确保你的信息安全无忧。价格公道,流程简单,同时提供全面的信息保护和事后痕迹清理,让你轻松提升G...
A Digital Transformation Methodology.pptx
《HSK标准教程4下》第15课课件new.pptx HSK chapter 15 pptx
01_Course_Introduction(20210916課後更新).pdf
3分钟读懂加州大学欧文分校毕业证UCI毕业证学历认证
ALISON -COURSE ADVANCED CHEMISTRY -POLIMERIZATION 2025.docx
3分钟读懂圭尔夫大学毕业证U of G毕业证学历认证
3分钟读懂肯塔基大学毕业证UK毕业证学历认证
3分钟读懂渥太华大学毕业证UO毕业证学历认证
3分钟读懂贵湖大学毕业证U of G毕业证学历认证
3分钟读懂福特汉姆大学毕业证Fordham毕业证学历认证

Android動態ui介面設計

  • 2. Android動態UI介面設計 Android動態元件設計  ListView  Gallery  GridView  ImageSwitch Adapter元件  ArrayAdapter  SimpleAdapter  自定Adapter 226
  • 3. 進階UI控制元件-Adapter使用 • Android 框架只負責應用程式的流程架構,框架設計師並不會知道最 終使用框架開發出的Application長的是什麼樣子。 • 應用程式設計師並不能直接去修改Android框架的內容,如此會造成 相容性問題,因此無法直接透過框架修改來決定應用程式的長相. • 為解決上述兩個問題,在Android裡設計了Adapter類別來做為 Android框架與應用程式之間的橋樑 • 為應付各種不同的資料數據來源,與不同的View元件,因此發展出各 式不同的Adapter元件。 為你把關每一道 學習品質 227
  • 4. 進階UI控制元件-Adapter使用 Adapter • 常見的Adapter的類別 ListAdapter SpinnerAdapter BaseAdapter ArrayAdapter CursorAdapter SimpleAdapter ResourceCursorAdapter • 常見Adapter對應到UI端的類別 SimpleCursorAdapter ViewGroup AdapterView AbsListView AbsSpinner ListView GridView Gallery Spinner 為你把關每一道 學習品質 228
  • 5. 進階UI控制元件-Adapter使用 • ArrayAdapter用途 • 作用為陣列與ListView之間的橋梁 • 可將陣列中定義的資料逐一的對應到ListView之中顯示 • 一般ArrayAdapter中顯示的ListView每行通常只有一個TextView ArrayList ListView Jarey Jarey TextView-Two John John ArrayAdapter May TextView-Two Ken May TextView-Two Ken TextView-Two 為你把關每一道 學習品質 229
  • 6. 進階UI控制元件-Adapter使用 • SimpleAdapter用途 • simpleAdapter可以定製每一列ListView中要顯示的內容 • 一般ListView中每一列的版面配置(Layout)會撰寫在XML檔中,在 由SimpleAdapter負責將內容(Data)填入Layout中的元件(View)。 ArrayList ListView HashMap Jarey 09222222 Name Jarey John Phone 0922 SimpleAdapter 09333333 HashMap May 09444444 Name John Phone 0933 Ken 095555555 為你把關每一道 學習品質 230
  • 7. 進階UI控制元件-Adapter使用 • 建構式ArrayAdapter (Context context, int resource, int textViewResourceId, T[] objects) • contex:要顯示的Context容器 • resource:layout定義,可以使用Android系統內建,或是自定layout. • textViewResourceId:位於layout中的textView,用來顯示data內容. • data:要顯示的資料內容 • 建構式SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) • contex:要顯示的Context容器 • data:基於Map的List. Map中包含了ListView每一列所需要的資料 • resource:顯示的Layout版型,此layout中至少要包含在to參數中所出現的 View。可使系統提供的layout,亦可自行定義 • from:名稱陣列,每一個名稝都對應Data中的索引鍵。 • to:為TextView類形的陣列,必須要在layout中可以被索引到。 為你把關每一道 學習品質 231
  • 8. 範例練習 範例專案名: ex05_01_Spinner 練習目標:  學習使用Spinner,利用ArrayAdapter提供 Spinner內容。 程式撰寫  建置Spinner元件,其內容資料於XML中利用 string array xml標籤編寫內容。  於Activity中讀入string array內容至記憶體,並套 用ArrayAdapter提供資料給Spiiner元件。 操作練習  模擬器練習,分練習XML方式導入靜態資料,與 使用Adapter方式動態載入資料兩種應用方式。 為你把關每一道 學習品質 232
  • 9. 進階UI控制元件-ListView • ListView為Android中用來顯示大量資 料的一個很重要的UI介面 • 由於手機受限於螢幕大小,當欲顯示 的資料數量超過一個頁面可以顯示時, 就可以利用ListView來做資料顯示 • ListView需搭配Adapter使用, ListView會自動依顯示控制的需求透 過Adapter介面取得資料。 • ListView提供OnItemClickListener() 方法,可以取得用戶的動件事件(例 如點選了那一個ListView元件) 為你把關每一道 學習品質 233
  • 10. 進階UI控制元件-ListView • ListView使用方式 • set data source to Adapter • get ListView from R.layout • set adapter to ListView • set click listener for each list item • ListView Event處理函式 • onItemClick(AdapterView<?> parent, View view, int position, long id) • onItemLongClick(AdapterView<?> parent, View view, int position, long id) • onItemSelected(AdapterView<?> parent, View view, int position, long id) 為你把關每一道 學習品質 234
  • 11. 範例練習 範例專案名: ex05_02_Adapter 練習目標:  了解各式adapter的使用  了解ListView與adapter之間的關係與運作 流程 程式撰寫  設計一ListView元件,並練習接上各式不 同的adapter與不同的資料來源串接  SimpleAdapter, ArrayAdapter 操作練習  透過模擬器操作不同的Activity,每一個 Activity代表一個不同Adapter的連接範例。 為你把關每一道 學習品質 235
  • 12. 進階UI控制元件-ListActivity • ListActivity使用時機 • 當一個Activity中只有顯示ListView,而且此ListView又會填滿整 個螢幕,此時可以直接使用ListActivity來代替Activity。 • ListActivity為一個包含了ListView的Activity,以wrapper的方式將 ListVIew包裝起來,方便更容易與直接的控制。 • ListActivity 預設ID元件 • ListActivity使用的layout檔中必須定義一個ListView,且此 ListView的id必須固定為[ @id/android:list ] • 另外可定義一個TextView當ListView裡沒有資料時可以顯示,此 TextView的id必須固定為[ @id/android:empty] 為你把關每一道 學習品質 236
  • 13. 進階UI控制元件-ListView • ListActivity使用方式 • Application extended ListActivity • set data source to Adapter • get ListView from ListActivity • set adapter to ListView • set click listener for each list item • ListView Event處理函式 • 在ListActivity中不用註冊Listener,而是直接以覆寫 (Override)來進行事件處理 • 可處理的Event函式與ListView相同 為你把關每一道 學習品質 237
  • 14. 範例練習 範例專案名: ex05_03_ListActivity 練習目標:  了解ListActivity的應用 程式撰寫  修改前一隻範例程式,試著將其改寫成 ListActivity  Activity直接繼承自ListActivity 操作練習  透過模擬器操作,注意ListActivity與ListView在對 於listener event 處理的寫法是否有所不同? 為你把關每一道 學習品質 238
  • 15. 進階UI控制元件-Adapter使用 • 自行定義Adapter內容 • 繼承(extended)BaseAdapter • 於建構式接收要處理的資料(Data)來源 • 覆寫(Override)以下四個Method • public int getCount() ; • 傳回Data的數量.(ListView的列數) • public Object getItem(int position); • 傳回指定的Data元件. • public long getItemId(int position); • 傳回Data的識別ID • public View getView(int position, View convertView, ViewGroup parent) • 傳回Layout與Data組合後的View元件(顯示於畫面上) • ※當Data內容有變更時,必須呼叫notifyDataSetChanged才會更新 ListView中的內容。 239 為你把關每一道 學習品質
  • 16. 進階UI控制元件-Adapter使用 • Adapter與Android框架運作流程 Android Activity AdapterView Adapter 框架 3.getCount() 4.getView() Application 2.setContentView() 1.onCreate() Map MyAdapter ListActivity Array Data Layout Cursor View XML 為你把關每一道 學習品質 240
  • 17. 範例練習 範例專案名: ex05_04_ImageAdapter 練習目標:  了解如何自行擴充Adapter類別  學習如何以高效率,最佳化記憶體方式設計 Adapter 程式撰寫  設計一個ImageAdapter類別,繼承至BaseAdapter 抽像類別  實作BaseAdapter的四個抽像函式  利用系統快取與ViewHolder提高Adapter的效能 操作練習  透過模擬器操作 為你把關每一道 學習品質 241
  • 18. 進階UI控制元件-ListView資料快取問題 • ListView為了節省記憶體與提高顯示的效能,會利用快取 機制,在ListView滑動時會重覆利用己使用過,目前不在 畫面上的View元件。 ConvertView ConvertView 重覆利用 ConvertView 由下往上滑動 ConvertView ConvertView 為你把關每一道 學習品質 242
  • 19. 進階UI控制元件-ListView內元件如何監聽事件 • ListView本身可以透過註冊setOnItemSelectListener來監 聽用戶點擊了那一條List Item。 • 若希望能為List Item中的每一個View元件單獨的設置 Listener事件,那麼需要注意以下二個問題: • ListView本身具有快取,List Item是重覆利用的,這將 導致用戶滑動List後,所點擊的元件可能與你當初註冊 的Listener元件不一致(如點了第5個Item中的一個 Button,但實際上第5個Item等同於重覆利用的第1個 Item) 為你把關每一道 學習品質 243
  • 20. 進階UI控制元件-ListView內元件如何監聽事件 • 由於Item元件是重覆利用,因此你將無法判斷用戶點 擊的Button為第幾個Item選項的Button,同時若你在每 次getView時都為新的Item重新設置新的Listener那麼 將會造成記憶體大量的浪費,同時也會降低顯示的效 能。 重覆利用 點擊第4個Item內的checkbox, 但呼叫的listener將與第1個 item相同。 為你把關每一道 學習品質 244
  • 21. 進階UI控制元件-ListView內元件如何監聽事件 • 解決LIstView 內Item元件的監聽事件的方法,可以透過 View.setTag方式,為將該List Item的資料快取在要被監 聽的View元件身上。如此當用戶點擊了CheckBox後,可 以在透過getTag的方式取得該List Item的資料做為判斷。 List Data Set setTag(Object); Profile1 Profile2 重覆利用 Profile3 Profile4 為你把關每一道 學習品質 245
  • 22. 進階UI控制元件-ListView資料快取問題 • 重覆使用的View元件會造成顯示不一致的問題,由其是當 View元件中有使用到如CheckBox這類的選單元件。 雖然只勾了一個選項。但往 上滑動時會造成第五個選項 看起來也是被勾選的 重覆利用 由下往上滑動 為你把關每一道 學習品質 246
  • 23. 進階UI控制元件-ListView資料快取問題 • 解決View元件顯示不一致的狀況,必須將ListView中每一 條的UI狀態記錄起來,在每次呼叫getView時去重新設定 UI狀態。 List Data狀態表 勾選 由下往上滑動 未勾選 重覆利用 未勾選 未勾選 未勾選 在準備顯示到畫面上前,重新將 View元件上的UI狀態做更新,將 勾選取消掉。 為你把關每一道 學習品質 247
  • 24. 範例練習 範例專案名: ex05_04_ImageAdapter 練習目標:  直接修改ImageAdapter範例,加入刪除模式功能  於刪除模式下顯示CheckBox元件提供用戶勾選。 程式撰寫  建置ListData 狀態表記錄每個ListView中每個元件的UI 狀態。  將ListView中的Layout所有的元件forcues狀能設為false 以避免遮避到ListView本身的onItemSelect事件。  註冊CheckBox的Onclick事件,並將狀態資料帶入至 Tag中提供供識別所點選的元件。 操作練習  透過模擬器操作 為你把關每一道 學習品質 248
  • 25. 進階UI控制元件-ImageSwitch&Gallery • ImageSwitch ViewGroup • 主要用來做圖片切換與自動播放用. AdapterView 可支援不同的進場與退場動畫特效 AbsSpinner • Gallery Gallery • 提供一個拖拉式圖片瀏覽與選擇介面 • 僅支援水平擺設方式 • 通常搭配ImageSwitch可用來做成簡 易的圖片瀏覽器。 為你把關每一道 學習品質 249
  • 26. 進階UI控制元件-ImageSwitch&Gallery • ImageSwitch元件 • XML宣告方式 • 程式碼使用方式 功能 程式碼 package Import android.widget.ImageSwitch; Reference ImageSwitch sw1 = (ImageSwitch) findViewById(R.id.imsw1); set sw1.setFactory(ViewSwitch.ViewFactory factory) sw1.setInAnimation(Animation inAnimation) sw1.setOutAnimation(Animation outAnimation) sw1.setImageResource (int resid) 為你把關每一道 學習品質 250
  • 27. 進階UI控制元件-ImageSwitch&Gallery • Gallery元件 • XML宣告方式 • 程式碼使用方式 功能 程式碼 package Import android.widget.Gallery; Reference Gallery gal1 = (Gallery) findViewById(R.id.gallery); set gal1.setAdapter(SpinnerAdapter adapter); Call back gal1.setOnItemSelectedListener(AdapterView.OnItemSelect edListener listener); 為你把關每一道 學習品質 251
  • 28. 範例練習 範例專案名: ex05_05_Gallery 練習目標:  透過Gallery與ImageSwitch設計一個簡易的相片 瀏覽器  復習先前教過的Adapter的應用 程式撰寫  撰寫一個Activity包含ImageSwitch與Gallery元件。  撰寫一個ImageAdapter提供給Gallery。 操作練習  透過模擬器操作 為你把關每一道 學習品質 252
  • 29. 進階UI控制元件-GridView • GridView為網格檢視元件,可以將很很多圖片以 ViewGroup 固定的大小排列顯示在畫面上可用來做為相簿與圖 片瀏覽等應用 AdapterView • GridView的資料取至於ListAdapter,一般要用做 AbsListView 相簿使用需要自行實作ImageAdapter(繼承至 BaseAdapter). GridView 為你把關每一道 學習品質 253
  • 30. 進階UI控制元件-GridView • GridView元件 • XML宣告方式 • 程式碼使用方式 功能 程式碼 package Import android.widget.GridView; Reference GridView grid= (GridView ) findViewById(R.id.grid); set grid.setAdapter(BaseAdapter adapter); Call back grid.setOnItemSelectedListener(AdapterView.OnItemSele ctedListener listener); 為你把關每一道 學習品質 254
  • 31. 第7節: Android 通知元件設計 Android Widget開發
  • 32. Android 通知元件設計 Android Menu元件設計  Option Menu  Context Menu Android通知元件設計  Dialog  Toast  Notification  Menu AppWidget桌面元件設計  Widget開發上的限制  Remove View的互動方式 256
  • 33. 進階UI控制元件-Menu選單 • Menu選單操作元件 • Option Menu • 按下menu建後顯 示 • Context Menu • 長時間按下一個視 窗後顯示 • Submenu • 子選單,可被 option或context Menu所呼叫 為你把關每一道 學習品質 257
  • 34. 進階UI控制元件-Option Menu • Option Menu • 選單位於整體畫面的下方,透過按下手機上的 Menu按鈕顯示 • 一個畫面最多可以安置6個選單項目,不支援 Checkbox及RadioButton • 超過6個選單的項目將會以擴充列的方式顯示。 • Option Menu 使用XML宣告 為你把關每一道 學習品質 258
  • 35. 進階UI控制元件-Option Menu • Inflating Option Menu Resource File • 透過MenuInflater.inflate() 協助載入xml資源檔 • public void inflate (int menuRes, Menu menu) @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; } 為你把關每一道 學習品質 259
  • 36. 進階UI控制元件-Option Menu • 建立Option Menu 使用MenuItem add函式 Public boolean onCreateOptionsMenu(Menu menu){ menu.add(0,MENU_ITEM_ID1, 0 “ MENU_ITEM_1”); menu.add(0,MENU_ITEM_ID2, 0 “ MENU_ITEM_2”); return true; } • MenuItem add函式 • public abstract MenuItem add (int groupId, int itemId, int order, int titleRes) • groupid:群組ID • itemid:項目ID • order:排序方式 • titleRes:每一個Item上的標題 為你把關每一道 學習品質 260
  • 37. 進階UI控制元件-Option Menu • 建立Menu • Call Back Function 為你把關每一道 學習品質 261
  • 38. 進階UI控制元件-Context Menu • Context Menu • 與在PC上的滑鼠右鍵功能類似,當按位某一 個View 2秒鐘,就會出現一個浮動式的 Context Menu。 • 較常使用在ListView上。 • 建立Option Menu 使用MenuItem add函式 為你把關每一道 學習品質 262
  • 39. 進階UI控制元件-Context Menu • Context Menu的callback函式 為你把關每一道 學習品質 263
  • 40. 進階UI控制元件-Submenu • Submenu • Context Menu與Option Menu可以在內嵌一個 子選單(Submenu)做為擴充。 • 子選單(Submenu)不能在擴充子選單 • 建立Submenu 使用xml 為你把關每一道 學習品質 264
  • 41. 進階UI控制元件-Submenu • 建立Submenu 使用SubMenu addSubMenu函式 @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); SubMenu fileMenu = menu.addSubMenu(GALLERY, SUBMANU01, Menu.NONE, "File"); SubMenu editMenu = menu.addSubMenu(GALLERY, SUBMANU02, Menu.NONE, "Edit"); fileMenu.add(GALLERY, MANU01, Menu.NONE, "new"); fileMenu.add(GALLERY, MANU02, Menu.NONE, "open"); fileMenu.add(GALLERY, MANU03, Menu.NONE, "save"); editMenu.add(GALLERY, MANU04, Menu.NONE, "undo"); editMenu.add(GALLERY, MANU05, Menu.NONE, "redo"); return true; } 為你把關每一道 學習品質 265
  • 42. 進階UI控制元件-Submenu • 處理Callback函式 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MANU01: case MANU02: case MANU03: case MANU04: case MANU05: String itemid = Integer.toString(item.getItemId()); String title = item.getTitle().toString(); showAlertDialog("項目ID = " + itemid + "n" + "標題 = " + title); return true; } return super.onOptionsItemSelected(item); } 為你把關每一道 學習品質 266
  • 43. 範例練習 範例專案名: ex06_01_01_OptionsMenu ex06_01_02_ContextMenu ex06_01_03_Submenu 練習目標:  學習各種Menu的應用場合與撰寫方式 程式撰寫  透過覆寫onCreateOptionsMenu函式來加入 Menu選單  透過覆寫onOptionsItemSelected來接收使用者的 選擇 操作練習  透過模擬器操作,透過按下手機上的Menu鍵來 呼叫出Menu選單。 為你把關每一道 學習品質 267
  • 44. Android通知元件-Notifications • Android提供三種不同的通知元件 • Toast • 短暫警示與通知,顯示數秒後會 自動消失 Toast Notification • Dialog • 對話窗可與使用者做簡單交談式 互動,一般用來做進度提示或確 認使用者的需求。 Dialog Notification • Status Bar Notification • 位於訊息列,訊息會長註於狀態 列,點擊後可啟動Activity。一般 Services會透過此通知用戶有事件 發生需返回Activity處理 Status Bar Notification 268 為你把關每一道 學習品質
  • 45. Android通知元件-Dialog元件 • Dialog是一切對話框基本類別,並非繼承於View類別. • Dialog也具有生命週期,其生命週期由Activity來誰護。 • 開發者可主動呼叫的函式 Activity • showDialog(int id) showDialog(int id) • dismissDialog(int id) Andr oid onCreateDialog(int id) 框架 onPreparDialog(int id, Dialog dialog) • 框架控制Dialog生命週期函式 • onCreateDialog(int id) • onPrepareDialog(int id, Dialog dialog) 269 為你把關每一道 學習品質
  • 46. Android通知元件-Dialog元件 • Dialog於Activity中的建立流程 • Step1: 呼叫Activity的showDialog(id) Button1.setOnClickListener(new OnClickListener(){ public void on click(View v){ showDialog(DIALOG1); } } ); • Step2: 覆寫(override)onCreateDialog(int id)函式 Protected Dialog onCreateDialog(int id){ switch(id){ Case DIALOG1: return buildDialog1(this); } return null; } 270 為你把關每一道 學習品質
  • 47. Android通知元件-Dialog元件 • Step3:建立需要的Dialog類別,將其返return回 Android框架 Private Dialog buildDialog1(Context context){ AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(R.drawable.alert_dialog_icon); builder.setTitle(R.string.alert_dialog_two_buttons_title); builder.setPositiveButton(R.string.alert_dialog_ok,new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int whichButton){ setTitle(“確認鈕”); } }); return builder.create(); } • Step4:覆寫onPrepareDialog(int id, Dialog dialog) protected void onPrepareDialog (int id, Dialog dialog, Bundle args){ return dialog; } 271 為你把關每一道 學習品質
  • 48. Android通知元件-Dialog元件 • AlertDialog • AlertDialog是Dialog的子類別,為最常使用的對話框 • 一個AlertDialog可以有二個至三個按鈕 • 不能直接以建構函式來產生AlertDialog物件,必須透過 AlertDialog.Builder來建構。 private Dialog buildDialog2(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(R.drawable.alert_dialog_icon); builder.setTitle(R.string.alert_dialog_two_buttons_msg); builder.setMessage(R.string.alert_dialog_two_buttons2_msg); builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { setTitle("點選了對話框上的確定按鈕"); }}); builder.setNeutralButton(略.同上); builder.setNegativeButton(略,同上; return builder.create(); } 272 為你把關每一道 學習品質
  • 49. Android通知元件-Dialog元件 • 具有View元件的對話框 private Dialog buildDialog3(Context context) { LayoutInflater inflater = LayoutInflater.from(this); final View textEntryView = inflater.inflate( R.layout.alert_dialog_text_entry, null); 略 AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setView(textEntryView); builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { setTitle("點選了對話框上的確定按鈕:" + ((TextView) textEntryView.findViewById(R.id.username_edit)).getText()); }}); builder.setNegativeButton(略…….); return builder.create(); } 為你把關每一道 學習品質 273
  • 50. Android通知元件-Dialog元件 • 進度對話框 private Dialog buildDialog4(Context context) { ProgressDialog dialog = new ProgressDialog(context); dialog.setTitle("正在下載歌曲"); dialog.setMessage("請稍候……-"); return dialog; } 為你把關每一道 學習品質 274
  • 51. 範例練習 範例專案名: ex06_02_Dialog 練習目標:  學習操作Android各種不同的Dialog對話視窗  學習如何將Dialog改成可以自定Layout元件 的對訊窗 程式撰寫  覆寫onCreateDialog函式,負責管理Activity 中呼叫的Dialog.  透過AlertDialog.Builder建立Dialog物件 操作練習  透過模擬器操作。 為你把關每一道 學習品質 275
  • 52. Android通知元件-Notification • Notification通知元件 • 不會打斷目前使用者的操作,訊息會長註於訊 息列中,待用戶有空時在進行處理,並可直接 啟動對應的Activity. • Notification可加入振動或聲音通知,以加強引 起用戶的注意。 為你把關每一道 學習品質 276
  • 53. Android通知元件-Notification • 如何撰寫Notification事件 • Step1:取得NotificationManager管理元件 mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); • Step2:建構Notification物件 • 第一個參數:要顯示的圖片ID • 第二個參數:要顯示的文字 • 第三個參數:顯示的時間,System.currentTimeMillis()代表立 即顯示 Notification notification = new Notification(drawable, tickerText,System.currentTimeMillis()); 為你把關每一道 學習品質 277
  • 54. Android通知元件-Notification • Step3:決定Notification如何呈現與處理事件 PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, ActivityMain.class), 0); • Context:作用於那一個Activity的Context • requestCode:目前無使用到 • Intent:要被啟動的Activity Intent • Flags: 細部的Intent操作控制,如 FLAG_CANCEL_CURRENT notification.setLatestEventInfo(this, title, content, contentIntent); • Step4:設定Notification預設的表現形式 • Notification.DEFAULT_VIBRATE 振動 • Notification.DEFAULT_SOUND 聲音 • Notification.DEFAULT_ALL 聲音+振動 • 需加入權限才能使用振動功能:Android.permission.VIBRATE notification.defaults = Notification.DEFAULT_ALL; mNotificationManager.notify(NOTIFICATIONS_ID, notification); 為你把關每一道 學習品質 278
  • 55. Android通知元件-Notification • Notification通知更新 • 透過notify()函式來更新通知,可以避免一直不斷產生新的 Notify訊息通知而導致塞滿了用戶的通知視窗 mNotificationManager.notify(NOTIFICATIONS_ID, notification); • 加入自定音效 • 系統預設音效 • notification.defaults |= Notification.DEFAULT_SOUND; • 讀取SD卡的mp3 • notification.sound =Uri.parse("file:///sdcard/notification/test.mp3"); • 從MediaStore的ContentProvider取得 • notification.sound = Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "6"); 為你把關每一道 學習品質 279
  • 56. Android通知元件-Notification • Notification相關FLAG設定 • FLAG_AUTO_CANCEL: • 用戶點了該通知後,系統便會自動清除該訊息 • FLAG_INSISTENT: • 重複發出響聲,直到使用者點選該訊息 • FLAG_ONGOING_EVENT: • 將該訊息放置放”進行中”群組,一般用來代表背景 Service還有在運行中。 • FLAG_NO_CLEAR: • 使用者就算點選了清除訊息,系統也不會把該訊息清 除,必須待應用程式自己發出清除的指令。 為你把關每一道 學習品質 280
  • 57. Android通知元件-Notification • 自定Notification顯示UI元件 • Step1: 利用RemoveView定義元件內容 RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout); contentView.setImageViewResource(R.id.imageIcon, R.drawable.notification_image); contentView.setTextViewText(R.id.textView, "Hello Notify"); notification.contentView = contentView; 為你把關每一道 學習品質 281
  • 58. Android通知元件-Notification • Step2: 發出通知訊息 • 使用contentIntent設置pendingIntent元件 Intent notificationIntent = new Intent(this, MyClass.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.contentIntent = contentIntent; mNotificationManager.notify(0, notification); 為你把關每一道 學習品質 282
  • 59. Android通知元件-Notification • Notification相關FLAG設定 • FLAG_AUTO_CANCEL: • 用戶點了該通知後,系統便會自動清除該訊息 • FLAG_INSISTENT: • 重複發出響聲,直到使用者點選該訊息 • FLAG_ONGOING_EVENT: • 將該訊息放置放”進行中”群組,一般用來代表背景 Service還有在運行中。 • FLAG_NO_CLEAR: • 使用者就算點選了清除訊息,系統也不會把該訊息清 除,必須待應用程式自己發出清除的指令。 為你把關每一道 學習品質 283
  • 60. Android通知元件-Tost通知元件 • Tost通知元件 • 為一個短暫提示元件,Toast會直接顯示於螢 幕下方. • Tost內容可以直接為描述一串文字,也可以帶 入View元件。 • Toast的顯示時間長度分為長與短兩種 • Toast.LENGTH_LONG • Toast.LENGTH_SHORT 為你把關每一道 學習品質 284
  • 61. Android通知元件-Tost通知元件 • 如何撰寫Tost通知 • Step1:實體化Toast物件 Toast toast = new Toast(this); • Step2:設定Toast內容 • setText(CharSequence s) • setView(View view) LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = vi.inflate(R.layout.toast,null); TextView tv = (TextView) view.findViewById(R.id.content); tv.setText("加入艾鍗,迅速提昇你的開發能力"); toast.setView(view); • Step3:設定顯示時間 toast.setDuration(Toast.LENGTH_SHORT); toast.show(); 為你把關每一道 學習品質 285
  • 62. 範例練習 範例專案名: ex06_03_Toast_and_Notification 練習目標:  學習如何建立Notification與Toast通知事件 程式撰寫  透過getSystemService(NOTIFICATION_SERVICE)取得 NotificationManager物件  建立PendingIntent物件,供用戶執選通知後返回Activity  透過notification.defaults決定通知時是否要加振動與音效  建立Toast物件,並傳送一簡單字串於畫面上 操作練習  透過模擬器練習,練習時可注意畫面的最上頂狀態列 收到Notification時的程現與執行後的處理方式 為你把關每一道 學習品質 286
  • 63. Android Widget開發 Widget程式開發  開發上的限制  Widget組成方式  如何設置組態設定Activity Remove View的互動方式 287
  • 64. Android Widget程式開發 • APP Widget為Android 1.5之後所提 供的功能。提供於Android桌面程式 (Home Screen)上安置各式各樣的 常註程式,例如小時鐘、Google Search... • 常註程式新增方式 • 在主畫面上按下觸控面版約2秒, 即會彈出Add to Home Screen 選單,選擇Widget後即會顯現 目前系統所安裝的各式Widget 為你把關每一道 學習品質 288
  • 65. Android Widget程式開發-使用限制 • Android Widget可以使用的功能 • 可加載於主畫面(Home Screen) • 同一個常駐程式可以多次啟動 • 常註程式啟動時不會採用全畫面(Full Screen) • Android Widget中不能使用的功能 • Event的呼叫。 • 有限的Layout使用,有限的GUI元件使用。 • 可使用的Layout類別: • Frame Layout • Linear Layout • Relative Layout • 可使用的GUI元件 • AnalogClock ImageButton • Button ProgressBar • Chronometer TextView 為你把關每一道 學習品質 289
  • 66. Android Widget程式開發-使用限制 • Android系統對Widget程式的處理方式會有所限制, Widget可以處理的方式選擇 處理方式 說明 指定執行間隔時間 於widget的資訊檔中設置定期執行的時間週期 指定執行時間 於Widget的資訊檔裡設定執行的時間 按下按鈕後才執行 常GUI介面被用戶按下時才執行 • Widget由於長駐於主畫面,且會不定時在背景運作, 因此設計時要特別注意評估電池與處理器的消耗狀況。 • Widget與Activity還有Services一般,皆有其獨自的生 命週期 為你把關每一道 學習品質 290
  • 67. Android Widget程式開發-生命週期 • Widget生命週期 開始 onDelete() onEnabled() onDisabled() onUpdate() App Widget 執行中 關閉 為你把關每一道 學習品質 291
  • 68. Android Widget程式開發-組成結構 • Android Widget應用程式組成結構 BroadcastReceiver AppWidgetManaget AppWidgetProvider 實作生命週期函式 廣播呼叫 onEnable,onUpdate, APPWIDGET_UPDATE onUpdate,onDelete d, myAppWidgetProvider onDisabled Android應用程式設定檔 Metadata設定 Widget資訊設定檔 Layout畫面布局檔 AndroidManifest.xml Name:名稱需為 Appwidget_info.xml Layout_sample.xml android.appwidget. 建立BroadcastReceiver provider 定義Layout布局 有限的layout元件使用 <action>欄位需明確定義為 畫面大小:74倍數-2 android.appwidget.action.APPWIDG 有限的GUI元件使用 Resource:指定 執行時間週期設定 ET_UPDATE information檔的來 源 為你把關每一道 學習品質 292
  • 69. Android Widget資料更新 • AppWidget主要是依建置在Home Launcher APP之上, 因此Widget畫面的更新與Event互動皆必須透過一個 Proxy來代為處理,而此Proxy就是AppWidgetManager 元件。 • 所有待更新的Widget元件,皆必須透過RemoteViews 元件封裝,所有的互動事件則必須透過pending Intent 註冊於RemoteViews中。 Home Launcher • AppWidget元件updateAppWidget函式協助將 RemoteViews更新於Widget元件上。 Widget setTextViewText setImageViewResource AppWidget Manager setOnClickPendingIntent RemoteViews 為你把關每一道 學習品質 293
  • 70. 範例練習 範例專案名: ex06_04_MyWidget 練習目標:  了解如何建置Widget元件  學習如何為Widget加入listener與更新UI 程式撰寫  實作一個Widget 的receiver元件,並實作組態設定 Activity,Widget啟動前會現顯示Activity應用程式。  撰寫Appwidget_info.xml檔,決定Widget顯示方式  撰寫Layout_sample.xml,決定Widget顯示的UI樣式。  撰寫RemoteView更新函式,取得Widget觸發事件, 並依事件狀態更新WidgetUI 操作練習  透過模擬器操作 為你把關每一道 學習品質 294
  • 71. Android Widget程式開發-組態設定Activity • AppWidget組態設定Activity • 當用戶新增一個Widget時,系統可以呼叫一個組態設定 Activity,提供用戶對該Widgegt進行設定,如改變顏色,顯示 大小,執行週期..等等資訊。 • 如何為AppWidget配置組態設定Activity • AndroidManifest.xml中定義Activity,<action>需定義為: ACTION_APPWIDGET_CONFIGURE <activity android:name="myAppWidgetConfigure"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> </intent-filter> </activity> • 於appwidget_info.xml中指定要呼叫的Activity <appwidget-provider .... android:configure= " com.example.android.appwidget.myAppwidgetConfigures" /> 為你把關每一道 學習品質 295
  • 72. Android Widget程式開發-組態設定Activity • AppWidget呼叫組態設定Activity時注意事項 • AppWidget呼叫執行Activity後,此Activity必須要返回一個結果, 而此結果必須要包含Widget ID(存在EXTRA_APPWIDGET_ID) • Activity被建立時,AppWidget中的onUpdate方法將不會被呼叫 到,因此Activity完成組態設定後一定要負責更新AppWidget程式 (可以透過請求AppWIdgetManager協助更新) • 組態設定Activity實作方式 • Step1:透過Intent取得AppWidget ID final Bundle extras = getIntent().getExtras(); If(extras != null){ int mAppWidgetId = extras.getInt( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } 為你把關每一道 學習品質 296
  • 73. Android Widget程式開發-組態設定Activity • Step2:執行組態設定,等待用戶設定操作 • Step3:設定完成後,更新AppWidget UI畫面 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(LifeCycleConfigure.this); RemoteViews views = new RemoteViews(getPackageName(), R.layout.life_cycle); appWidgetManager.updateAppWidget(mAppWidgetId, views); • Step4:最後建立一個Intent返回結果,並結束Activity Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); setResult(RESULT_OK, resultValue); finish(); 為你把關每一道 學習品質 297
  • 74. 範例練習 範例專案名: ex06_05_Appwidget 練習目標:  了解桌面Widget應用程式的撰寫方式與生命流程  學習如何為Widget加入組態設定用Activity 程式撰寫  實作一個Widget 的receiver元件,並實作組態設定 Activity,Widget啟動前會現顯示Activity應用程式。  撰寫Appwidget_info.xml檔,決定Widget顯示方式  撰寫Layout_sample.xml,決定Widget顯示的UI樣式。 操作練習  透過模擬器操作 為你把關每一道 學習品質 298
  • 76. Broadcast Receiver與Service元件 BroadCastReceiver元件  廣播的用途與種類  如何發送廣播封包  如何註冊接收廣播封包  廣播封包加入自定權限 Services 元件應用  Local 與 Remote Services  Services生命週期  如何與Services進行溝通  Remote Services設計實作  如何與RemoteServices溝通  Services與Activity通訊架構 設計 300
  • 77. BroadCast Receiver元件 • 廣播接收程式可用來接收其他應用程式所發出的訊息。 • 許多的廣播通知訊息都是來自於Android作業系統 • 電池電量快用盡 • 網路連線變化 • 有來電或簡訊通知 • 應用程式本身也可以發出廣播訊息,可做為與其他應用程 式互動溝通的管道。 • 需注意的是廣播訊息是公開的,任何應用程式都可以 透過註冊BraodCast Receiver來接收到你所廣播的訊 息。 • 一般常用來做為Services應用程式與Activity應用程式溝通 使用。 為你把關每一道 學習品質 301
  • 78. BroadCast Receiver元件 • 如何發送廣播 • 在程式中透過Intent建立好希望被那些action filter所接 收,接著透過sendBroadcast函式發送出去。 public static final String NEW_BROADCAST= " com.ittraining.action.NEW_BROADCAST "; Intent intent = new Intent(NEWO_BROADCAST); intent.putExtra(" data1",someData); intent.putExtra(" data2",someData); sendBroadcast(intent); 為你把關每一道 學習品質 302
  • 79. BroadCast Receiver元件 • 如何接收廣播 • 想接收並且處理廣播的Intent,就必需要註冊一個 BroadcastReciever,並且設定一個Intent Filter以將不需 要監聽的訊息過慮掉,最後在將其註冊到Android框架 中。 • Step1: 繼承BroadcastReceiver類別,並覆寫 onReceive(Context context, Intent intetn)函式 • 需注意onReceive函式內的處理不宜超過5秒,長時間 的處理建議移到Thread中執行。 public class IttrainingAndroidReceiver extends BroadcastReceiver{ @override Public void onReceive(Context context, Intent intent){ //接收後的處理 } } 為你把關每一道 學習品質 303
  • 80. BroadCast Receiver元件 • Step2: 註冊BroadCastReceiver • 透過XML註冊 <receiver android:name= " IttrainingAndroidReceiver " > <intent-filter> <action android:name= " com.ittraining.action.NEW_BROADCAST " /> </intent-filter> </receiver> • 透過程式碼註冊 IntentFilter filter =new IntentFilter(NEW_BROADCAST); IttrainingAndroidReceiver receiver=new IttrainingAndroidReceiver(); registerReceiver(receiver , filter); unregisterReceiver(receiver); • 取消註冊 unregisterReceiver(receiver); 為你把關每一道 學習品質 304
  • 81. 範例練習 範例專案名: ex07_01_Broadcastreceiver 練習目標:  學習如何發送廣播訊息  了解如何接收其它應用程式所發出的廣播訊息 程式撰寫  建立一個Activity應用程式與二個Recever程式  由Activity發送broadcast至Recever程式 操作練習  透過模擬器操作。注意兩個receiver的<intent- filter>action name並不相同,透過Activity可透過 不同的action決定要將訊息broadcast至指定的 receiver. 為你把關每一道 學習品質 305
  • 82. BroadCast Receiver元件-安全性管理 • Android廣播服務安全性漏洞 • 主要利用Intent Filter做為過濾,任何其它應用 程式只要得知廣播的Action Name就可以註冊 取得該廣播的資料。這將存在一個安全性的漏 洞,若你的廣播中所傳遞的是很重要的資料, 這將有可能被其它惡意軟體給監聽取得。 • 增加自訂權限傳送與接收廣播 • 開發者可為自己的APP程式加入自訂權限,任 何的應用程式如果要接收該廣播資料,則必須 宣告取得相關的權限。 為你把關每一道 學習品質 306
  • 83. BroadCast Receiver元件-安全性管理 • 增加權限到AndroidManifest.xml定義描述檔 <permission android:name="com.ittraining.ex07_02.SEND_DATA" android:description="@string/permission_aceess_deta" android:label="@string/permission_aceess" android:protectionLevel="normal" > </permission> • name:權限名稱,請求權限與執行權限時使用,必須為唯 一的值。 • description:提供詳細說明為何需要此權限,與如何使用 • lable:用戶安裝軟體時顯示給使用者看,以提供用戶進行 授權,此字串不應太長。 • protectionLevel:權限等級,normal為最基本等級。 為你把關每一道 學習品質 307
  • 84. BroadCast Receiver元件-安全性管理 • 於AndroidManifest.xml宣告請求使用者授權 <uses-permission android:name="com.ittraining.ex07_02.SEND_DATA"/> • 發送廣播時於sendBroadcast第二個參數帶入權 限名稱 sendBroadcast(intent, "com.ittraining.ex07_02.SEND_DATA“); • 接收端在註冊Receiver元件時,第三個參數需帶 入權限名稱 registerReceiver(receiver,filter, "com.ittraining.ex07_02.SEND_DATA“,null); 為你把關每一道 學習品質 308
  • 85. Services元件 • Services是在背景運作,不直接與使用者互動,因此並無 UI畫面 • Services無法獨立自行運作,而必須透過Activity或其它 Context物件來呼叫啟動 • Context.startService() • Context.binService() • 若Services的onCreate(),onStart()內需執行一些耗時的處 理,請使用Thread處理,以避免造成UI操件lock. • 使用Services的好處,在於Activity結束後其Services元件 依然會在背景做運行,Services有其獨立的生命週期不會 受Activity生命週期影影。 – 播放音樂 – 背景接收網路訊息 為你把關每一道 學習品質 309
  • 86. Services元件 • Android Services的使用方式可區分為二類 • Local Services (操作自己應用程式的Services) • Remote Services (操作其它應用程式的Services) • 與Services溝通方式 • 透過BroadCast傳送Intent至Services • 透過Binder與Services做Local Services連結 • 透過IPC(interprocess communication)與Remote Services做連結 • 透過Contex.getSystemService(String name),函 式可取得Android預設的Services元件. 為你把關每一道 學習品質 310
  • 88. Services元件 • Android系統內提供的一些Services服務 Services代碼 對應Manager 物件 說明 WINDOW_SERVICE WindowManager 管理視窗畫面 LAYOUT_INFLATER_SERVICE LayoutInflater 載入xml檔所定義的View元件 ACTIVITY_SERVICE ActivityManager 管理應用程式的系統狀態 POWER_SERVICE PowerManger 電源管理 ALARM_SERVICE AlarmManager 鬧鐘管理 NOTIFICATION_SERVICE NotificationManager 狀態列訊息通知服務 KEYGUARD_SERVICE KeyguardManager 鍵盤鎖管理 LOCATION_SERVICE LocationManager 位置服務管理,GPS SEARCH_SERVICE SearchManager 搜尋服務管理 VEBRATOR_SERVICE Vebrator 振動服務管理 CONNECTIVITY_SERVICE Connectivity 網路連線服務管理 WIFI_SERVICE WifiManager WIFI連線服務管理 TELEPHONY_SERVICE TeleponyManager 電話服務管理 為你把關每一道 學習品質 312
  • 90. Services元件-生命週期 • Services元件有其獨 立的生命週期 • onCreate() • onStart() • onDestroy() • 啟動Services的方式 不同,對應的生命 週期也不同。 • startServices() • bindServices() 為你把關每一道 學習品質 314
  • 91. Services元件-啟動Services • Step1: 於AndroidManifest.xml中加入Services宣告 <service android:enabled="true" android:name=".TestService" /> • Step2:覆寫Services函式-處理生命週期 public class TestService extends Service { @Override public void onCreate() { Log.e(TAG, "============> TestService.onCreate"); } @Override public void onStart(Intent intent, int startId) { Log.e(TAG, "============> TestService.onStart"); } @Override public void onDestroy() { Log.e(TAG, "============> TestService.onDestroy"); } } 為你把關每一道 學習品質 315
  • 92. Services元件-啟動Services • Step3:覆寫Services函式-提供Bind接口 @Override public IBinder onBind(Intent i) { return new LocalBinder();; } public class LocalBinder extends Binder { TestService getService() { return TestService.this; } } @Override public boolean onUnbind(Intent i) { Log.e(TAG, "============> TestService.onUnbind"); Return true; } @Override public void onRebind(Intent i) { Log.e(TAG, "============> TestService.onRebind"); } 為你把關每一道 學習品質 316
  • 93. Services元件-啟動Service • Step4:透過Activity啟動Service-使用startService() private void startService() { Intent i = new Intent(this, TestService.class); this.startService(i); } private void stopService() { Intent i = new Intent(this, TestService.class); this.stopService(i); } • Step4:透過Activity啟動Services-使用bindService() private void bindService() { Intent it = new Intent(this, TestService.class); bindService(it , _connection, Context.BIND_AUTO_CREATE); _isBound = true; } private void unbindService() { if (_isBound) { unbindService(_connection); _isBound = false; } 為你把關每一道}學習品質 317
  • 94. Services元件-啟動Service • Step6:SerrviceConnection元件建立-透過bindService() private ServiceConnection _connection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service){ _boundService = ((TestService.LocalBinder)service).getService(); Toast.makeText(TestServiceHolder.this, "Service connected:", Toast.LENGTH_SHORT).show(); } public void onServiceDisconnected(ComponentName className) { _boundService = null; Toast.makeText(TestServiceHolder.this, "Service connected", Toast.LENGTH_SHORT).show(); } }; 為你把關每一道 學習品質 318
  • 95. BroadcastReceiver與Services綜合演練 • 結合Services服與程式與BroadcastReceiver,實作 一鬧鐘計時器。 提供UI畫面讓User設定鬧鐘時 Services在背景進行時間排程倒 間設定完成後會通知背景 數,當時間到時透過broadcast訊 Services進行倒數計時,並註冊 息,傳送回主程式,並播放一段鬧鐘 一個BroadcastReceiver類別 音效與Toast訊息 KitchenTimer.java KitchenTimerService.java KitchenTimer Schedule(long delay) KitchenTimerSdervice.shecule(alarmtimer) Timer.shedule(timerTask,delay) KitchenTimer TimerTask() KitchenTimerReceiver-receiver sendBroadcast(new Intent(ACTION)) 為你把關每一道 學習品質 319
  • 96. BroadcastReceiver與Services綜合演練 • Step1:建立Services宣告 <service android:enabled="true" android:name=".KitchenTimerService" /> • Step2:主程式onCreate() //啓動服務程式KitchenTimerService Intent intent = new Intent(this, KitchenTimerService.class); startService(intent); //註冊廣播接收receiver IntentFilter filter = new IntentFilter(KitchenTimerService.ACTION); registerReceiver(receiver, filter); //(Bind)服務程式KitchenTimerService bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); 為你把關每一道 學習品質 320
  • 97. BroadcastReceiver與Services綜合演練 • Step3:主程式onDestroy() //Activity結束時,要將Service相關資源一並結束 @Override public void onDestroy() { super.onDestroy(); unbindService(serviceConnection); //Unbind service unregisterReceiver(receiver); //Unregister Receiver kitchenTimerService.stopSelf(); //Stop Service } • Step4:定義接收廣播類別KitchTimerReceiver private class KitchenTimerReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Toast toast = Toast.makeText(getApplicationContext(), "Time over!", Toast.LENGTH_LONG); toast.show(); MediaPlayer mp = MediaPlayer.create(KitchenTimer.this, R.raw.alarm); try { mp.start(); } catch (Exception e) { } kitchenTimerService.schedule(alarmtimer); } 為你把關每一道 學習品質 } 321
  • 98. BroadcastReceiver與Services綜合演練 • Step5:定義與Service bind的ServiceConnection private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { kitchenTimerService = ((KitchenTimerService.KitchenTimerBinder)service).getService(); } public void onServiceDisconnected(ComponentName className) { kitchenTimerService = null; } }; 為你把關每一道 學習品質 322
  • 99. BroadcastReceiver與Services綜合演練 • Step6:建立Services類:KitchenTimerService public void onCreate() { super.onCreate(); Toast toast = Toast.makeText(getApplicationContext(), "onCreate()", Toast.LENGTH_SHORT); toast.show(); } public void onStart(Intent intent, int startId) { super.onStart(intent, startId); Toast toast = Toast.makeText(getApplicationContext(), "onStart()", Toast.LENGTH_SHORT); toast.show(); } public void onDestroy() { super.onDestroy(); Toast toast = Toast.makeText(getApplicationContext(), "onDestroy()", Toast.LENGTH_SHORT); toast.show(); if (timer != null) { timer.cancel(); timer = null; } } 為你把關每一道 學習品質 323
  • 100. BroadcastReceiver與Services綜合演練 • Step7:覆寫Services Bind相關函式 @Override public IBinder onBind(Intent intent) { Toast toast = Toast.makeText(getApplicationContext(), "onBind()", Toast.LENGTH_SHORT); toast.show(); return new KitchenTimerBinder(); } @Override public void onRebind(Intent intent) { Toast toast = Toast.makeText(getApplicationContext(), "onRebind()", Toast.LENGTH_SHORT); toast.show(); } @Override public boolean onUnbind(Intent intent) { Toast toast = Toast.makeText(getApplicationContext(), "onUnbind()", Toast.LENGTH_SHORT); toast.show(); return true; //當再度自Client接口時,呼叫 onRebind的場合會回覆 true } 為你把關每一道 學習品質 324
  • 101. BroadcastReceiver與Services綜合演練 • Step8:Service發送廣播訊息至主程式 public void schedule(long delay) { if (timer != null) { timer.cancel(); } timer = new Timer(); TimerTask timerTask = new TimerTask() { public void run() { //送出信息給廣播接收程式 sendBroadcast(new Intent(ACTION)); } }; //設定Alarm time,且Time out時會執行timerTask送出信息 timer.schedule(timerTask, delay); } 為你把關每一道 學習品質 325
  • 102. 範例練習 範例專案名: ex07_02_Kitchentimer 練習目標:  學習如何結合BroadCastReceiver與Services的應用 程式撰寫  實作一個Activity並內置一個Receiver類別,當用設定 好時間後將啟動一個Services在背景做倒數計時的動 作。  實作一個Services應用程式,由Activity所呼叫建立, 當指定的計時工作結束後將透過broadcast方式通知 Activity的receiver類別。 操作練習  透過模擬器操作,倒數計時的單位為分鐘。時間到後 會發出聲響,並顯示一段Toast字串於畫面上。 為你把關每一道 學習品質 326
  • 103. Remote Services應用 • 要將Services元件跑在獨立的Processe中可透過在 AndroidMainfest.xml中,宣告services元件加上 android:process=":remote" <service android:name=".services.TrackerServices" android:process=":remote"> • Services中設置Messenger可以提供與遠端Services元件進 行雙向溝通。 private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { /*接收來自client傳來的訊息*/ } } private Messenger mMessenger = new Messenger(mHandler); @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } 為你把關每一道 學習品質 327
  • 104. Remote Services應用 • Client端在利用Bind與遠端Services連接,並取得 Messenger元件。 private Messenger remoteMessenger; private ServiceConnection connection = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { remoteMessenger = new Messenger(service); } public void onServiceDisconnected(ComponentName name) { remoteMessenger = null; } }; • 傳送訊息至Remote Services Private Message localMessenger; private void sendMessage() { Message message = Message.obtain(null, 0); message.replyTo = localMessenger; try { rMessenger.send(message); } catch (RemoteException e) { e.printStackTrace(); } } 為你把關每一道 學習品質 328
  • 105. 範例練習 範例專案名: ex07_03_RemoteService 練習目標:  了解RemoteServices與Local Services的差別  學習如何使用Messenger進行IPC跨Process通訊 程式撰寫  撰寫一個Services元件,並將process tag設為:remote  設置Messenger 物件做為IPC通訊管道。  撰寫Activity 元件,利用Bind 與remote services 通 訊。 操作練習  透過模擬 為你把關每一道 學習品質 329
  • 106. IntentService應用 • Android預設所有的四大元件都是運行在主執行緒中,包含 Service也是運行在主執行緒中,因此若在Service執行耗時 的工作則將會導致UI lock。避免UI Lock的方式為將Service 設置為remote,或是透過IntentService。 • IntentService 為一次性使用的Service元件,並且會自動運 行在子執行緒中,使用者可以免除複雜的Message、Loop 與Handler設計,透過Intentservice可以快速的處理一次性 耗時的工作。 • 將工作放置於IntentService的優勢 • 比較不容易被系統Kill • 工作於子執行緒中,不會導致UI Thread Lock • 非常容易使用,使用完即自動回收,不佔用記憶體。 為你把關每一道 學習品質 330
  • 107. 範例練習 範例專案名: ex07_04_IntentService 練習目標:  了解Intent Service、Thread與Service的差別  學習如何利用Intent Service 在背景處理耗時的工作 程式撰寫  繼承IntentService類別,並實作onHandleIntent函式  將耗時的工作寫在onHandleIntent函式中。  撰寫Activity頁面,利用startService函式呼叫 IntentService工作。 操作練習  透過模擬 為你把關每一道 學習品質 331
  • 109. SQLite DataBase開發技巧 SQLite Database存取技巧  SQLite語言定義與建置工具  SQLiteOpenHelp類別實作  資料庫的基本IO操作方式  設計DataBase Adapter架構 333
  • 110. SQLite DataBase • SQLite是Android內建的一個輕量化的嵌入式資料庫,可使 用SQL語法進行控制存取。 • SQLite的優點 • 免費,無需授權 • 輕量,約150KB左右,很適在嵌入式手機領域使用 • 無需設定、安裝與管理,沒有伺服器,不需組態檔,無 需資料庫管理員 • SQLite只是一個檔案,可以很方便的移動或複製到另一 系統,也能運作的很良好。 • Android將SQLite檔案存放於下列路徑中 • /data/data/packagename/databases • 可以使用adb或File Explorer來觀移存取資料庫檔案 為你把關每一道 學習品質 334
  • 111. SQLite DataBase • SQL入門 • SQL描述語法主要包含三種類型 • DLL(資料定義語言) • 修改 • 查尋 • DLL資料定義語言: • 資料庫的組成由多個資料表(table)多個資料列(Row) 若干資料欄(column)所組成。 • 每個資料欄具有欄位名稱與資料類形(文字,數字…) Create table mytalbe( _id integer primary key autoincrement, Name text, Phone text) • 第一個欄位指定為主鍵(PRIMARY KEY) 為你把關每一道 學習品質 335
  • 112. SQLite DataBase • 安裝Questoid SQLite Browser Eclipse Plugin,協助以圖形化方式觀看 Android內的SQLite資料表 • http://www.questoid.net/Tools/QuestoidSQLiteBrowser.aspx • 將com.questoid.sqlitebrowser_1.1.0.jar Copy至Eclipse的plugins目 錄中,並重新啟動Eclipse. • 切換至DDMS視圖,利用File Explorer工具找到要查看的SQLite data base檔案. • SQL語法指令查尋與學習資源 • http://www.1keydata.com/tw/sql/sqlhaving.html 為你把關每一道 學習品質 336
  • 113. SQLite DataBase-SQLiteOpenHelper • Android應用程式中提供了SQLiteOpenHelper類別來協助操 作SQLite資料庫並,提供產生與管理資料庫的版本 • SQLiteOpenHelper為一抽像類別,需繼承並實作三個函式 • onCreate(SQLiteDatabase db) • 資料庫第一次產生時呼叫。 • onUpdate(SQLiteDatabase db,int oldVersion,int newVersion) • 當資料庫需要升級時,由系統主動呼叫。一般用來刪除舊資料 表,並建立新的資料表 • onOpen(SQLiteDatabase db) • 當資料庫被開啟時的Callback函式,由系統呼叫,一般不會使用到。 為你把關每一道 學習品質 337
  • 114. SQLite DataBase-SQLiteOpenHelper • 如何建立SQLiteOpenHelper類別 private static final String DATABASE_NAME = "dbForTest.db"; private static final int DATABASE_VERSION = 1; private static final String TABLE_NAME = "diary"; private static final String TITLE = "title"; private static final String BODY = "body"; private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE + " text not null, " + BODY + " text not null " + ");"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } 為你把關每一道 學習品質 338
  • 115. SQLite DataBase-SQLiteOpenHelper • 取得透過SQLiteOpenHelper取得SQLiteDatabase類別 Public Methods synchronized SQLiteDatabase getReadableDatabase()Create and/or open a database. synchronized SQLiteDatabase getWritableDatabase()Create and/or open a database that will be used for reading and writing. • 利用SQLiteDatabase提供的函式可以存取操作資料庫 • public Cursor rawQuery (String sql, String[] selectionArgs) • 最低階的操作函式,可以直接接受標準SQL語法 • 為方便不熟SQL語法的開發者,另外有提供一系列的API函式,系統 會將API指令自動轉換成標準的SQL語法呼叫資料庫。 • pubilc delete(….) • pubilc insert(….) • pubilc update(….) • public Cursor query (….) 為你把關每一道 學習品質 339
  • 116. SQLite DataBase-資料庫操作 • 如何插入資料庫記錄 private void insertItem() { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); String sql1 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY + ") values('haiyang', 'android的發展真是迅速');"; String sql2 = "insert into " + TABLE_NAME + " (" + TITLE + ", " + BODY + ") values('icesky', 'android的發展真是迅速');"; try { db.execSQL(sql1); db.execSQL(sql2); setTitle("插入兩條數據成功"); } catch (SQLException e) { setTitle("插入兩條數據失敗"); } } 為你把關每一道 學習品質 340
  • 117. SQLite DataBase-資料庫操作 • 如何刪除資料記錄 private void deleteItem() { try { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); db.delete(TABLE_NAME, " title = 'haiyang'", null); setTitle("刪除title為haiyang的一條記錄"); } catch (SQLException e) { } } • 查尋資料 private void showItems() { SQLiteDatabase db = mOpenHelper.getReadableDatabase(); String col[] = { TITLE, BODY }; Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null); Integer num = cur.getCount(); setTitle(Integer.toString(num) + " 條記錄"); } 為你把關每一道 學習品質 341
  • 118. SQLite DataBase-資料庫操作 • 刪除整個Table private void dropTable() { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); String sql = "drop table " + TABLE_NAME; try { db.execSQL(sql); setTitle("數據表成功刪除︰" + sql); } catch (SQLException e) { setTitle("數據表刪除錯誤"); } } • 建立新的Table private void CreateTable() { SQLiteDatabase db = mOpenHelper.getWritableDatabase(); String sql = "CREATE TABLE " + TABLE_NAME + " (" + TITLE + " text not null, " + BODY + " text not null " + ");"; try { db.execSQL("DROP TABLE IF EXISTS diary"); db.execSQL(sql); setTitle("數據表成功重建"); } catch (SQLException e) { setTitle("數據表重建錯誤"); } 為你把關每一道 學習品質 } 342
  • 119. 範例練習 範例專案名: ex08_01_Sqlite 練習目標:  學習如何建立與使用SQLite資料庫 程式撰寫  撰寫DataBaseHelper 繼承SQLiteOpenHelper  透過DataBaseHelper取得SQLiteDatabase物件,並實作新 增、刪除、查尋、建立資料表等函式 操作練習  透過模擬器操作,可以藉由DDMS的檔案瀏覽器 將SQLite資料庫檔滙出,或滙入現有的SQLite資 料庫至手機上。 為你把關每一道 學習品質 343
  • 120. SQLite DataBase-Query函式 • SQLiteDatabase的query方法 • Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) • distinct : 是否希望每一row都是唯一的 • table:要查尋的資料表(Table) • columns:回傳資料包含的訊息列。不在清單中的其它列將不會取得。 • selection:相當於SQL中的where,如想傳回所有資料請用null • selectionArgs:如select中有使用到[?]變數,此字串將用來取代[?] • groupBy:查尋得到的資料是否要分群組 • having:相當於SQL中的having • orderBy:是否需要排序,若設定為null代表不排序 • limit:限制查尋回的資料組數上限 為你把關每一道 學習品質 344
  • 121. SQLite DataBase-Cursor介面 • android.database.Cursor介面 • 由query方法查尋到資料後,將會回傳Cursor物件。 • 透過Cursor可以將資料庫查出來的資料進行讀寫操作。 • Cursor可以連結CursorAdapter並覆寫其bindView()和newView()兩 抽像方法來達到更豐富的顯示方式 Activity SQLiteOpenHelper Cursor Query結果 SQLiteDatabase 為你把關每一道 學習品質 345
  • 122. SQLite DataBase-Cursor介面 • Cursor常用的函式 函式 說明 movetoPosition(int pos) 移動Cursor到指定位置 Move(int offset) 向前或向後位移:正數向前,負責向後 moveToFirst() 移動Cursor到最前或最後位置 moveToLast() moveToNext() 將Cursor向前或向後移動一格 moveToLast() isBeforeFirst() 判斷Cursor是否指向第一個數據之前,或最 isAfterLast() 後一個數據之後 isFirst() 判斷Cursor是否指向第一行或最後一行 isLast() getColumnCount() 取得行(列)數目 getCount() getColumnIndexOrThrow(String 根據列的名稱取得索引值(以0開始) columnName) getBlob(int index) 依據資料型別取回Cursor目前所指的資料。 getInt(int index) getLong(int index) getShort(int index) getFloat(int index) 為你把關每一道 學習品質 getString(int index) 346
  • 123. SQLite DataBase-Cursor介面 • Cursor與CursorAdapter連接 • public SimpleCursorAdapter (Context contex, int layout, Cursor c, String[]from, int[] to) • context:作用於那個Context物件上 • layout:顯示介面layout樣版,需包含to所指定的View id • c: cursor資料來源 • from:需要從cursor取出的列名稱索引值 • to:layout中需要作用對應於from值的View元件id s = (Spinner)findViewById(R.id.spinner); display = (TextView)findViewById(R.id.display); SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item,c,new String[] { MyHelper.COUNTRY}, new int[] {android.R.id.text1}); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_it em); s.setAdapter(adapter); 為你把關每一道 學習品質 347
  • 124. SQLite DataBase-日記簿運作流程 ActivityDiaryEdit DiaryDbAdapter onCreate () onClick() deleteDiary() createDiary() getAllNotes() EditText EditText Button getDiary() updateDiary() ActivityMain extends ListActivity onMenuItemSelected() onCreateOptionsMenu() DatabaseHelper createDiary() onListItemClick() onCreate () SimpleCursorAdapter NAME:database TABLE: diary Query結 Cursor 果 為你把關每一道 學習品質 348
  • 125. 範例練習 範例專案名: ex08_02_Sqldiary 練習目標:  學習如何利用SQLite開發一個簡單的日記本  學習SimpleCursorAdapter的使用 程式撰寫  實作一個ListActivity,並將SQLite讀取得到的資料透 過SimpleCursorAdapter顯示於ListActivity上.  實作一個DiaryDbAdapter,協助處理與SQLite資料庫 存取有關的所有操作  設計一個日記輸入與編輯的UI頁面 操作練習  透過模擬器進行操作。 為你把關每一道 學習品質 349
  • 126. DataBaseAdapter架構實作 • 設計DataBaseAdapter可提供Activity頁面一個統 一且一致的存取資料庫的介面,並且將SQL語法 隱藏在Adapter內,對外只提供高階的存取介面。 SqlObject SqlObject DataBaseAdapter SqlObject IOInterface Activity SQLite DataBaseOpenHelp 為你把關每一道 學習品質 350
  • 127. DataBaseAdapter架構實作 • 資料庫表單常數定義介面 • DataBaseColumnDefine public interface DataBaseColumnDefine { /* 表單名稱 */ public static final String USERPROFILE_TABLE_NAME = "UserProfileDB"; /* 欄位名稱 */ public static final String USERPROFILE_KEY_ID = "_id"; /*SQL指令*/ public static final String SQL_CREATE="CREATE TABLE "; public static final String SQL_DATA_AUTO=" integer primary key autoincrement"; public static final String SQL_DATA_NUMERIC=" NUMERIC"; public static final String SQL_DATA_TEXT=" TEXT"; /*建立table的sql語法*/ public static final String CREATE_USERPROFILE_TABLE = SQL_CREATE + USERPROFILE_TABLE_NAME+ " (" + USERPROFILE_KEY_ID + SQL_DATA_AUTO+");"; /*Query回來資料的欄位範圍*/ public static String[] userProfileDataSet = { USERPROFILE_KEY_ID,}; } 為你把關每一道 學習品質 351
  • 128. DataBaseAdapter架構實作 • SqlObject抽像介面設計 • 抽像的功能 /** * 取得privateKey值 */ abstract int getPrivateKey(); /** * 設定privateKey值 */ abstract void setPrivateKey(int privateKey); /** * 從資料庫中讀入資料 * @param cursor */ abstract void readProfile(Cursor cursor); /** * 將資料轉換成ContentValues以供資料庫做後操作 */ abstract ContentValues getContentValues(); 為你把關每一道 學習品質 352
  • 129. DataBaseAdapter架構實作 • SqlObject抽像介面 • 產生SqlObject的建構工廠 /** * 依需求取得不同型態的SQL Object * @param type * @return */ public static SqlObject createUserDataObject(SqlType type){ switch(type){ } return null; } 為你把關每一道 學習品質 353
  • 130. DataBaseAdapter架構實作 • DataBaseAdapter實作方式 • 使用Singleton架構 private SQLiteDatabase sqlDataBase; private static DataBaseAdapter dbAdapter; private DataBaseAdapter(Context context){ DataBaseHelp dataBaseHelp= new DataBaseHelp(context); try { dataBaseHelp.createDataBase(); } catch (IOException e) { e.printStackTrace(); } sqlDataBase=dataBaseHelp.getWritableDatabase(); } public synchronized static DataBaseInterface getInstence(Context context){ if(dbAdapter==null) dbAdapter=new DataBaseAdapter(context.getApplicationContext()); return dbAdapter; } 為你把關每一道 學習品質 354
  • 131. DataBaseAdapter架構實作 • 透過DataBaseOpenHelp讀寫資料庫(SqlObject) • 新增 mDb.insert(USERPROFILE_TABLE_NAME, null, initialValues); • 刪除 mDb.delete(USERPROFILE_TABLE_NAME, USERPROFILE_KEY_ID + "=" + sqlObject.getPrivateKey(), null); • 修改 mDb.update(USERPROFILE_TABLE_NAME, initialValues, USERPROFILE_KEY_ID + "=" + sqlObject.getPrivateKey(0, null) > 0; • 查尋 Cursor mCursor=mDb.query(USERPROFILE_TABLE_NAME, userProfileDataSet, null, null, null, null,null); 為你把關每一道 學習品質 355
  • 132. DataBaseAdapter架構實作 • 上層Activity使用DataBaseAdapter方式 • 取得DataBaseAdapter物件實體 DataBaseAdapter dbAdapter=DataBaseAdapter.getInstence(this); • 讀取資料 ArrayList<UserProfile>allUser= (ArrayList<UserProfile>) dbAdapter.getAllUser(null); ArrayList<UserProfile>allUser=dbAdapter.getAllUser(allUser); //參照更新 • 新建資料 profile.setPhotoType(1); profile.setUserCompony("test"); profile.setUserName("Jarey"); profile.setUserPhone("09xxx"); long privateKey=dbAdapter.addUserProfile(profile); 為你把關每一道 學習品質 356
  • 133. 範例練習 範例專案名: ex08_03_SqlTemplet 練習目標:  學習如何設計DataBase Adapter  透過DataBase Adapter層將應用層與資料存取層分 程式撰寫  設計一簡單的資料庫表單,並實作DataBase Adapter 元件。  Activity層透過DataBase Adapter對資料庫進行資料存 取。  實作一個BaseAdapter元件,將從DataBaseAdapter 讀出的資料透過BaseAdapter顯示於ListView上。 操作練習  透過模擬器進行操作。 為你把關每一道 學習品質 357
  • 134. 第10節: Content Provider元件 Android Thread程式設計
  • 135. Content Provider元件 ContentProvider元件設計  ContentProvider應用時機  與系統ContentProvider連接  自建ContentProvider 359
  • 136. Content Provider元件 • ContentProvider作用 • Android程式中所有的資料(包含檔案,資料庫)全都是Private的,不同 的應用程式之間不能直接存取 • ContentProvider提供解決不同應用程式之間交換資料的需求 • ContentProvider提供一組標準介面 • query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) • 透過Uri進行查尋,結果將透過傳回的Cursor物件進行存取. • insert(Uri url,ContentValues values) • 將一組資料插入到Uri指定的位置 • update(Uri url,ContentValues values,String where,String[] selectionArgs) • 更新Uri指定位置的資料 • delete(Uri url,String where,String[] selectionArgs) • 刪除Uri指定並符合條件的資料 為你把關每一道 學習品質 360
  • 137. Content Provider元件 • ContentResolver • 外部應用程式可以透過ContentResolver介面來存取 ContentProvider所提供的資料 • ContentResolver物件是透過Activity.getContentResolver()取得 • ContentResolver所提供的存取介面 • query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) • insert(Uri url,ContentValues values) • update(Uri url,ContentValues values,String where,String[] selectionArgs) • delete(Uri url,String where,String[] selectionArgs) Application Application URI Content Content Activity Data Resolver query Provider insert update 為你把關每一道 學習品質 delett 361
  • 138. Content Provider元件 • ContentProvider 中使用的Uri形式 • content://contacts/people/ 代表全部聯絡人資料 • content://contacts/people/1 代表ID為1的連絡人資料 • Uri的組成結構: content://authority/path/id • 第一部份:content:// • 必要的標準前置碼(prefix) • 第二部份:authority • 提供者的名稱,在此建使用完全套件名稱定義以避免名稱出現衝 突狀況 • 第三部份:path • 為提供者內部的虛擬目錄路徑 • 第四部份:id • 請求之特定記錄的主鍵ID,若要請求所有記錄可以直接以/結尾 為你把關每一道 學習品質 362
  • 139. ContentProvider元件-讀取連絡人資料 • Android內建的ContentProvider • content://browser • content://contacts • content://media • content://settings • Step1:於AndroidManifest.xml中加入權限 <uses-permission android:name="android.permission.READ_CONTACTS" /> • Step2:取得ContentResolver物件,query連絡人資料 import android.provider.ContactsContract; import android.content.ContentResolver; ContentResolver cr = getContentResolver(); Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); 為你把關每一道 學習品質 363
  • 140. Content Provider元件-讀取連絡人資料 • Step3:取得連絡人姓名 String name = cur.getString(cur.getColumnIndex("display_name")); • Ste4:取得連絡人ID (2.0.1後改版,Phone移至不同URI) long id = cur.getLong(cur.getColumnIndex(" _id")); • Step5:透過ID重新查尋得使用者電話 Cursor pcur = getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null ,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + Long.toString(id), null, null); String strPhoneNumber = pcur.getString( pcur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 為你把關每一道 學習品質 364
  • 141. 範例練習 範例專案名: ex08_04_Contentprovider 練習目標:  學習如何建立ContentResolver並連接至Android 的連絡人Content Povider,取得用戶的連絡人清 單資料 程式撰寫  透過getContentResolver ()取得ContentResolver 物件  連接至Android CONTENT_URI ,並將資料透過 adapter顯示於ListView上 操作練習  透過模擬器操作 為你把關每一道 學習品質 365
  • 142. ContentProvider元件-自建ContentProvider • 修改先前的日記簿範列,將新增、刪除、修改與查尋操作改以 ContentProvider的方式來實作。 ActivityDiaryEdit EditText EditText Button DiaryContentProvider insertDiary() Content extend ContentProvider updateDiary() Resolver Content query() Provider Insert() delete() ActivityMain extends ListActivity update() onMenuItemSelected() onCreateOptionsMenu() Content onOptionsItemSelected() Resolver onListItemClick() SQLiteOpenHelper SimpleCursorAdapter Diary Query結 NAME:database Cursor BaseColumns 為你把關每一道 學習品質 果 TABLE: diary 366
  • 143. ContentProvider元件-自建ContentProvider • Diary類別實作 public final class Diary { //這裡的 AUTHORITY 要求是唯一,而且和Manifest當中provider標籤的AUTHORITY內容一致 public static final String AUTHORITY = "com.ex09_2_contentprovider.diarycontentprovider"; private Diary() {} public static final class DiaryColumns implements BaseColumns { // This class cannot be instantiated private DiaryColumns() {} public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/diaries"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.diary"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.diary"; public static final String DEFAULT_SORT_ORDER = "created DESC"; public static final String TITLE = "title"; public static final String BODY = "body"; _id title body create public static final String CREATED = "created"; unique-id 標題 內文 建立時間 } } unique-id 標題 內文 建立時間 為你把關每一道 學習品質 367
  • 144. ContentProvider元件-自建ContentProvider • DiaryContentProvider類別實作 • 繼承自ContentProvider類別 • 定義Uri類別變數: content://com.ex09_2_contentprovider.diarycontentprovider/diaries • content:固定的開頭不用更改 • AUTHORITY:授權字串必須是唯一的,宣告告於AndroidManifest.xml • request: 資料型別,在此只定義一個型別,對應資料表名稱。也可以設 計成兩個公開的資料表例如 diaries/my ,diaries/other. • id:代表要存取那一筆資料 • 建構資料儲存系統,在此使用的是SQLite資料庫 • 實作ContentProvider抽像方法 • oncreate();query();inster();delete();update();getType(); • 於AndroidManifest.xml中加入<provider>標籤 <provider android:name="DiaryContentProvider" android:authorities="com.ex09_2_contentprovider.diarycontentprovider" /> 為你把關每一道 學習品質 368
  • 145. ContentProvider元件-自建ContentProvider • android.database.sqlite.SQLiteQueryBuilder類別介紹 • 建構SQL查尋語法的輔助類別 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); • qb.query(SQLiteDatabase db,String[] projectionIn,String selection,String[] selectionArgs,String groupBy,String having,String sortOrder,String limit); 為你把關每一道 學習品質 369
  • 146. ContentProvider元件-自建ContentProvider • android.content.ContentUris類別介紹 • URI的一個補助類別,包含了二個函式 • Public static Uri withAppendedId(Uri contentUri,long id) • 負責將id和Uri串接在一起成新的Uri。 Uri diaryUri = ContentUris.withAppendedId( Diary.DiaryColumns.CONTENT_URI, rowId) • Public static long parseId(Uri contentUri) • 負責把Uri後的id解析出來。 • 例如com.ex09_2_contentprovider.diarycontentprovider/100 透過parseId後回傳值為100 為你把關每一道 學習品質 370
  • 147. ContentProvider元件-自建ContentProvider • android.content.UriMatcher類別介紹 • 為用來判斷Uri的一個補助類別 • 提供方便的判斷Uri是針對單一資料的要求,或是針對全部 資料的要求 • 建立比對條件式 sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(Diary.AUTHORITY, "diaries", DIARIES); sUriMatcher.addURI(Diary.AUTHORITY, "diaries/#", DIARY_ID); • 進行比對 sUriMatcher.match(uri) 為你把關每一道 學習品質 371
  • 148. 範例練習 範例專案名: ex08_05_Contentprovider_Diary 練習目標:  學習如何自行建立一個ContentProvider  學習如何透過ConentResolver與ContentProvider 連接存取資料。 程式撰寫  將前一個範例中的DiaryDbAdapter改繼承至 ContentProvider,並提供一個URI接口,讓其他 應用程式可以連接存取資料。 操作練習  透過模擬器操作,觀查使用ContentProvider實作 的不同處 為你把關每一道 學習品質 372
  • 149. Android Thread程式設計  Android Thread運作機制  認識Looper與Message Queue  Handler  如何進入UI Thread變更UI內容  Handler  Activity.runOnUiThread  View.post(Runnable)  AsyncTask 373
  • 150. Android Thread運作機制-Looper與MQ • 在Android中Thread分為有Message Queue的循環Thread 與沒有Message Queue的循環Thread兩種。 • 有Message Queue的循環Thread • 主執行緒(UI Thread)為有包含Message Queue的 Thread. • Looper會不斷循環的確認Message Queue裡是否有要 處理的Event. • 可透過Handler物件來將訊息丟到MQ中 Looper • 無Message Queue的循環Thread • 由主執行緒產生的子執行緒並不 MQ 會具有Looper與MQ物件 Push Handler 為你把關每一道 學習品質 374 374
  • 151. Android Thread運作機制-Looper與MQ • MQ可做為執行緒之間的溝通管道 • 子執行緒可透過Handler Push Message至主執行緒的MQ中來與 主執行緒溝通。 • 透過MQ傳遞Message為非同步方式,呼叫者並不會因此而被 Lock住,Message Push至MQ後函式會立即返回。 • 子執行緒本身不具有Looper與MQ,落其他執行緒(如主執行緒) 需要與子執行緒溝通時,必須先為子執行緒建立Looper與MQ物 件。 message 主執行緒 message Looper UI Thread 子執行緒 Looper MQ MQ 為你把關每一道 學習品質 375 375
  • 152. Android Thread運作機制-Looper與MQ • UI(主)執行緒 • UI Thread中所有的操作必須在5秒內回應, 否則系統會因愈時而強制關閉應用程式。 • 關於UI的操作只能在主執行緒(UI Thread)中處理, 子執行緒中只能進行數據資料等其他非UI的操作。 • 子執行緒若有需要做UI的控制,必須將需求傳送 給主執行緒的MQ,在由主執行緒負責做UI的變更。 主(UI)Thread onClick(View V){ new Thread().start(); } message handlerMessage(Message msg){ File Text Data Looper textView.setText(“…”); } MQ 子Thread 搜尋讀取檔案中的文字,並顯示於UI textView.setText(“”); 為你把關每一道 學習品質 handler.sendMessage(m); 376 376
  • 153. Android Thread運作機制-Looper與MQ • Handler物件 • Handler是由Android框架所提供的類別,用來協助將 Message物件送到MQ中。當Looper發現MQ中有 Message,便會呼叫handleMessage方法進行處理。 • Handler除了傳送Message物件外,也可以傳送實作 Runnable的介面的物件到MQ上。 • Handler宣告方式 Handler h = new Handler(){ @override public void handleMessage(Message msg){ //處理message } } 為你把關每一道 學習品質 377 377
  • 154. Android Thread運作機制-Looper與MQ • Handler建構與Callback方式(框架原始碼) public Handler(Looper looper, Callback callback) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; } public interface Callback { public boolean handleMessage(Message msg); } public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }} 為你把關每一道 學習品質 378 378
  • 155. Android Thread運作機制-Looper與MQ • 透過obtainMessage可取得Message物件 • public final Message obtainMessage (int what, int arg1, int arg2, Object obj) • 取得Message與傳送Message至MQ中 Handler h = new Handler(){ public void handleMessage(Message msg){ //處理message } } h.removeMessage(0); h.obtainMessage(1,1,1,”my message); h.sendMessage(m); 為你把關每一道 學習品質 379 379
  • 156. Android Thread運作機制-Looper與MQ public static final void prepare() { • 替子執行緒產生Looper與MQ if (sThreadLocal.get() != null) { throw new RuntimeException( Class subThread implements Runnable{ "Only one Looper may be created public void run(){ per thread"); } Looper.prepare(); 框架原始碼 sThreadLocal.set(new Looper()); } h = new Handler(){ public handlerMessage(Message msg){ //處理message } }; private Looper() { Looper.loop(); 框架原始碼 mQueue = new MessageQueue(); mRun = true; } mThread = Thread.currentThread(); } } 為你把關每一道 學習品質 380 380
  • 157. Android Thread運作機制-Looper與MQ • 如何取得執行緒的Looper物件 • Looper.myLooper () 可用來取得目前執行緒的Looper • Looper. getMainLooper() 可用來取得主執行緒的Looper • 如何控制Handler所要接收的Looper? • 指定接收處理子執行緒Message Handler mHandler = new Handler(Looper.myLooper()){ public void handleMessage(Message msg){ //不可控制UI } }; • 指定接收處理主執行緒Message(Current Thread) Handler mHandler = new Handler(Looper.getMainLooper()){ public void handleMessage(Message msg){ //可控制UI } }; 為你把關每一道 學習品質 381 381
  • 158. 範例練習 範例專案名: ex09_01_LooperMQ 練習目標:  了解Android Thread的運作流程原理  了解UI Thread的操作方式  學習使用Handler操作 程式撰寫  建立Thread並指定給Looper與MQ,主執行緒透 過Looper與MQ與子執行緒進行雙向溝通 操作練習  透過模擬器操作練習 為你把關每一道 學習品質 382 382
  • 159. 如何變更UI Thread內容 • 在Android中非UI Thread是不能直接去控制UI,一但違反此 條件,系統將會強制將應用程式結束。 • UI Thread應盡量保持暢通,User所有的操作處理皆必須在 五秒之內回應,若有超過5秒的處理需求,必須使用Thread將 其切割出去處理。 • 在Android子執行緒要進入UI Thread去變更UI內容,有以下 的四種方法 • 透過掛Handler Push Message/Runnable於UI Thread 處理UI內容 • 透過Activity.runOnUIThread(),直接指定進入UI Thread內處理 • 透過View.Post(Runnable)介面處理 • 透過AsncTask類別協助處理,此為Android官方建議的最佳方案,需 1.5版後的Android才有支援。 為你把關每一道 學習品質 383 383
  • 160. 如何變更UI Thread內容-使用Handler • 透過Handler Push訊息至UI Thread • Handler.post(Runnable r); • Handler.postDelayed(Runnable r, long uptimeMillis) • Handler.sendMessage(Message msg); • Handler.sendMessageDelayed(Message msg, long delayMillis) • Handler可Post Runnable介面 • 在此指的Runnable介面與Thread無關,只是單純的 CallBack Function. 為你把關每一道 學習品質 384 384
  • 161. 如何變更UI Thread內容-使用Handler Public void onClick(View V){ Public class mainHandler extends switch(v.getId()){ Handler{ case 101: public mainHandler() { Handler sh = new subHandler(mLooper); super(Looper.getMainLooper());} Message m=sh.obtainMessage(1,33,1,null); public void handleMessage( sh.sendMessage(m); Message msg){ break; setTitle(" " +msg.arg1); } } } } Class myThread extends Thread{ Public class subHandler extends Handler{ pubic void run(){ public subHandler( Looper lp) Looper.prepare(); { super(lp); } mLooper = Looper.myLooper(); public void handleMessage(Message msg){ Looper.loop(); value += msg.arg1; } Handler ha = new mainHandler(); } Message m = ha.obtainMessage(1,value,1,null) ha.sendMessage(m); 為你把關每一道 學習品質 } 385 385 }
  • 162. 如何變更UI Thread內容-使用Activity.runOnUIThread 使用Activity.runOnUIThread實作閃爍文字 TimerTask taskcc = new TimerTask() { public void run() { runOnUiThread(new Runnable() { public void run() { if (clo == 1) { clo = 0; touchScreen.setTextColor(Color.RED); } else { clo = 1; touchScreen.setTextColor(Color.GREEN); } } } }); } }; //第二個參數代表的是delay, 第三個則是間隔多久 timer.schedule(taskcc, 1, 300); 為你把關每一道 學習品質 386 386
  • 163. 如何變更UI Thread內容-使用View.post • public classView extends Object • public boolean post (Runnable action) • 此函式會將Runnable物件Push至main Thread的MQ中 • Runnable的run method將會在UI Thread被呼叫執行 public void onClick(View v) { new Thread(new Runnable() { public void run() { //子執行緒進行長時間的 io讀取圖片 final Bitmap bmap = loadImageFromNetwork(); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bmap); } }); } }).start();} 為你把關每一道 學習品質 387 387
  • 164. 如何變更UI Thread內容-使用AsyncTask類別 • AsyncTask 為Google在Android 1.5所提供的類別。 • 使用AsyncTask必須使用繼承的方式,物件的必須在UI Thread中被建立,並且只能使用一次。 • 可用泛型指定Params,Progress,Result三個主要參數的型別 • AsyncTask可覆寫的方法 • protected abstract Result doInBackground (Params... params) • protected final void publishProgress (Progress... values) • protected void onPostExecute (Result result) • protected void onPreExecute () • protected void onProgressUpdate (Progress... values) 為你把關每一道 學習品質 388 388
  • 165. 如何變更UI Thread內容-使用AsyncTask類別 • AsyncTask 與框架之間的運作流程圖 publishProgress(Progress... values) onProgressUpdate(Progress... values) doInBackground(Params... params) onPostExecute(Result result) onPreExecute() 1 Activity Main Thread Work Thread new AsyncTask().execute(); UI Thread Android 框架層 為你把關每一道 學習品質 389 389
  • 166. 如何變更UI Thread內容-使用asyncTask類別 public void onClick(View v) { new DownloadFilesTask().execute(url1, url2, url3) } private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } } 為你把關每一道 學習品質 390 390
  • 167. 正確的Thread使用觀念 • AsyncTask 於API中提到的四個注意事項 • The task instance must be created on the UI thread. • execute(Params…) must be invoked on the UI thread. • Do not call onPreExecute(),onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…) manually. • The task can be executed only once (an exception will be thrown if a second execution is attempted.) • Thread並非萬靈丹 • Thread並不能取代Services元件 • 在背景的Activity隨時都有可能被系統Kill掉,但Thread 可能還在繼續跑。 • Thread適用於短時間,一次性處理函式。 • 一般系統層級,需要長時間服務,與穩定性的,請使用 Services元件來 (IntentServices) 為你把關每一道 學習品質 391 391
  • 168. 範例練習 範例專案名: ex09_02_AsyncTaskExample 練習目標:  設計一個AsyncTask,可以協助背景處理網路下載網路 圖片。 程式撰寫  繼承AsyncTask類別,並覆寫底下的所有函式  撰寫一個Activity,並新增一個Button與ImageView元 件,點擊Button後會建立AsyncTask物件協助從網路 上下載一張圖片,在下載過程中於UI Thread顯示進度 完成後顯示於ImageView 操作練習  透過模擬器操作,練習時需連上Internet,並記得於 androidManifest.xml中加入Internet的使用權限 為你把關每一道 學習品質 392 392
  • 170. Android 系統元件應用 Android系統元件應用  感測器元件應用  GPS定位元件應用 網路元件應用  Http Client 394
  • 171. Android系統元件應用(GPS、感測器) • Android GPS定位服務位於android.location套件中,定位 服務元件為LocationManager。 • Android.location套件包含的類別 • Criteria (依條件動態選擇最佳化定位資料源) • LocationManager類別 (定位服務) • LocationProvider類別 (定位的資料源) • LocationListener介面 (定期接收回報) • Location類別 (回報的定位資料封裝) 為你把關每一道 學習品質 395 395
  • 172. Android系統元件應用(GPS、感測器) • Criteria (依條件動態選擇最佳化定位資料源) • Criteria建構方式 Criteria criteria = new Criteria(); • 設定定位精確度 • Criteria. ACCURACY_FINE 精確 • Criteria. ACCURACY_COARSE 模糊 public void setAccuracy (int accuracy) • 是否提供高度資訊 public void setAltitudeRequired (boolean altitudeRequired) • 是否提供方向資訊 public void setBearingRequired (boolean bearingRequired) 為你把關每一道 學習品質 396 396
  • 173. Android系統元件應用(GPS、感測器) • Criteria (依條件動態選擇最佳化定位資料源) • 是否允許使用付費的服務 public void setCostAllowed (boolean costAllowed) • 限定電池的消耗量 public void setPowerRequirement (int level) • Criteria. NO_REQUIREMENT 無 • Criteria. POWER_LOW 低 • Criteria.POWER_MEDIUM 中 • Criteria. POWER_HIGH 高 • 是否提供速度資訊 public void setSpeedRequired (boolean speedRequired) 為你把關每一道 學習品質 397 397
  • 174. Android系統元件應用(GPS、感測器) • LocationManager類別 (定位服務) • 取得LocationManagement元件 /*於Activity中呼叫*/ LocationManager lg=getSystemServices(Context.LOCATION_SERVICE); • 取得最佳的LocationProvier元件 public String getBestProvider (Criteria criteria, boolean enabledOnly) • 取得最後己知的GPS位址 public Location getLastKnownLocation (String provider) 為你把關每一道 學習品質 398 398
  • 175. Android系統元件應用(GPS、感測器) • LocationManager類別 (定位服務) • 依取得週期性回報GPS坐標 public void requestLocationUpdates (long minTime, float minDistance, Criteria criteria, LocationListener listener, Looper looper) • miniTime:最小回報間隔時間(毫秒) • miniDistance:最小回報距離間隔(公尺) • criteria:自動挑選最適當的Location Provider • Listener:接收回報座標資料的介面 • Looper:決定回報的函式要跑的Thread,若指定 null,則回報函式將跑在main Thread上。 為你把關每一道 學習品質 399 399
  • 176. Android系統元件應用(GPS、感測器) • LocationManager類別 (定位服務) • 只要求提供一次GPS座標回報 public void requestSingleUpdate (Criteria criteria, LocationListener listener, Looper looper) • criteria:自動挑選最適當的Location Provider • Listener:接收回報座標資料的介面 • Looper:決定回報的函式要跑的Thread,若指定 null,則回報函式將跑在main Thread上。 為你把關每一道 學習品質 400 400
  • 177. Android系統元件應用(GPS、感測器) • LocationProvider類別 (定位的資料源) • 抽像類別,無法自行以new建構,一般透過Criteria 類別來協助做最佳化的provider選擇。 • LocationListener介面 (定期接收回報) • 一組抽像的介面,用來接收來自LocationManager 的通知回報。此介面實作後需被註冊至 requestLocationUpdates(…); • 當服務被關閉 public abstract void onProviderDisabled (String provider) 為你把關每一道 學習品質 401 401
  • 178. Android系統元件應用(GPS、感測器) • LocationListener介面 (定期接收回報) • 當座標變更 public abstract void onLocationChanged (Location location) 函式 功能 location.getLatitude() 取得緯度 location.getlongitude() 取得經度 location.getAltitude() 取得高度 location.getAccuracy() 取得精確度 location.getTime() 取得時間 location.getSpeed() 取得速度 location.getBearing() 取得方向 為你把關每一道 學習品質 402 402
  • 179. Android系統元件應用(GPS、感測器) • LocationListener介面 (定期接收回報) • 當服務被打開 public abstract void onProviderEnabled (String provider) • 當服服狀態改變(如無法提供服務,或己回複服務) public abstract void onStatusChanged (String provider, int status, Bundle extras) • AVAILABLE • OUT_OF_SERVICE • TEMPORARILY_UNAVAILABLE 為你把關每一道 學習品質 403 403
  • 180. 範例練習 範例專案名: ex10_01_GPS定位服務 練習目標:  了解GPS定位服務的使用方式  了解如何設定自動最佳化的定位回報 程式撰寫  取得LocationManager元件  設置GPS Provider選擇條件,並依最佳化原則自 動選用  實作LocationListener 介面  向LocationManager註冊LocationListener  依回報座標所取得的資料,顯示於UI上 為你把關每一道 學習品質 404
  • 181. Sensor感測器使用 • Android提供了許多Sensor的支援,不同的手機所支援的 Sensor H/W會有所不同。 TYPE_ACCELEROMETER 加速度測器 TYPE_AMBIENT_TEMPERATURE 環境溫度感測器 TYPE_GRAVITY 重力感測器 TYPE_GYROSCOPE 陀螺儀感測器 TYPE_LIGHT 亮度感測器 TYPE_LINEAR_ACCELERATION 線性加速感測器 TYPE_MAGNETIC_FIELD 磁場感測器 TYPE_ORIENTATION 方位感測器 TYPE_PRESSURE 壓力感測器 TYPE_PROXIMITY 接近感測器 TYPE_RELATIVE_HUMIDITY 濕度感測器 TYPE_ROTATION_VECTOR 旋轉向量感測器 TYPE_TEMPERATURE 溫度感測器 為你把關每一道 學習品質 405 405
  • 182. Sensor感測器使用 • 感測器的資料欄位 • 加速感測器 TYPE_ACCELEROMETER • values[0]:Gx • values[1]:Gy • values[2]:Gz Z軸 Y軸 X軸 為你把關每一道 學習品質 406 406
  • 183. Sensor感測器使用 • 感測器的資料欄位 • 磁場感應器 TYPE_MAGNETIC_FIELD • values[0]:x軸 • values[1]:y軸 • values[2]:z軸 • 方向感測器 TYPE_ORIENTATION • values[0]:依Z軸旋轉與Y軸的夾角大小(度) • values[1]:依X軸旋轉與Z軸的夾角大小(度) • values[2]:依Y軸旋轉與Z軸的夾角大小(度) Z 軸 Y軸 X軸 為你把關每一道 學習品質 407
  • 184. Sensor感測器使用 • 感測器的資料欄位 • 溫度感測器 TYPE_TEMPERATURE • values[0]:溫度 • values[1]:無作用 • values[2]:無作用 為你把關每一道 學習品質 408
  • 185. mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); Sensor感測器使用 • 感測器API的使用操作流程 • 取得SensorManager系統服務元件 SensorManager manager=(SensorManager)getSystemServices(SENSER_SERVICE); • 實作SensorEventListener以取得感測器回報資料 • 當感測器精確度發生變化時呼叫 public abstract void onAccuracyChanged (int sensor, int accuracy) • 當感測器資料有變化時呼叫 public abstract void onSensorChanged (int sensor, float[] values) • 決定要使用的感測器種類 mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 為你把關每一道 學習品質 409 409
  • 186. mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); Sensor感測器使用 • 感測器API的使用操作流程 • 註冊Sensor監聽事件 public boolean registerListener (SensorEventListener listener, Sensor sensor, int rate) • listener: 監聽的事件介面 • sensor: 要監聽的sensor • rate: 延遲時間的精確度 rate 常數 延遲時間長度 SensorManager. SENSOR_DELAY_FASTEST 0ms SensorManager. SENSOR_DELAY_GAME 20ms SensorManager. SENSOR_DELAY_UI 60ms SensorManager. SENSOR_DELAY_NORMAL 200ms 為你把關每一道 學習品質 410 410
  • 187. 範例練習 範例專案名: ex10_02_Sensor 練習目標:  了解Sensor感測器的設定與取得資料的方式  了解不同感測器所代表的資料函義 程式撰寫  取得SensorManager元件  實作SensorEventListener介面  決定Sensor型態  註冊監聽的Sensor  取得回報的資料並顯示於UI上 為你把關每一道 學習品質 411
  • 188. Http client介紹 • GET 方法的實作範例 /*建立HttpClient物件*/ httpClient = new DefaultHttpClient(); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, password); httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds); /* 建立HTTP Get連線 */ HttpGet httpRequest = new HttpGet("http://url"); /* 發出HTTP request */ HttpResponse httpResponse = httpClient.execute(httpRequest); /* 確認response是否ok,狀態碼為200 ,並取得資料*/ if (httpResponse.getStatusLine().getStatusCode() == 200) { return httpResponse.getEntity().getContent(); } 為你把關每一道 學習品質 412 412
  • 189. Http client介紹 • POST 方法介紹 • POST方法用來向目的服務器發出請求,要求它接受被 附在請求後的物件。 • 呼叫HttpClient中的HttpPost與HttpGet類似,除了設置 HttpPost的物件與HttpGet有些不同之外,剩下的步驟 都差不多 • POST實作功能: • 向留言版或類似討論組發送訊息 • 提交數據資料,如將HTML表單的結果提交給Server • 透過附加操作來擴展資料庫內容 為你把關每一道 學習品質 413 413
  • 190. Http client介紹 • Post建置流程: • 建立HttpClient 的物件 • 依照連接方式建立連接物件(HttpPost)。在構造函數中傳入待連接 的URL位址。 • 利用NameValuePair類別來建立參數表單,該類別的建構式第一個 參數是參數名稱,第二參數是該參數的值 • 呼叫HttpPost的setEntity函式,將參數表單(NameValuePair)附加 上去。 • 呼叫第一步中創建好的HttpClient物件的execute 方法,並帶入第 二步中建立的HttpPost或HttpGet物件,以發送需求至Server端。 • HttpClient.execute會回傳HttpResponse物件,可用來判斷是否傳 送成功。 為你把關每一道 學習品質 414 414
  • 191. Http client介紹 • Post方法的實作範例: /*建立HttpClient物件*/ /* 建立HTTP PhttpClient = new DefaultHttpClient(); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, password); httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds); ost連線 */ HttpPost httpRequest = new HttpPost("http://url"); /* 建立NameValuePair[]陣列儲存傳送參數*/ List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("Name", "Value")); /* 將參數加載於HttpPost物件中 */ httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); /* 發出HTTP request */ HttpResponse httpResponse = httpClient.execute(httpRequest); /* 確認response是否ok,狀態碼為200 ,並取得資料*/ if (httpResponse.getStatusLine().getStatusCode() == 200) { return httpResponse.getEntity().getContent(); } 為你把關每一道 學習品質 415 415
  • 192. Android應用程式設計 • 透過HttpClient取得BmipImage public Bitmap getURLBitmap(URL imageUrl , ) { URL imageUrl = null; Bitmap bitmap = null; try { imageUrl = new URL("http://" + ipAddress + cgiImageCommand); } catch (MalformedURLException e) { e.printStackTrace(); } try { HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection(); conn.setRequestMethod("GET"); conn.setDoInput(true); conn.setRequestProperty("Authorization", "Basic "+ Base64Coder.encodeString(userName + ":" + password)); conn.connect(); InputStream is = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(is); is.close(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } 為你把關每一道 學習品質 416 416
  • 193. Http client介紹 • Http Cliet常見編碼問題: • Post Entity時需指定編碼格式為HTTP.UTF_8,因為預 設的編碼格式為ISO-8859-1在處理中文時會有亂碼狀況。 post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); • 接收response 資料時使用EntityUtils.toString()來進行 轉串轉換,該函式會依照Server回傳的header 資料來 判判需使用何種解碼類型。 String str = EntityUtils.toString(rp.getEntity()); 為你把關每一道 學習品質 417 417
  • 194. 範例練習 範例專案名: ex10_03 DroidCam 練習目標:  了解如何使用HttpClient存取網路資料  了解如何使用HttpClient與Servier進行認證動作 程式撰寫  透過HttpClient與IPCam進行連線登入  透過Http Get取得圖片  透過Http Post發送控制指令 為你把關每一道 學習品質 418 418
  • 195. Android應用程式設計 • IPCam Viewer 工作流程 • 建立新增編輯IPCam Viewer的Activity頁面 • 建立觀看IPcam Viwer的Activity頁面 • 撰寫AsyncTask類別,協助處理下載IPcam影像圖片的 工作 • 撰寫AsyncTask類別協助處理IPcam PT控制指令 • 整合頁面操作流程(開機進入Viewer頁面,透過Menu 新增Ipcam) • 撰寫程式邏輯,透過httpclient與ipcam進行連接,收送 ipcam cgi command。 為你把關每一道 學習品質 419 419
  • 196. Android遊戲設計 • 播放影像程式流程架構圖 將bitmapImage顯示於ImaveView 連至IPcam下載圖片更新 onProgressUpdate(Bitmap bitmap) publishProgress(Progress... values) doInBackground(Params... params) Httclient連線 onPreExecute() onDraw() Activity AsyncTask 為你把關每一道 學習品質 420 420
  • 197. Android遊戲設計 • 控制IPCam的流程架構 傳送控制PT 的CGI Command onPostExecute(Result result) doInBackground(Params... params) Httclient連線 onPreExecute() Excute() Activity AsyncTask 為你把關每一道 學習品質 421 421
  • 198. Http Client介紹 • Http Client主要提供的功能 • 實現了所有HTTP 的方法(GET,POST,PUT,HEAD ) • 支持自動轉向 • 支持HTTPS 協議 • 支持代理服務器等 • GET 方法的實作流程 • 建立HttpClient 的物件 • 依照連接方式建立連接物件(HttpGet)。 在構造函數中傳入待連接 的URL位址。 • 呼叫第一步中創建好的HttpClient物件的execute 方法,並帶入第 二步中建立的HttpPost或HttpGet物件,以發送需求至Server端。 • HttpClient.execute會回傳HttpResponse物件,可用來判斷是否傳 送成功。 • 對得到後的內容進行處理 為你把關每一道 學習品質 422 422
  • 200. Android 系統元件應用 Android多媒體元件  Camera元件應用  MediaPlay元件應用  VideoView元件應用  相片瀏覽與多點縮放實作 424
  • 201. 多媒體元件-Camera元件應用 • 使用Android相機功能主要由以下三個功能所組成 • 預覽 • 對焦 • 取得相片 • Camera預覽 • 利用android.hardware.Camera設定相機參數 • 以SurfaceView做為相機的preview繪圖區塊 • 需注意SurfaceView 不會直接處理 Surface 物件, 必須經過 SurfaceHolder 處理。 • 透過Camera.open()開啟camera並取得camer物件. 為你把關每一道 學習品質 425 425
  • 202. 多媒體元件-Camera元件應用 • 初始化SurfaceView private SurfaceHolder surfaceHolder; private SurfaceView surfacePreview; /* 取得SurfaceView元件實體物件 */ surfacePreview = (SurfaceView) findViewById(R.id.surfacePreview); /*取得surfaceHolder物件*/ surfaceHolder = surfacePreview.getHolder(); /* 註冊Surface.Callback函式實作 */ surfaceHolder.addCallback(this); /* 代表此surface不包含資料,資料將透過其它物件提供(Camera),在預覽較為流暢 */ surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 為你把關每一道 學習品質 426 426
  • 203. 多媒體元件-Camera元件應用 • 實作SurfaceHolder.Callback介面 /* 當Surface大小發生改變時被呼叫 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width,int height); /*Surface建立成功後會呼叫,在此進行Camera的初始化*/ @Override public void surfaceCreated(SurfaceHolder holder) /* SurfaceView元件被銷毀前進行資源的釋放回收 */ @Override public void surfaceDestroyed(SurfaceHolder holder) 為你把關每一道 學習品質 427 427
  • 204. 多媒體元件-Camera元件應用 • 開啟相機,並設定相機相關參數 /* 利用camera的靜態方法open取得camera物件 */ camera = Camera.open(); /* 取得Camera的設定參數物件 */ Camera.Parameters cameraParameters = camera.getParameters(); /* 照片的格式 */ cameraParameters.setPictureFormat(PixelFormat.JPEG); /* 設置為可自動對焦,只有在相機開啟時對一次焦 */ cameraParameters.setFocusMode("auto"); /* 將新的參數質設定到Camera物件中 */ camera.setParameters(cameraParameters); /* 調整鏡頭的方向*/ camera.setDisplayOrientation(90); 為你把關每一道 學習品質 428 428
  • 205. 多媒體元件-Camera元件應用 • 進行相機畫面預覽 camera.setPreviewDisplay(surfaceHolder); /* 開始預覽 */ camera.startPreview(); • 實作AutoFocusCallback (對焦成功時呼叫) /* 對焦Call back函式實作 */ autoFocusCallBack = new AutoFocusCallback() { @Override public void onAutoFocus(boolean paramBoolean, Camera paramCamera) { /* 如果對到焦了 */ if (paramBoolean) { /* 拍照 */ tackPicture(); } } }; 為你把關每一道 學習品質 429 429
  • 206. 多媒體元件-Camera元件應用 • 實作PictureCallback介面 (照相完成後由系統呼叫) /* JPEG格式相片,call back實作 */ private PictureCallback jpegPicturecallBack = new PictureCallback() { @Override public void onPictureTaken(byte[] paramArrayOfByte, Camera paramCamera) { Bitmap bm = BitmapFactory.decodeByteArray(paramArrayOfByte, 0, paramArrayOfByte.length); try { /* 建立IO串流 */ BufferedOutputStream bufferOutPut = new BufferedOutputStream( new FileOutputStream(PICTURE_SAVE_DIR)); /* 壓縮並儲存圖檔,壓縮轉檔 */ bm.compress(Bitmap.CompressFormat.JPEG, 80, bufferOutPut); bufferOutPut.flush(); bufferOutPut.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }; 為你把關每一道 學習品質 430 430
  • 207. 多媒體元件-Camera元件應用 • 呼叫拍照功能 camera.takePicture(shutterCallBack, rawPictureCallBack,jpegPicturecallBack); • 呼叫對焦功能 camera.autoFocus(autoFocusCallBack); 為你把關每一道 學習品質 431 431
  • 208. 範例練習 範例專案名: ex011_01_Camera 練習目標:  學習如何建立使用Camera元件進行預覽 、對焦、照相 程式撰寫  了解如何取得與使用camera物物進行相機參數設定。  了解如何建置SurfaceView進行快進繪圖,並做為相機預覽 繪圖區  了解如何使用AutoFocusCallback來進行對焦。 為你把關每一道 學習品質 432 432
  • 209. 多媒體元件-VideoView • Android提供了VideoView元件,透過它可以播放許多不同 格式的影片 • 於Layout XML中定義VideoView元件 為你把關每一道 學習品質 433 433
  • 210. 多媒體元件-VideoView • 指定來源的影片URI • 來至網路 Uri mUri = Uri.parse(editTextRtspUrl.getText().toString()) • 來至SD卡 Uri mUri=Uri.parse(Environment.getExternalStorageDirectory()+ "/xxxx.3gp"); • 來至系統索引的多媒體資料庫 Cursor cursor = this.getContentResolver().query( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null, null,null); cursor.moveToFirst(); int videoID = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.VideoColumns._ID)); Uri playVideo = Uri.withAppendedPath( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, String .valueOf(videoID)); 為你把關每一道 學習品質 434 434
  • 211. 多媒體元件-VideoView • 開始播放影片 private void playVideo(Uri uri) { /* 設定VideoView的來源片位址 */ videoView.setVideoURI(uri); /* 設定控制器掛載在Activity上 */ videoView.setMediaController(new MediaController(this)); /* 開始播放 */ videoView.start(); } • 取得播放開始事件 videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { } }); 為你把關每一道 學習品質 435 435
  • 212. 多媒體元件-VideoView • 取得播放結束事件 videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { } }); 為你把關每一道 學習品質 436 436
  • 213. 範例練習 範例專案名: ex011_02_VideoView 練習目標:  學習如何建立使用VideoView元件進行影片播放  學習如何在VideoView上播放不同資料來源的影 片(網路、SD卡、系統資料庫索引的資料) 程式撰寫  於Layout中放置VideoView元件。  指定URI影片資料來源  設置MediaController控制器  註冊監聽以得知影片開始與播放完畢事件 為你把關每一道 學習品質 437 437
  • 214. 多媒體元件-MediaPlayer元件 • MediaPlayer元件同時提供了Video與Audio解碼功能,許 多Android高階的多媒體元件(如VideoView)其底層皆是使 用MediaPlayer。 • Android MediaPlayer元件在2.0以前使用的是OpenCORE 多媒體框架,但由於其架構系統過於龐大複雜,因此在 2.0之開始改以架構較簡潔的Stagefright取代之。 • 相較於高階的元件(如VideoView),使用MediaPlayer元件 將可以有較高的自由控制性,MediaPlayer提供了許多的 事件,包含播放、停止、暫停、重置、指定影片大小.等 功能。 為你把關每一道 學習品質 438 438
  • 215. 多媒體元件-MediaPlayer元件 • MediaPlayer的建構方式 • 利用靜態create函式建構 public static MediaPlayer create (Context context, Uri uri) public static MediaPlayer create (Context context, int resid) public static MediaPlayer create (Context context, Uri uri, SurfaceHolder holder) • 透過new建構 MediaPlayer mediaPlayer = new MediaPlayer(); public void setDataSource (String path) public void setDataSource (FileDescriptor fd, long offset, long length) public void setDataSource (FileDescriptor fd) public void setDataSource (Context context, Uri uri) 為你把關每一道 學習品質 439 439
  • 216. 多媒體元件-MediaPlayer元件 • MediaPlayer播放控制流程 prepare() setDataSource() start() pause() prepareAsync() reset() stop() • MediaPlayer的Video畫面顯示 /* 設定SufaceView Callback介面 */ surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); /* 設定mediaplayer參數 */ mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDisplay(surfaceHolder); 為你把關每一道 學習品質 440 440
  • 217. 多媒體元件-MediaPlayer元件 • MediaPlayer的監聽事件 • OnCompletionListener • OnPrepareListener • OnErrorListener • OnBufferingUpdateListener • OnInfoListener • OnVideoSizeChangedListener • OnSeekCompleteListener • 播放進度的取得 /*取得總長度*/ mediaPlayer.getDuration(); /*取得目前播放的長度*/ mediaPlayer.getCurrentPosition(); 為你把關每一道 學習品質 441 441
  • 218. 範例練習 範例專案名: ex11_03_MediaPlayer 練習目標:  學習如何建立使用MediaPlayer元件進行影片播放  學習如何自行設置MediaControl元件  學習如何自行設置播放進度條 程式撰寫  設置Layout xml檔,自行定義播放控制元件與顯示元 件  設置Mediplayer所要播放的影片來源  播放影片控制  設置Thread進行播放進度更新. 為你把關每一道 學習品質 442 442
  • 219. 相片瀏覽器 • 相片瀏覽器基本功能需求 • 可支援多點觸控縮放 • 放大後可以移動圖片觀看局部部位 • 具等比例放大縮小圖片功能 • 具單點圖片二下自動進行局部放大或縮小 • 實作方式 • 使用WebView方式實作 • 使用ImageView方式實作 為你把關每一道 學習品質 443 443
  • 220. 相片瀏覽器 • 繼承ImageView元件,撰寫一隻具有touch與縮放功能的 ImageViewTouch元件 • 於XML Layout中放置ImageViewTouch元件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <it.sephiroth.android.library.imagezoom.ImageViewTouch android:id="@+id/imageView1" android:scaleType="fitCenter" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 為你把關每一道 學習品質 444 444
  • 221. 相片瀏覽器 • 於Activity中透過findViewbyID取得ImageViewTouch物件 參照 ImageViewTouch mImageView = (ImageViewTouch)findViewById( R.id.imageView1 ); • 設置要覽瀏的相片資料,(Bitmap物件) mImageView.setImageBitmapReset( bitmap, orientation, true ); 為你把關每一道 學習品質 445 445
  • 222. 範例練習 範例專案名: ex11_04_ 練習目標:  學習如何建立使用相片瀏覽元件  支援多點縮放  支援單點縮放  支援拖拉移動  自動置中與等比例縮放 為你把關每一道 學習品質 446 446
  • 224. Google API套件應用 Gppgle Map API Key申請 Google Map 應用程式開發 如何為APP簽署憑證 如何申請成為Google開發者 448
  • 225. 如何使用Google MAP • Google MAP API為一個獨立的add-on API,並沒 有直接被包含在Android Platform中. • 該API中主要由MapView與MapController組合而成,而由 於MapView會取得私人的地圖位置,因此在使用時需先於 Google上註冊取得APIKey才得以顯示出地圖畫面。 為你把關每一道 學習品質 449 449
  • 226. 申請Google Map API Key. • 要使用GoogleMaps必須先與Google申請一組經驗 證的API Key.一組Key可以同時應用在多個應用程 式。 • Step 1: 找到模擬器的金鑰 debug.keystore C:Documents and SettingsYour_PC_Name.android debug.keystore 喜好設定AndroidBuild • Step2: 利用keytool產生keystore與MD5編碼 keytool -list -alias androiddebugkey -keystore "C:Documents and SettingsYour_PC_Name.androiddebug.keystore" -storepass android - keypass android 為你把關每一道 學習品質 450 450
  • 227. 申請Google Map API Key. • Step3: 利用MD5取得Google API 金鑰 http://code.google.com/intl/zh-TW/android/maps-api-signup.html 輸入MD5編碼: 1C:6B:27:C8:B6:42:5B:BF:0C:DD:xx:xx:xx:xx:xx:xx 為你把關每一道 學習品質 451 451
  • 228. 申請Google Map API Key. • Step4: 登入google 帳號後取得API金鑰 為你把關每一道 學習品質 452 452
  • 229. 申請Google Map API Key. • Step5: 建立Google Map Android專案 • Step1 首先需要要先建立一個含Google Map API的模擬器 2. 3. 1. 為你把關每一道 學習品質 453 453
  • 230. 申請Google Map API Key. • Step2 建立新專案使用Google API Target AndroidMap 選擇Android API Target AndroidMap com.ittraining.gmap AndroidMap 7 為你把關每一道 學習品質 454 454
  • 231. 申請Google Map API Key. • Step3 修改Activity,改繼承至MapActivity 2. 1. 3. 為你把關每一道 學習品質 455 455
  • 232. 申請Google Map API Key. • Step4 修改AndroidManfest.xml 滙入套件與開放權限 2. 4. 3. 1. 2. 4. 3. 1. 為你把關每一道 學習品質 456 456
  • 233. 申請Google Map API Key. • Step5 加入MapView元件於main.xml layout中 為你把關每一道 學習品質 457 457
  • 234. 申請Google Map API Key. • Step7 執行測試 為你把關每一道 學習品質 458 458
  • 235. Google Map API應用 • 利用GPS座標取得地址 private String getLocationAddress(GeoPoint point){ String add = ""; Geocoder geoCoder = new Geocoder(getBaseContext(),Locale.getDefault()); try { List<Address> addresses = geoCoder.getFromLocation( point.getLatitudeE6() / 1E6, point.getLongitudeE6() / 1E6, 1); Address address = addresses.get(0); int maxLine = address.getMaxAddressLineIndex(); if(maxLine >= 2){ add = address.getAddressLine(1) + address.getAddressLine(2); }else { add = address.getAddressLine(1); } } catch (IOException e) { e.printStackTrace(); } return add; } 為你把關每一道 學習品質 459 459
  • 236. 範例練習 範例專案名: ex12_01 GoogleMap 練習目標:  了解如何使用使用GoogleMap API  學習如何使將圖層繪製在Google Map地圖上 程式撰寫  設計Layout XML,使用GoogleMapView元件.  取得loactionGPS服務,並註冊定期接收定位回 報資料。  實作ItemizedOverlay介面,並新增OverlayIte於 MAP中 為你把關每一道 學習品質 460 460
  • 237. 申請成為Android開發人員 • Step 01: 進入Android Developer網站,並點擊右側Publish底下的 Learn more連結。 為你把關每一道 學習品質 461 461
  • 238. 申請成為Android開發人員 • Step 02: 利用Google 帳號登入,並填寫個人資料 為你把關每一道 學習品質 462 462
  • 239. 申請成為Android開發人員 • Step 03: 註冊費用為25美金,並提供Google Checkout付費方式。 請點繼續進鈕進入付費流程 為你把關每一道 學習品質 463 463
  • 240. 申請成為Android開發人員 • Step 04: 確認帳單資料,並再次輸入Google密碼登入 為你把關每一道 學習品質 464 464
  • 241. 申請成為Android開發人員 • Step 05: 新增信用卡付款,輸入卡號與個人資料,完成付款流程。 為你把關每一道 學習品質 465 465
  • 242. 申請成為Android開發人員 • Step 06: 確認付款完成,點選Andorid Market開發人員網站,以完 成註冊手續。。 為你把關每一道 學習品質 466 466
  • 243. 申請成為Android開發人員 • Step 07: 同發人員協議書確認,請扣選同意,並點選繼續鈕。 為你把關每一道 學習品質 467 467
  • 244. 申請成為Android開發人員 • Step 08: 完成註冊,點選上傳應用程式,開始上傳你的APP軟體。 為你把關每一道 學習品質 468 468
  • 245. 申請成為Android開發人員 • Step 09: 上傳發布應用程: 為你把關每一道 學習品質 469 469
  • 248. 如何為APP申簽署憑證 • Step 1: 利用keytool產生憑證檔 keytool -genkey -v -keystore JareyMobile.keystore -alias JareyMobile -keyalg RSA - validity 10000 為你把關每一道 學習品質 472 472
  • 249. 如何為APP申簽署憑證 • Step 2: 於Eclipse中選擇要簽署憑證的專案,於功能選單 中執行Export Signed Application Package. 為你把關每一道 學習品質 473 473
  • 250. 如何為APP申簽署憑證 • Step 3: 確認專案名稱,並指定keystore檔檔路徑與密碼 為你把關每一道 學習品質 474 474
  • 251. 如何為APP申簽署憑證 • Step 4: 選擇Key Alias名稱並輸入密碼。最後指定滙出的 具有簽署憑證的APK檔路徑。 為你把關每一道 學習品質 475 475
  • 252. 第14節: Android UI設計模式 第三方套件應用
  • 253. Google API套件應用 Gppgle Map API Key申請 Google Map 應用程式開發 如何為APP簽署憑證 如何申請成為Google開發者 477
  • 254. Android 專案設計方向 • 手機受限於螢布大小限制,不如PC般適合透過Browser頁 面來存取吸收豐富的網路資源。 • 手機應用程式主要的工作就是在於重新收集整理網路上的 資料,並在重新排版成適合手機操作與瀏覽的介面。 • 手機應用程式的組成結構 • 經組織整理過的Content資料內容 • Internet Services • 良好的使用者介面 • Content • 一個好的應用程式,Content可以說是很重要的關鍵, 由於一般的網路資訊是過於雜亂的,用戶透過手機必 須要經過很多道關卡步聚才能取得想要的資訊。因此 將Content重新組織整理將可以提供更穩定與有價質的 資訊給手機用戶。 為你把關每一道 學習品質 478 478
  • 255. Android 專案設計方向 • Internet Services • 網路是手機與外界溝通最佳的管道,而目前網路資訊 最豐富的莫過於www,透過http可以取得網路上各式 各樣的資訊與資料,但要手機同時對外去與那麼多的 services做連線與存取資料,其穩定性與效能是有問題 的。因此一般需要自己建立一個雲端的Services來提 供單一有效率的連線服務。而自建的services在與自己 整理的content資料做連接。 • 使用介面 • 手機的操作介面與一般的應用程式設計不同,良好的 操作介面將有助於使用者更方便快速的取得所要的資 訊。手機的操作介面將盡量保持與Android系統相近的 操作風格,這將有助於減少用戶重新學習與猜惻新UI 的使用方式。 為你把關每一道 學習品質 479 479
  • 256. Android 專案設計方向 • 設計實用的應用程式的思考方向 • 原始資料來源是否雜亂且沒有標準? • 是否能為資料重新整理出一套新標準? • 是不需要使用到雲端伺服器? • 是否需要使用到大量資料的Query與分析? • 是否為生常生活中經常需要使用到的應用? 為你把關每一道 學習品質 480 480
  • 257. Android 專案設計方向 • 手機應用程式基本開發步驟 • 功能定義 • UI介面設計 • 資料操作和儲存結構 • UI頁面切換流程動線規劃 • 程式架構設計規劃 • 考量是否需要Services與APPWidget應用程式 • 後端Server應用程式建置 • 完成程式細節功能調整 • 測試與驗證程式 • 發布到Android Market 為你把關每一道 學習品質 481 481
  • 258. Android的UI設計模式 • Android UI Design Pattern • 為Google在2010的GoogleIO中所提出的概念 • Android UI設計的原則 • Clear vs.“simple” • Content vs. chrome • Consistent yet engaging (elegant variation) • Enhanced by cloud • 5種UI Pattern • Dashboard • Action Bar • Search Bar • Quick Actions • Companion Widget 為你把關每一道 學習品質 482 482
  • 259. Android的UI設計模式 • Dashboard • A quick intro to an app, revealing capabilities and proactively highlighting new content • Full-screen • Can be organized by: • Features • Categories • Accounts • Recommendations • DO highlight what’s new • DO focus on 3-6 most important choices • DO be flavorful 483 483
  • 260. Android的UI設計模式 • Action Bar • Dedicated real estate at top of the screen to support navigation and frequently used operations • Replaces title bar • Best for actions common across your app • Search • Refresh • Compose (new) • Can provide a quick link back to dashboard (or other app home) • Recommendations • DO use to bring key actions onscreen • DO help to convey a sense of place • DO use consistently within your app • DON’T use for contextual actions 484
  • 261. Android的UI設計模式 • Quick Actions • Action popup triggered from distinct visual target • Minimally disruptive to screen context • Actions are straightforward • Fast & fun • Recommendations • DO use when items have competing internal targets • DO present only the for most important and obvious actions • DO use when the item doesn’t have a meaningful detail view • DON’T use in contexts which support multiple selection 485 485
  • 262. Android的UI設計模式 • Search Bar • Consistent pop-in search form anchored to top of screen • Replaces action bar (if present) • Support suggestions • Can use corpora selector to alter search mode Alternately, can offer suggestions for primary search mode,and additional items for triggering other modes • Recommendations • DO use for simple searches • DO present rich suggestions • DO use the same behavior 486
  • 263. Android的UI設計模式 • Companion Widget • Supports the app by displaying its content and capabilities on the Home screen • Makes Home feel more custom, personalized • Recommendations • DO provide value above a simple app icon (content) • DON’TDO handoff to the full app for real tasks • DO be space efficient • just provide a larger app launcher 487 487
  • 264. Android的UI設計模式 • 完整的應用程式UI流程圖 • Android UI Desgin Pattern的線上學習網站 • http://www.androidpatterns.com/ 488 488
  • 265. Android的UI設計模式 • 線上資源參考 • Iconfinder :Icon 圖檔搜尋引擎 • http://www.iconfinder.com/ • Android UI Desgin Pattern的線上學習網站 • http://www.androidpatterns.com/ • balsamiq mockups:UI模式設計器 • http://www.balsamiq.com/ • 大予創意部落格:GUI多媒體互動設計 • http://aja-creative.blogspot.com/ • UIPatterns:專業UI配色與模版設計 • http://ui-patterns.com/explore 489 489
  • 266. 第三方套件應用 Android 相關第三方Lib應用  GreenDroid  Asmack  Viewflow  ViewBadger  Pulltorefresh  Android-uitableview  ActionBarSherlock  NewQuickAction3D  ListViewTipsAndTicks  cwac-touchlist  Shared_DragAndDrop  cwac-AdapterWrapper 490
  • 267. 開發式UI函式庫-Asmack • Asmack為XMPP應用於android的client端 函式庫,XMPP為一套標準的IM通訊協定, 包含Google Talk在內有許多IM即時通訊軟 體皆支援XMPP協定。 • XMPP連線 public static XMPPConnection getConnection(String domain,int port) throws XMPPExcep tion { ConnectionConfiguration config = new ConnectionConfiguration(domain,port); XMPPConnection connection = new XMPPConnection(config); connection.connect(); return connection; } 491
  • 268. 開發式UI函式庫-Asmack • XMPP登入 XMPPConnection connection=getConnection(); connection.login("jareyxxxx@gmail.com", "*****"); • XMPP斷線 XMPPConnection connection=getConnection(); connection.disconnect(); • 發送訊息 Message msg = new Message(“xxxxx@gmail.com”, Message.Type.chat); msg.setBody(“Hello”); connection.sendPacket(msg); 492
  • 269. 開發式UI函式庫-Asmack • XMPP接收訊息監聽 PacketFilter filter = new MessageTypeFilter(Message.Type.chat); connection.addPacketListener(new PacketListener() { public void processPacket(Packet packet) { Message message = (Message) packet; if (message.getBody() != null) { String fromName = StringUtils.parseBareAddress(message.getFrom()); messages.add(fromName + ":"); messages.add(message.getBody()); mHandler.post(new Runnable() { public void run() { setListAdapter(); } }); } } }, filter); 493 493
  • 270. 範例練習 範例專案名: ex13_01 GoogleTalk 練習目標:  了解如何使用Asmack套件  利用Asmack與GoogleTalk Server連線 程式撰寫  使用Asmack撰寫一簡易的聊天程式,兩個用戶 可以透過Google Talk傳送訊息。 為你把關每一道 學習品質 494 494
  • 271. 開發式UI函式庫-GreenDroid • GitHub位址 • https://github.com/cyrilmottier/GreenDroid • UI畫面截圖 495 495
  • 272. 開發式UI函式庫-GreenDroid • • GreenDroid為一個開放式的Android UI函 式庫,主要提供許多標準的UI Pattern應 用模組,可以簡化許多UI開發的繁鎖的工 作。 • 可提供的模組 • SegmentedBar • ActionBarActivity • QuickAction • AsyncImageView • Tweaked ItemViews 496 496
  • 273. 範例練習 範例專案名: ex13_02 GreenDroid 練習目標:  了解如何使用GreenDroid套件  練習ActionBar的建立與使用方式 程式撰寫  開新專案並指定使用GreenDroid為其外部函式庫 連結  練習撰寫使用ActionBard 為你把關每一道 學習品質 497 497
  • 274. 開發式UI函式庫-Viewflow • GitHub位址 • https://github.com/pakerfeldt/android-viewflow • UI畫面截圖 498 498
  • 275. 開發式UI函式庫-Viewflow • Viewflow函式庫提供一個可以水平左右 滑動的頁面切換器 • 於Layout XML中加入Viewflow元件 <org.taptwo.android.widget.ViewFlow android:duplicateParentState="true" android:id="@+id/viewflow" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <org.taptwo.android.widget.TitleFlowIndicator android:id="@+id/viewflowindic" android:layout_height="wrap_content" android:layout_width="fill_parent" app:footerLineHeight="2" app:footerTriangleHeight="10" app:textColor="#FFFFFFFF" app:selectedColor="#FFFFC445" app:footerColor="#FFFFC445" app:titlePadding="10" app:textSize="13" android:layout_marginTop="10dip" 499 499 />
  • 276. 開發式UI函式庫-Viewflow • 使用ViewFlow ViewFlow viewFlow = (ViewFlow) findViewById(R.id.viewflow); AndroidVersionAdapter adapter = new AndroidVersionAdapter(this); viewFlow.setAdapter(adapter); TitleFlowIndicator indicator = (TitleFlowIndicator) findViewById(R.id.viewflowindic); indicator.setTitleProvider(adapter); viewFlow.setFlowIndicator(indicator); 500 500
  • 277. 範例練習 範例專案名: ex13_03 Viewflow 練習目標:  了解如何使用Viewflow套件 程式撰寫  使用Viewflow套件導入UI設計。 為你把關每一道 學習品質 501 501
  • 278. 開發式UI函式庫-Viewbadger • GitHub位址 • https://github.com/thiagolocatelli/android- uitableview • UI畫面截圖 502 502
  • 279. 開發式UI函式庫-Pulltorefresh • GitHub位址 • https://github.com/johannilsson/android- pulltorefresh • UI畫面截圖 503 503
  • 280. 開發式UI函式庫-uitableview • GitHub位址 • https://github.com/thiagolocatelli/android- uitableview • UI畫面截圖 504 504
  • 281. 開發式UI函式庫-ActionBarSherlock • GitHub位址 • https://github.com/lorensiuswlt/ActionBarS herlock • UI畫面截圖 505 505
  • 282. 開發式UI函式庫-NewQuickAction3D • GitHub位址 • https://github.com/lorensiuswlt/NewQuickA ction3D • UI畫面截圖 506 506
  • 283. 開發式UI函式庫-ListViewTipsAndTicks • GitHub位址 • https://github.com/cyrilmottier/ListViewTipsA ndTricks • UI畫面截圖 507 507
  • 284. 開發式UI函式庫-cwac-touchlist • GitHub位址 • https://github.com/commonsguy/cwac- touchlist • UI畫面截圖 508 508
  • 285. 開發式UI函式庫-Shared_DragAndDrop • GitHub位址 • https://github.com/teslacoil/Shared_DragAnd Drop • UI畫面截圖 509 509
  • 286. 開發式UI函式庫-cwac-AdapterWrapper • GitHub位址 • https://github.com/commonsguy/cwac- adapter • UI畫面截圖 510 510
  • 287. 開發式UI函式庫-Workspace Widget • 下載網址 • http://blog.sephiroth.it/2011/11/01/android- workspace-widget/ • UI畫面截圖 511 511