さて、ほとんどAndroidを触ることもなかった最近です。
リハビリを兼ねて極小さなプログラムを書いてみました。
Google Developer Day 2008にてルービンさんが実演されていたMP3プレーヤーの極手抜き版です。
要はServiceを用いてActivityが実行を終了しても再生を続けることを目指しました。
うまくいったので晒しておきます。
Service
AndroidではServiceはActivityと違い画面を持ちません。
デーモンであるかのように専用のスレッドにて常駐します。
ActivityはServiceに対し、start、stopを行うことや、既に実行されているServiceに対してbindを行うことができます。
ServiceにbindしたActivityはServiceに対し専用のメソッドを呼び出すことや、逆にServiceがActivityのCallbackを呼び出すことができます。
Serviceにて提供するサービスをActivityが利用するにはServiceの実装に用いたaidlにより生成されたInterfaceを利用する必要があります。
詳しくはAPI Demoのapp.Service、また公式ドキュメントのaidlを参照してください。
http://code.google.com/android/reference/aidl.html
今回はmp3を決め打ちで再生していますのでaidlは使っていません。
ActivityにてServiceを起動するとmp3の再生を開始します。
loopingを設定していますので無限に実行します。
package minghai.practice2; import java.io.IOException; import android.app.Notification; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.widget.Toast; public class PlayerService extends Service { private NotificationManager mNM; MediaPlayer mp; @Override protected void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. showNotification(); mp = new MediaPlayer(); } @Override protected void onStart(int startId, Bundle arguments) { if (mp != null && mp.isPlaying()) return; try { mp.setDataSource("/sdcard/your.mp3"); mp.setLooping(1); mp.prepare(); mp.start(); } catch (IOException e) { Log.d("TEST", e.getMessage()); throw new RuntimeException(e.getMessage(), e); } } @Override protected void onDestroy() { // Cancel the persistent notification. mNM.cancel(R.string.start_service); mp.stop(); mp.release(); // Tell the user we stopped. Toast.makeText(this, "MP3 Player Stopped", Toast.LENGTH_SHORT).show(); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } /** * Show a notification while this service is running. */ private void showNotification() { // This is who should be launched if the user selects our notification. Intent contentIntent = new Intent(this, MP3Player.class); // This is who should be launched if the user selects the app icon in the notification, // (in this case, we launch the same activity for both) Intent appIntent = new Intent(this, MP3Player.class); // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = "Playing MP3"; mNM.notify(R.string.start_service, // we use a string id because it is a unique // number. we use it later to cancel the // notification new Notification( this, // our context R.drawable.stat_happy, // the icon for the status bar text, // the text to display in the ticker System.currentTimeMillis(), // the timestamp for the notification "MP3 Player Service", // the title for the notification text, // the details to display in the notification contentIntent, // the contentIntent (see above) R.drawable.icon, // the app icon "MP3 Player", // the name of the app appIntent)); // the appIntent (see above) } }
Notification
Serviceを用いる場合にはNotificationを定義しておきます。
これはサービスが実行されている間ホームのUIからServiceにアクセスする手段を与えます。
Androidではサービスを実行している間、Notificationを設定しておくと画面の一番上のステータスバーにアイコンが表示されます。
この時、ステータスバーをクリックし、下に向かってドラッグすると実行中のサービスの一覧画面になります。
一覧からServiceのアイコンをクリックすると設定されたActivityが実行されます。
今回の場合元のActivityが実行され、音楽の再生を停止することが可能になります。
Activity
今回のActivityが行っていることは実にシンプルです。
画面にはボタンを2つ用意しています。
1つはServiceの開始であり、音楽の再生開始ボタンです。
もう一つはServiceの停止ボタンです。
Serviceは1度起動すれば、複数起動することはありません。
package minghai.practice2; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MP3Player extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); Button button = (Button)findViewById(R.id.start); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { startService(new Intent(MP3Player.this, PlayerService.class), null); } }); button = (Button)findViewById(R.id.stop); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { // Cancel a previous call to startService(). Note that the // service will not actually stop at this point if there are // still bound clients. stopService(new Intent(MP3Player.this, PlayerService.class)); } }); } }
まとめ
ServiceはonCreateで実際のサービスを開始してはいけないようです。MediaPlayerの場合、再生がすぐに停止する症状に悩みました。
このプログラムを作成した後に気付いたのですが、英語のサイトでもっと優れたmp3プレーヤーを作成された方がいらしました。
m3用ですが十分に参考になると思います。
http://www.helloandroid.com/node/140
ところでmp3の再生にemulatorがCPUの20%から30%も使用してしまいます。
やっぱりAndroidのemulatorは重いですね。