教育部補助資訊軟體人才培育先導計畫 100 年度課程發展專案計畫 實驗課程名稱 : IPC(Inter-Process Communication) 開發教師 : 張晉源老師 開發學生 : 林政揚 學校系所 : 樹德科技大學資訊工程學系

Similar documents
Android Service

多媒體應用 13 新增專案並完成版面配置 <ExMusic01> <activity_main.xml> ImageView ID imgplay ImageView ID imgstop ImageView ID imgfront TextView ID txtsong TextView ID t

用手機直接傳值不透過網頁連接, 來當作搖控器控制家電 ( 電視遙控器 ) 按下按鍵發送同時會回傳值來確定是否有送出 問題 :1. 應該是使用了太多 thread 導致在傳值上有問題 2. 一次按很多次按鈕沒辦法即時反應

res/layout 目录下的 main.xml 源码 : <?xml version="1.0" encoding="utf 8"?> <TabHost android:layout_height="fill_parent" xml

新・解きながら学ぶJava

單步除錯 (1/10) 打開 Android Studio, 點選 Start a new Android Studio project 建立專案 Application name 輸入 BMI 點下 Next 2 P a g e

Android Robert C.C. Huang Oscar F.Y. Liu Peter C.L. Hsieh 2011/03/21

主程式 : public class Main3Activity extends AppCompatActivity { ListView listview; // 先整理資料來源,listitem.xml 需要傳入三種資料 : 圖片 狗狗名字 狗狗生日 // 狗狗圖片 int[] pic =new

詞 彙 表 編 號 詞 彙 描 述 1 預 約 人 資 料 中 文 姓 名 英 文 姓 名 身 份 證 字 號 預 約 人 電 話 性 別 2 付 款 資 料 信 用 卡 別 信 用 卡 號 信 用 卡 有 效 日 期 3 住 房 條 件 入 住 日 期 退 房 日 期 人 數 房 間 數 量 入

建模与图形思考

中 文 摘 要 智 慧 型 手 機 由 於 有 強 大 的 功 能, 以 及 優 渥 的 便 利 性, 還 能 與 網 路 保 持 隨 時 的 鏈 結 與 同 步 更 新, 因 此 深 受 廣 大 消 費 者 喜 愛, 當 然, 手 機 遊 戲 也 成 為 現 代 人 不 可 或 缺 的 娛 樂 之

Microsoft PowerPoint - ch6 [相容模式]

ShareText

書面

Android Android Android SDK iv

Dynamic Layout in Android

Microsoft Word - GoF-ch06-8-AbsFactory-ok.doc

1: public class MyOutputStream implements AutoCloseable { 3: public void close() throws IOException { 4: throw new IOException(); 5: } 6:

EJB-Programming-4-cn.doc

0511-Android程式之GPS應用_專題週記4

Microsoft Word - 01.DOC

Java

雲端 Cloud Computing 技術指南 運算 應用 平台與架構 10/04/15 11:55:46 INFO 10/04/15 11:55:53 INFO 10/04/15 11:55:56 INFO 10/04/15 11:56:05 INFO 10/04/15 11:56:07 INFO

投影片 1

Android Fragment

01_Service

The golden pins of the PCI card can be oxidized after months or years

Microsoft Word - ASM SDK 說明文件

Microsoft Word - 第1章 Android基本概念.docx

1.JasperReport ireport JasperReport ireport JDK JDK JDK JDK ant ant...6

Chapter 9: Objects and Classes

Database_001

mvc

untitled

KillTest 质量更高 服务更好 学习资料 半年免费更新服务

untitled

建立Android新專案

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

预览图 : (2) 在 SelectCity.java 中增加控件, 用于绑定 select_city 文件的 ListView, TextView,EditTest 等控件 代码和注释如下 :

ContextMenu

Android 编程基础 Android 开发教程 & 笔记 1

概述

《大话设计模式》第一章

INTRODUCTION TO COM.DOC

Lecture01_Android介绍

EJB-Programming-3.PDF

Microsoft Word - 004_Android線程模式介紹.doc

JavaIO.PDF

Android + NFC

任務二 : 產生 20 個有炸彈的磚塊, 放在隨機的位置編輯 Block 類別的程式碼 import greenfoot.; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) Write a description of class

手说TTS开发指南

<ADB6ADB1C25EA8FAA6DB2D4D56432E706466>

epub83-1

2/14 Buffer I12, /* x=2, buffer = I 1 2 */ Buffer I243, /* x=34, buffer = I 2 43 */ x=56, buffer = I243 Buffer I243I265 code_int(int x, char *buffer)

Microsoft Word - 第3章.doc

<4D F736F F D FB1B5A4663F3FA4A7ACFC5FB371A5CEA9CAB1B5A466AABA3FA6583FA5CE5F6F6B2E646F63>

C/C++ - 字符输入输出和字符确认

RecyclerView and CardVew

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

ASP.NET MVC Visual Studio MVC MVC 範例 1-1 建立第一個 MVC 專案 Visual Studio MVC step 01 Visual Studio Web ASP.NET Web (.NET Framework) step 02 C:\M

BOOL EnumWindows(WNDENUMPROC lparam); lpenumfunc, LPARAM (Native Interface) PowerBuilder PowerBuilder PBNI 2

Lecture01_Android介绍

Microsoft Word - A _ doc

新版 明解C++入門編

Android 开发教程

Windows RTEMS 1 Danilliu MMI TCP/IP QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos eco

前言 C# C# C# C C# C# C# C# C# microservices C# More Effective C# More Effective C# C# C# C# Effective C# 50 C# C# 7 Effective vii

FY.DOC

untitled

建立Android新專案

Java Access 5-1 Server Client Client Server Server Client 5-2 DataInputStream Class java.io.datainptstream (extends) FilterInputStream InputStream Obj

09 (File Processes) (mkdir) 9-3 (createnewfile) 9-4 (write) 9-5 (read) 9-6 (deletefile) 9-7 (deletedir) (Exercises)

WebSphere Studio Application Developer IBM Portal Toolkit... 2/21 1. WebSphere Portal Portal WebSphere Application Server stopserver.bat -configfile..

Microsoft Word - 02.目錄.doc

附录J:Eclipse教程

untitled

目 錄 版 次 變 更 記 錄... 2 原 始 程 式 碼 類 型 之 使 用 手 冊... 3 一 安 裝 軟 體 套 件 事 前 準 備... 3 二 編 譯 流 程 說 明

chp6.ppt

IBM Rational ClearQuest Client for Eclipse 1/ IBM Rational ClearQuest Client for Ecl

RunPC2_.doc

ltu

Chapter 16 Widget 作者 : 林致孙 不少 Android 手機在使用者剛購買時, 手機的桌面上就已經有不少的小工具 (Widget), 有些可以即時顯示氣候資訊, 有些則可以顯示最新股票資訊 本章將 利用兩個例子來說明 Widget 是如何設計的 16.1 時辰顯示小工具 在 An

<4D F736F F F696E74202D20332D322E432B2BC3E6CFF2B6D4CFF3B3CCD0F2C9E8BCC6A1AAD6D8D4D8A1A2BCCCB3D0A1A2B6E0CCACBACDBEDBBACF2E707074>

X6-04_How_do_I_write_a_com_port_communicate_program_of_XPAC_tc

Microsoft Word zw

KillTest 质量更高 服务更好 学习资料 半年免费更新服务

Microsoft Word - 苹果脚本跟我学.doc

Microsoft PowerPoint - App與微控器整合.pptx

C6_ppt.PDF

KillTest 质量更高 服务更好 学习资料 半年免费更新服务

Important Notice SUNPLUS TECHNOLOGY CO. reserves the right to change this documentation without prior notice. Information provided by SUNPLUS TECHNOLO

chapter 2 HTML5 目錄iii HTML HTML HTML HTML HTML canvas

建模与图形思考

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc

图 6-1 主界面 MainActivity 界面对应的布局文件 (activity_main.xml) 如下所示 : <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="

内 容 提 要 将 JAVA 开 发 环 境 迁 移 到 Linux 系 统 上 是 现 在 很 多 公 司 的 现 实 想 法, 而 在 Linux 上 配 置 JAVA 开 发 环 境 是 步 入 Linux 下 JAVA 程 序 开 发 的 第 一 步, 本 文 图 文 并 茂 地 全 程 指

ii Vue Bootstrap 4 ES 6 Vue Vue Bootstrap 4 ES 6 Vue 2 vue html vue html vue Vue HTML 5 CSS ES 6 HTML 5 CSS Visual Studio Code h

Microsoft Word - edu-re~1.doc

Microsoft Word - 發布版---規範_全文_.doc

概 述 随 着 中 国 高 等 教 育 数 量 扩 张 目 标 的 逐 步 实 现, 提 高 教 育 质 量 的 重 要 性 日 益 凸 显 发 布 高 校 毕 业 生 就 业 质 量 年 度 报 告, 是 高 等 学 校 建 立 健 全 就 业 状 况 反 馈 机 制 引 导 高 校 优 化 招

Transcription:

教育部補助資訊軟體人才培育先導計畫 100 年度課程發展專案計畫 實驗課程名稱 : IPC(Inter-Process Communication) 開發教師 : 張晉源老師 開發學生 : 林政揚 (s11639104@stu.edu.tw) 學校系所 : 樹德科技大學資訊工程學系

實驗目的 本實驗的目的在於讓同學們可以了解 Android 系統核心內部的行程通訊的原理, 透過呼叫系統提供的其中一樣服務 (MediaPlayer), 來實作 IPC(Inter-Process Communication) 機制, 讓同學們可以對 IPC 的機制流程有更深刻的理解, 藉此可跟前幾章相做呼應 個人電腦 X 1 需求 : 個人電腦或筆記型電腦一部 目的 : 實作 IPC 機制程式 MP3 2 首 實驗器材 個人電腦 eclipse JDK SDK ADT 實驗所需軟體 實驗步驟簡述 創建專案 (1) 創建專案 MediaIPC 裡面包含兩支程式 MediaIPCActivity.java/ RemoteService.java (2) 創建專案 MediaClient 裡面包含 MediaClientActivity.java 實作 (1) 撰寫 RemoteService.java 內容 (2) main.xml 撰寫 (3) string.xml 撰寫 (4) AndroidManifest.xml 撰寫 (5) 撰寫 MediaIPCActivity.java 內容 (6) 撰寫 MediaClientActivity.java 內容 (7) 測試

Part I 基本知識 Binder 流程

Binder 架構 (MediaPlayer) 舉例 1 系統 Service 實例 Media server framework/base/media/mediaserver/main_mediaserver.cpp 檔案 : 19: int main(int argc, char** argv) 20: { 21: sp<processstate> proc(processstate::self()); 22: sp<iservicemanager> sm = defaultservicemanager(); 23: LOGI("ServiceManager: %p", sm.get()); 24: AudioFlinger::instantiate(); 25: MediaPlayerService::instantiate(); 26: CameraService::instantiate(); 27: AudioPolicyService::instantiate(); 28: ProcessState::self()->startThreadPool(); 29: IPCThreadState::self()->joinThreadPool(); 30: 1. 程式碼第 21 行建立一個 ProcessState 的參照, 但是這個物件後面並沒有被使用到, 那麼為什麼要建立呢? 教學的簡報上有提過, 如果一個行程要使用 Binder 機制, 那麼他的行程中必須要建立一個 ProcessState 物件來負責管理 Service 的代理對象 2. 第 22 行呼叫 defaultservicemanager() 取得一個 Service Manager 代理對象 3. 後面幾行都是實體化 Service 物件, 展開之後發現都是一些調用 Service Manager 的 addservice 進行註冊的函數, 以 AudioFlinger 為例,instantiate 如下 : 1: void AudioFlinger::instantiate() { 2: defaultservicemanager()->addservice( 3: String16("media.audio_flinger"), new AudioFlinger()); 4: 4. 最後呼叫 ProcessState 的 startthreadpool 方法和 IPCThreadState 的 jointhreadpool

使 Media Server 進入等待請求的循環當中 2 系統 Service 的基礎 BBinder 仔細查看一下 Media Server 中定義的四個 Service 將會發現它們都是繼承自 BBinder, 而 BBinder 又繼承自 IBinder 介面, 每個 Service 都覆寫了 BBinder 的 ontransact 函數, 當 Client 發送請求到達 Service 時, 將會呼叫 Service 的 ontransact 函數, 後面將會詳細的介紹這個機制 3 Service 註冊 每個 Service 都需要向 大管家 Service Manager 進行註冊, 呼叫 Service Manager 的 addservice 方法註冊 這樣 Service Manager 將會執行 Client 端查詢和獲取該 Service( 代理對象 ), 然後 Client 端就可以通過該 Service 的代理對象請求該 Service 的服務 4 Service 進入等待請求的循環 每個 Service 必須要進入死循環, 等待 Client 端請求的到達, 本例中最後兩句就是使 Service 進行等待請求的循環之中 ProcessState 的 startthreadpool 方法最終調用的也是 IPCThreadState 的 jointhreadpool 方法, 具體請查看程式碼 IPCThreadState 的 jointhreadpool 方法的程式碼如下 : 1: void IPCThreadState::joinThreadPool(bool ismain) 2: { 3:... 4: do { 5: int32_t cmd; 6: 7:... 8: 9: // now get the next command to be processed, waiting if necessary 10: result = talkwithdriver(); 11: if (result >= NO_ERROR) { 12:... 13: 14: result = executecommand(cmd); 15: 16: 17:... 18: while (result!= -ECONNREFUSED && result!= -EBADF); 19: 20:... 21: Service 在 IPCThreadState 的 jointhreadpool 方法中, 呼叫 talkwithdriver 方法和 Binder 驅動進行溝通, 讀取 Client 端的請求 當 Client 端請求到達之後呼叫 executecommand 方法進行處理

Service 怎樣處理客戶端的請求? 看一下 executecommand 方法的程式碼 : 1: status_t IPCThreadState::executeCommand(int32_t cmd) 2: { 3: BBinder* obj; 4: RefBase::weakref_type* refs; 5: status_t result = NO_ERROR; 6: 7: switch (cmd) { 8:... 9: case BR_TRANSACTION: 10: { 11:... 12: if (tr.target.ptr) { 13: sp<bbinder> b((bbinder*)tr.cookie); 14: const status_t error = b->transact(tr.code, buffer, &reply, 0); 15: if (error < NO_ERROR) reply.seterror(error); 16: 17: 18:... 19: 20: 21: 22:... 23: 24: 25: if (result!= NO_ERROR) { 26: mlasterror = result; 27: 28: 29: return result; 30: 可以看到 IPCThreadState 將會直接呼叫 BBinder 的 transact 方法來處理客戶端請求, 再看一下 BBinder 的 transact 方法 : 1: status_t BBinder::transact( 2: uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 3: { 4: data.setdataposition(0); 5: 6: status_t err = NO_ERROR; 7: switch (code) { 8: case PING_TRANSACTION:

9: reply->writeint32(pingbinder()); 10: 11: default: 12: err = ontransact(code, data, reply, flags); 13: 14: 15: 16: if (reply!= NULL) { 17: reply->setdataposition(0); 18: 19: 20: return err; 21: 發現它將會叫用自己的方法 ontransact 前面提到所有的 Service 都繼承自 BBinder, 並且都覆寫了 ontransact 虛函數 那麼 IPCThreadState 將會呼叫 Service 定義 ontransact 方法來處理客戶請求 Part II 放置音樂檔案及創建專案 Step 1 SDcard 放入所需檔案 放入兩個 mp3 檔案, 名稱分別為 music.mp3 music.mp3

Step 2 新增 MediaIPC 專案 File > New > Android Project( 新增一個 Android 專案 ) Project name : 為您的 Android 專案命名 Build Target : 選擇您剛剛所選的 Android 版本 (2.2) 設定方式 : Application Name: 請自行設定欲使用的名稱, 建議與本實習取相同名稱 MediaIPC Project Name: 預設會與 Application Name 相同 Package Name: 請不要使用預設的名稱, 建意將前述取名為各自學校的名稱 ( 可參考本範例 ) SDK 版本 : 請挑選 Android2.2 版 之後一直下一步, 直到 Finish, 無須再進行任何設定

Step 3 新增 RomteService 於左側欄中的 src -> stu.edu.mediaipc 按右鍵 new -> Class 並設定 class 名稱為 RomteService, 之後按下 Finish 即可 Step 4 新增 MediaClient 專案 依照前面的步驟再新增另一個專案, 叫 MediaClient 設定方式 : Application Name: 請自行設定欲使用的名稱, 建議與本實習取相同名稱 MediaClient Project Name: 預設會與 Application Name 相同 Package Name: 請不要使用預設的名稱, 建意將前述取名為各自學校的名稱 ( 可參考本範例 ) SDK 版本 : 請挑選 Android2.2 版 之後一直下一步, 直到 Finish, 無須再進行任何設定

Step 5 刪除兩者專案中不必要的 Menu 資料夾 此步驟請將 MediaIPC 及 MediaClient 專案中位於 res 內的 Menu 資料夾刪除, 因為此資 料夾內的檔案會與後續我們要增加的檔案有所衝突 Part III MediaIPC Project 撰寫 Step 1 string.xml 撰寫 string.xml 在創建專案時就一並會被創建出來, 在 res ->values 資料夾底下, 在這邊新增一些字串 <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">hello World, MediaIPCActivity!</string> <string name="app_name">mediaipc</string> <string name="remote_service_started">remoteservice started!!</string> <string name="remote_service_label">remoteservice label</string> <string name="remote_service_stopped">remoteservice stopped!!</string> </resources>

Step 2 activity_main.xml 撰寫 activity_main.xml 在創建專案時就一並會被創建出來, 在 res ->layout 資料夾底下, 在 這邊新增三個按鈕, 做播放 暫停及停止動作 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <Button android:id="@+id/start" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="start" /> <Button android:id="@+id/pause" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="pause" /> <Button android:id="@+id/stop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="stop" /> </LinearLayout> Step 3 RomteService.java MediaIPCActivity.java 檔先不動, 因為需要呼叫 RomteService.java 檔, 若先寫 MediaIPCActivity.java 則在撰寫的過程中會出現大量錯誤, 所以我們撰寫的順序稍微改變一下 宣告全域變數 (Global variables) 並將 RomteService 繼承 Service, 且實作 onbind package stu.edu.mediaipc; import java.io.ioexception; import android.app.notification; import android.app.notificationmanager; import android.app.pendingintent;

import android.app.service; import android.content.intent; import android.media.mediaplayer; import android.os.handler; import android.os.ibinder; import android.os.message; import android.os.messenger; import android.os.remoteexception; import android.util.log; import android.widget.toast; public class RomteService extends Service { private String path1 = "/sdcard/music1.mp3"; private String path2 = "/sdcard/music2.mp3"; private static final int SOUNG1 = 1; private static final int SOUNG2 = 2; private static final int PAUSE = 3; private static final int STOP = 4; /** For showing and hiding our notification. */ NotificationManager mnm; Messenger mclients ;// 紀錄 client 的 Messnger int mvalue = 0; MediaPlayer mp; /* * 下面是如何使用 Messenger 的概要 : * 1. Service 實作一個接收從 Client 端的每次請求時產生回應的 Handler * 2. Handler 被用來建立一個 Messenger 物件 ( 它是 Handler 的一個參照 ) * 3. Messenger 建立一個從 service 的 onbind() 返回給 Client 端的 IBinder * 4. 客戶端使用 IBinder 來實體化這個 Messenger( 它參照到 service 的 Handler) *,Client 端用它來向 service 發送 Message * 5. service 在它的 Handler 中接收每個消息 具體是在 handlemessage() 方法中 */ Messenger mmessenger = null;// 讓 client 可以對 service 溝通的 Messenger /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onbind(intent intent) {

Log.i("RemoteService", "onbind()"); return mmessenger.getbinder(); 撰寫一個方法 shownotification() 這方法是當 service 被創建時會做提醒的動作, 提醒 client 已經連線成功 /** * Show a notification while this service is running. */ private void shownotification() { CharSequence text = gettext(r.string.remote_service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis()); PendingIntent contentintent = PendingIntent.getActivity(this, 0, new Intent(this, MediaIPCActivity.class), 0); // Set the info for the views that show in the notification panel. notification.setlatesteventinfo(this, gettext(r.string.remote_service_label), text, contentintent); // Send the notification. // We use a string id because it is a unique number. We use it later to cancel. mnm.notify(r.string.remote_service_started, notification); 建立一個內隱類別 (inner class ), 繼承 Handler 覆寫 handlemessage () 方法, 將從 Client 端傳來的 Message 做處理 class IncomingHandler extends Handler { @Override public void handlemessage(message msg) { Message message = null; mclients = msg.replyto; try { switch (msg.what) { case SOUNG1: message = Message.obtain(null, SOUNG1); mp.reset(); mp.setdatasource(path1); mp.prepare(); mclients.send(message); mp.start();

case SOUNG2: message = Message.obtain(null, SOUNG2); mp.reset(); mp.setdatasource(path2); mp.prepare(); mp.start(); mclients.send(message); case STOP: message = Message.obtain(null, STOP); mp.stop(); mclients.send(message); case PAUSE: message = Message.obtain(null, PAUSE); mp.pause(); mclients.send(message); catch (IllegalArgumentException e) { e.printstacktrace(); catch (IllegalStateException e) { e.printstacktrace(); catch (IOException e) { e.printstacktrace(); catch (RemoteException e) { e.printstacktrace(); Service 生命週期 : oncreate() -> onstart() -> ondestroy(), 由於本範例沒用到 onstart() 因此沒有做覆寫動作, 這邊做的是將提醒框以及 Media Player 做關閉動作 覆寫 oncrate() @Override public void oncreate() { Log.i("RemoteService", "oncreate()"); mnm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); mp = new MediaPlayer();

shownotification(); // Display a notification 覆寫 ondestroy() @Override public void ondestroy() { Log.i("RemoteService", "ondestroy()"); // Cancel the persistent notification. mnm.cancel(r.string.remote_service_started); mp.reset(); mp.release(); // Tell the user we stopped. Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show(); 附註 : RomteService.java 檔完成之 source code 如下所示 : package stu.edu.mediaipc; import java.io.ioexception; import android.app.notification; import android.app.notificationmanager; import android.app.pendingintent; import android.app.service; import android.content.intent; import android.media.mediaplayer; import android.os.handler; import android.os.ibinder; import android.os.message; import android.os.messenger; import android.os.remoteexception; import android.util.log; import android.widget.toast; public class RomteService extends Service { private String path1 = "/sdcard/music1.mp3"; private String path2 = "/sdcard/music2.mp3"; private static final int SOUNG1 = 1; private static final int SOUNG2 = 2;

private static final int PAUSE = 3; private static final int STOP = 4; /** For showing and hiding our notification. */ NotificationManager mnm; Messenger mclients ;// 紀錄 client 的 Messnger int mvalue = 0; MediaPlayer mp; Messenger mmessenger = null;// 讓 client 可以對 service 溝通的 Messenger /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onbind(intent intent) { Log.i("RemoteService", "onbind()"); return mmessenger.getbinder(); /** * Show a notification while this service is running. */ private void shownotification() { CharSequence text = gettext(r.string.remote_service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis()); PendingIntent contentintent = PendingIntent.getActivity(this, 0, new Intent(this, MediaIPCActivity.class), 0); // Set the info for the views that show in the notification panel. notification.setlatesteventinfo(this, gettext(r.string.remote_service_label), text, contentintent); // Send the notification. // We use a string id because it is a unique number. We use it later to cancel. mnm.notify(r.string.remote_service_started, notification);

@Override public void oncreate() { if (mmessenger == null) { mmessenger = new Messenger(new IncomingHandler()); Log.i("RemoteService", "oncreate()"); mnm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); mp = new MediaPlayer(); shownotification(); // Display a notification @Override public void ondestroy() { Log.i("RemoteService", "ondestroy()"); // Cancel the persistent notification. mnm.cancel(r.string.remote_service_started); mp.reset(); mp.release(); // Tell the user we stopped. Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show(); class IncomingHandler extends Handler { @Override public void handlemessage(message msg) { Message message = null; mclients = msg.replyto; try { switch (msg.what) { case SOUNG1: message = Message.obtain(null, SOUNG1); mp.reset(); mp.setdatasource(path1); mp.prepare(); mclients.send(message); mp.start();

case SOUNG2: message = Message.obtain(null, SOUNG2); mp.reset(); mp.setdatasource(path2); mp.prepare(); mp.start(); mclients.send(message); case STOP: message = Message.obtain(null, STOP); mp.stop(); mclients.send(message); case PAUSE: message = Message.obtain(null, PAUSE); mp.pause(); mclients.send(message); catch (IllegalArgumentException e) { e.printstacktrace(); catch (IllegalStateException e) { e.printstacktrace(); catch (IOException e) { e.printstacktrace(); catch (RemoteException e) { e.printstacktrace(); Step 4 AndroidManifest.xml 撰寫這邊是在做權限設定以及 service 的相關設定, 如果沒做這些設定程式將會無法執行 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="stu.edu.mediaipc"

android:versioncode="1" android:versionname="1.0" > <uses-sdk android:minsdkversion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".mediaipcactivity" > <intent-filter > <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <!-- 以下為新增片段 --> <service android:enabled="true" android:name=".romteservice" android:process=":remote" > <intent-filter > <action android:name="stu.edu.mediaipc.romteservicetransact" /> </intent-filter> </service> <!-- 以上為新增片段 --> </application> </manifest> Slep5 MediaIPCActivity.java 撰寫 宣告全域變數 (Global variables) package stu.edu.mediaipc; import android.app.activity; import android.content.componentname; import android.content.context; import android.content.intent;

import android.content.serviceconnection; import android.os.bundle; import android.os.handler; import android.os.ibinder; import android.os.message; import android.os.messenger; import android.os.remoteexception; import android.util.log; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; public class MediaIPCActivity extends Activity { private Button start, pause, stop; private Messenger locms = new Messenger(new handler()); private Messenger romms; private static final int SOUNG1 = 1; private static final int PAUSE = 3; private static final int STOP = 4; private static final String tag = "MediaIPCActivity"; protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); /* 以下為新增程式片段 */ start = (Button) findviewbyid(r.id.start); pause = (Button) findviewbyid(r.id.pause); stop = (Button) findviewbyid(r.id.stop); start.setonclicklistener(this); pause.setonclicklistener(this); stop.setonclicklistener(this); bindservice(new Intent(this,RomteService.class), serverconnection, Context.BIND_AUTO_CREATE); /* 以上為新增程式片段 */ 新增 ServiceConnection 變數 這類別是用來與 Service 做連線用的, 當連線成功後, 會呼叫 onserviceconnected, 這時候再用 剛剛上面定義好的 Messager roms 去參照從 service 回傳過來的 Ibinder

private ServiceConnection serverconnection = new ServiceConnection() { public void onserviceconnected(componentname name, IBinder service) { // TODO Auto-generated method stub Log.i("ServiceConnection", "onserviceconnected"); romms = new Messenger(service); public void onservicedisconnected(componentname name) { // TODO Auto-generated method stub romms = null; ; 新增內隱 Class handler 這類別是內隱類別 (inner class), 繼承 Handler 覆寫 handlemessage() 方法, 將從 Service 端傳來的 Message 做處理 class handler extends Handler { @Override public void handlemessage(message msg) { switch (msg.what) { case SOUNG1: settitle("play song1"); case PAUSE: settitle("meida Pause"); case STOP: settitle("media Stop"); 實做 OnClickListener 為方便處理按鈕事件, 因此覆寫監聽事件 public void onclick(view v) { Message message = null; try { if (v == start) message = Message.obtain(null, SOUNG1);

else if (v == pause) message = Message.obtain(null, PAUSE); else if (v == stop) message = Message.obtain(null, STOP); message.replyto = locms; if (message!= null) romms.send(message); catch (RemoteException e) { e.printstacktrace(); 附註 : MediaIPCActivity java 檔完成之 source code 如下所示 : package stu.edu.mediaipc; import android.app.activity; import android.content.componentname; import android.content.context; import android.content.intent; import android.content.serviceconnection; import android.os.bundle; import android.os.handler; import android.os.ibinder; import android.os.message; import android.os.messenger; import android.os.remoteexception; import android.util.log; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; public class MediaIPCActivity extends Activity implements OnClickListener { private Button start, pause, stop; private Messenger locms = new Messenger(new handler()); private Messenger romms; private static final int SOUNG1 = 1; private static final int PAUSE = 3; private static final int STOP = 4; private static final String tag = "MediaIPCActivity";

class handler extends Handler { @Override public void handlemessage(message msg) { switch (msg.what) { case SOUNG1: settitle("play song1"); case PAUSE: settitle("meida Pause"); case STOP: settitle("media Stop"); protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); start = (Button) findviewbyid(r.id.start); pause = (Button) findviewbyid(r.id.pause); stop = (Button) findviewbyid(r.id.stop); start.setonclicklistener(this); pause.setonclicklistener(this); stop.setonclicklistener(this); bindservice(new Intent(this,RomteService.class), serverconnection, Context.BIND_AUTO_CREATE); Log.i("MediaIPCActivity", "oncreate()"); private ServiceConnection serverconnection = new ServiceConnection() { public void onserviceconnected(componentname name, IBinder service) { // TODO Auto-generated method stub Log.i("ServiceConnection", "onserviceconnected"); romms = new Messenger(service);

; public void onservicedisconnected(componentname name) { // TODO Auto-generated method stub romms = null; public void onclick(view v) { Message message = null; try { if (v == start) message = Message.obtain(null, SOUNG1); else if (v == pause) message = Message.obtain(null, PAUSE); else if (v == stop) message = Message.obtain(null, STOP); message.replyto = locms; if (message!= null) romms.send(message); catch (RemoteException e) { e.printstacktrace();

Part IV MediaClient Project 撰寫 Step 1 將 MediaIPC 中的 main.xml 覆蓋 MediaClient 中的 main.xml 將 MediaIPC 的 res -> layout -> main.xml 複製到 MediaClient 的 res -> layout 因內容相同, 所以直接複製過來使用即可 Step 2 撰寫 MediaClientActivity.java 內容 與 MediaIPCActivity.java 大同小異, 下列需要更改之處將會用紅框標示 package stu.edu.mediaclient; import android.app.activity; import android.content.componentname; import android.content.context; import android.content.intent; import android.content.serviceconnection; import android.os.bundle; import android.os.handler; import android.os.ibinder;

import android.os.message; import android.os.messenger; import android.os.remoteexception; import android.util.log; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; public class MediaClientActivity extends Activity implements OnClickListener { private Button start, pause, stop; private Messenger locms = new Messenger(new Handler()); private Messenger romms; private static final int SONG2 = 2; private static final int PAUSE = 3; private static final int STOP = 4; private static final String tag = "MediaIPCActivity"; private ServiceConnection serviceconnection = new ServiceConnection() { public void onservicedisconnected(componentname name) { Log.i(tag, "onservicedisconnected"); romms = null; ; public void onserviceconnected(componentname name, IBinder service) { Log.i(tag, "onserviceconnected"); romms = new Messenger(service); class handler extends Handler { @Override public void handlemessage(message msg) { switch (msg.what) { case SONG2: settitle("play song2"); case PAUSE: settitle("meida Pause"); case STOP: settitle("media Stop");

/** Called when the activity is first created. */ @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); start = (Button) findviewbyid(r.id.start); pause = (Button) findviewbyid(r.id.pause); stop = (Button) findviewbyid(r.id.stop); start.setonclicklistener(this); pause.setonclicklistener(this); stop.setonclicklistener(this); // 呼叫名為 " stu.edu.mediaipc.romteservicetransact" 的 Service bindservice(new Intent("stu.edu.mediaipc.RomteServiceTransact"), serviceconnection, Context.BIND_AUTO_CREATE); @Override public void onclick(view v) { Message message = null; try { if (v == start) message = Message.obtain(null, SONG2); else if (v == pause) message = Message.obtain(null, PAUSE); else if (v == stop) message = Message.obtain(null, STOP); message.replyto = locms; romms.send(message); catch (RemoteException e) { e.printstacktrace();

Part IV 測試 Step 1 執行應用程式並進行撥放音樂 啟動 MeidaIPC 按播放 按 home 鍵啟動 MediaClient 按播放