android開發-介面設計基本知識Ⅳ,android介面設計
上一章講述了Android介面開發中的Widget,Service,BroadcastReceiver基本知識點,本章以一個實際案例-後台音樂播放器解析各個知識點之間的關係。
1.功能需求
做一個Android音樂播放器
- 用到Service、Broadcast Receiver、Widget
- 使用後台服務播放音樂
- 做一個音樂播放的Widget
- 顯示歌曲名
- 顯示上一首、下一首、播放、暫停
2.軟體實現
圖1
圖2
圖3
簡易說明
長按手機介面出現2所示資訊,彈出小組件選項,點擊進入小組件1。選擇極客班-作業四,根據提示拖放介面到案頭,出現3所示音樂播放介面。點擊按鈕可實現音樂切換播放歌曲功能。
3.實現流程
後台音樂播放器主要是通過Widget的特性,用廣播為通道,完成Widget與Service之間的互動。
Widget:更新案頭資訊,發送廣播資訊,接收使用者操作事件。
Service:註冊服務,接收廣播資訊,發送廣播資訊。
4.介面布局
音樂播放器在介面布局和設定檔中主要包括以下方面:
- appwidget-provider提供了案頭widget的初始化顯示狀態、預設表徵圖、大小等功能,它放在res/xml檔案夾下,參考項目中的music_app_widget_info.xml檔案。
- android:initialLayout="@layout/music_app_widget":這個就是指定初始化顯示時,應該顯示的布局,參考項目中的music_app_widget.xml檔案。
- 項目應用了服務,廣播,須在AndroidManifest.xml中配置相應的標籤。具體資訊參考項目中的AndroidManifest.xml檔案。
5.核心程式碼分析(1)Widget函數-onUpdate()
在使用者添加Widget時,會調用OnUpdate()函數,在OnUpdate()中要實現綁定RemoteView和更新Widget的操作。在繫結控制項時,主要應用了PendingIntent的方式。
PendingIntent 是Intent的封裝,在構造PendingIntent前,也要先構造一個Intent,並可以利用Intent 的屬性傳進去action,Extra等,同樣,在接收時,對方依然是接收Intent的,而不是接收PaddingIntent。
PendingIntent.getBroadcast(context, 0,intent, 0);指從系統中擷取一個用於可以發送BroadcastReceiver廣播的PendingIntent對象。PendingIntent這個類用於 處理即將發生的事情。比如在通知Notification中用於跳轉頁面,但不是馬上跳轉。所以可以將它理解成一個封裝成訊息的intent的。即這個intent並不是立即start,而是像訊息一樣被發送出去,等接收方接到以後,再分析裡面的內容。項目相關代 碼摘抄如下:
1 private PendingIntent getPendingIntent(Context context, int buttonId) { 2 Intent intent = new Intent(); 3 intent.setClass(context, ExampleAppWidgetProvider.class); 4 intent.addCategory(Intent.CATEGORY_ALTERNATIVE); 5 intent.setData(Uri.parse("harvic:" + buttonId)); 6 PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0); 7 return pi; 8 } 9 10 // 更新所有的 widget11 private void pushUpdate(Context context,AppWidgetManager appWidgetManager,String songName,Boolean play_pause) {12 13 RemoteViews remoteView = new RemoteViews(context.getPackageName(),R.layout.music_app_widget);14 //將按鈕與點擊事件綁定15 remoteView.setOnClickPendingIntent(R.id.play_pause,getPendingIntent(context, R.id.play_pause));16 remoteView.setOnClickPendingIntent(R.id.prev_song, getPendingIntent(context, R.id.prev_song));17 remoteView.setOnClickPendingIntent(R.id.next_song, getPendingIntent(context, R.id.next_song));18 19 //設定內容20 if (!songName.equals("")) {21 remoteView.setTextViewText(R.id.song_name, songName);22 }23 //設定按鈕圖片24 if (play_pause) {25 remoteView.setImageViewResource(R.id.play_pause, R.drawable.button_stop);26 }else {27 remoteView.setImageViewResource(R.id.play_pause, R.drawable.button_on);28 }29 // 相當於獲得所有本程式建立的appwidget30 ComponentName componentName = new ComponentName(context,ExampleAppWidgetProvider.class);31 appWidgetManager.updateAppWidget(componentName, remoteView);32 }33 34 @Override35 public void onUpdate(Context context, AppWidgetManager appWidgetManager,36 int[] appWidgetIds) {37 38 pushUpdate(context,appWidgetManager,"",false);39 }Widget-onUpdate()(2)Widget函數-onReceive()
接收使用者操作,在接收時,首先根據目前使用者點擊的哪個按鈕,然後給MusicManageService發送不同的廣播(發送按鈕id),讓MusicManageService做出不同的響應,接收代碼如下 :
1 // 接收廣播的回呼函數 2 @Override 3 public void onReceive(Context context, Intent intent) { 4 String action = intent.getAction(); 5 Log.d("harvic", "action:"+action); 6 if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) { 7 Uri data = intent.getData(); 8 int buttonId = Integer.parseInt(data.getSchemeSpecificPart()); 9 switch (buttonId) {10 case R.id.play_pause:11 pushAction(context,MusicManageService.ACTION_PLAY_PAUSE);12 if(mStop){13 Intent startIntent = new Intent(context,MusicManageService.class);14 context.startService(startIntent);15 mStop = false;16 }17 break;18 case R.id.prev_song:19 pushAction(context, MusicManageService.ACTION_PRE);20 break;21 case R.id.next_song:22 pushAction(context, MusicManageService.ACTION_NEXT);23 break;24 }25 }else if (MAIN_UPDATE_UI.equals(action)){26 int play_pause = intent.getIntExtra(KEY_MAIN_ACTIVITY_UI_BTN, -1);27 String songid = intent.getStringExtra(KEY_MAIN_ACTIVITY_UI_TEXT);28 if(songid==null) songid="歌曲";29 switch (play_pause) {30 case VAL_UPDATE_UI_PLAY:31 pushUpdate(context, AppWidgetManager.getInstance(context), songid,true);32 break;33 case VAL_UPDATE_UI_PAUSE:34 pushUpdate(context, AppWidgetManager.getInstance(context), songid,false);35 break;36 default:37 break;38 }39 40 }41 42 super.onReceive(context, intent);43 }Widget-onReceive()(3)Widget發送廣播
//發送按鍵廣播 private void pushAction(Context context, int ACTION) { //發送目的服務 Intent actionIntent = new Intent(MusicManageService.ACTION); //發送參數 actionIntent.putExtra(MusicManageService.KEY_USR_ACTION, ACTION); context.sendBroadcast(actionIntent); }(4)Service註冊廣播
服 務要與按鈕相互動,在Service中一般是通過BroadcastReceiver來實現,所以在 MusicManageService的OnCreate函數中(Service起來的時候調用OnCreate)應該包括下面幾個步驟:註冊 Receiver。對應的項目代碼如下:
1 private BroadcastReceiver receiver = new BroadcastReceiver() { 2 @Override 3 public void onReceive(Context context, Intent intent) { 4 String action = intent.getAction(); 5 if (ACTION.equals(action)) { 6 int widget_action = intent.getIntExtra(KEY_USR_ACTION, -1); 7 switch (widget_action){ 8 case ACTION_PRE: 9 playPrev(context);Log.d("harvic","action_prev");break;10 case ACTION_PLAY_PAUSE:11 if (mPlayState) {12 pause(context);Log.d("harvic","action_pause");13 }else{14 play(context);Log.d("harvic","action_play");15 }16 break;17 case ACTION_NEXT:playNext(context);Log.d("harvic","action_next");break;18 default:break;19 }}20 }21 };22 @Override23 public void onCreate() {24 // TODO Auto-generated method stub25 super.onCreate();26 IntentFilter intentFilter = new IntentFilter();27 intentFilter.addAction(ACTION);28 //註冊服務29 registerReceiver(receiver, intentFilter);30 //載入歌曲31 initList();32 //播放預設歌曲33 mediaPlayerStart();34 }(5)歌曲定義
歌曲為本地歌曲檔案,放在項目的raw目錄下:
1 //歌曲播放 2 private void mediaPlayerStart(){ 3 mPlayer = new MediaPlayer(); 4 mPlayer = MediaPlayer.create(getApplicationContext(), mArrayList[mIndex]); 5 mPlayer.start(); 6 mPlayState = true; 7 //通過廣播發送當前播放狀態到Widget 8 postState(getApplicationContext(), ExampleAppWidgetProvider.VAL_UPDATE_UI_PLAY,mIndex); 9 }10 //歌曲初始化11 private void initList() {12 //歌曲路徑13 mArrayList[0] = R.raw.night_two;14 mArrayList[1] = R.raw.night_four;15 mArrayList[2] = R.raw.night_five;16 mArrayList[3] = R.raw.night_six;17 //歌曲名稱18 mArrayListName[0] ="石進-夜的鋼琴曲二";19 mArrayListName[1] = "石進-夜的鋼琴曲四";20 mArrayListName[2] ="石進-夜的鋼琴曲五";21 mArrayListName[3] = "石進-夜的鋼琴曲六";22 }(6)Service發送廣播
歌曲通過Widget不同按鈕切換髮送廣播到Service,Service通過播放功能函數(參考項目原始碼)做出相應的播放功能切換處理以後,就又一次發送一個廣播資訊回饋給Widget,Widget接收到廣播資訊後進行更新處理,項目代碼如下:
1 //回饋廣播資訊給Widget 2 private void postState(Context context, int state,int songid) { 3 //定義發送廣播接收者 4 Intent actionIntent = new Intent(ExampleAppWidgetProvider.MAIN_UPDATE_UI); 5 //定義歌曲播放狀態(播放/暫停) 6 actionIntent.putExtra(ExampleAppWidgetProvider.KEY_MAIN_ACTIVITY_UI_BTN,state); 7 //定義發送資訊(歌曲名稱) 8 actionIntent.putExtra(ExampleAppWidgetProvider.KEY_MAIN_ACTIVITY_UI_TEXT, mArrayListName[songid]); 9 context.sendBroadcast(actionIntent);10 }6.項目原始碼下載
本項目原始碼在360雲端硬碟上,開發環境為 Android Studio 2.0 beta 7。
https://yunpan.cn/cYamkZG3sq9jf 訪問密碼 f3d5