2013年5月16日 星期四

[Android] 鬧鐘(AlarmMamager and PendingIntent) 上篇

我們利用AlarmManager實作一個鬧鐘,
讓他在開機後1分鐘後,發出鈴響。
只要利用PendingIntent及AlarmManager就可以做到這樣的功能。

1. MainActivity.java
import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
 Button mButton;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  mButton = (Button) findViewById(R.id.button1);
  mButton.setOnClickListener(new Button.OnClickListener() {

   @Override
   public void onClick(View v) {
    
    Intent intent = new Intent(MainActivity.this, PlayReceiver.class);
    intent.putExtra("msg", "play_voice");
    intent.addCategory(String.valueOf(SystemClock.elapsedRealtime()));
     //SystemClock.elapsedRealtime()會回傳從開機到現在當下所花的時間,手機進入睡眠時間也算在內(單位milliseconds)
    long elapsed = SystemClock.elapsedRealtime() + 60 * 1000; //60秒
    // 發送一個broadcast,類似 Context.sendBroadcast()
    // PendingIntent.FLAG_UPDATE_CURRENT參數表示,如果已存在 PendingIntent,就更新 extra data.
    PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this, 1, intent, 
      PendingIntent.FLAG_UPDATE_CURRENT);
    
    AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
    am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, elapsed , pi);

   }

  });
 }


}
那Intent,和PendingIntent有什麼不同呢?
一般的Intent,用startActivity(intent)就會直接去啟動和intent。
PendingIntent可以想成延遲Intent,它則是先把某個Intent包好,丟給某個程式,等到一段時間後再去執行Intent。
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, elapsed , pi);
等到第二個參數(elapsed)所設定的時間到達時,就會執行pi這個PendingIntent
這裡有一點要注意,當 AlarmManager 執行 set() 時,Android 系統會比對已註冊的其他 Intent 的 action、data、type、class、category, 如果這幾個屬性完全相同,則系統會將這兩個 Intent 視為一樣, 這時系統會視 PendingIntent.FLAG_xxx 參數以決定如何處理這個新註冊的 Intent 。

2.接下來建立接收廣播的class:
PlayReceiver.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;

public class PlayReceiver extends BroadcastReceiver {

 private SoundPool sp;
 private int sourceid;

 @Override
 public void onReceive(Context context, Intent intent) {
  
  Bundle bData = intent.getExtras();
 
  if (bData.get("msg").equals("play_voice")) {
   sp = new SoundPool(10, AudioManager.STREAM_MUSIC, 5);
   sourceid = sp.load(context, R.raw.harm, 1);
   
   playSounds(1, context);
  }
  
 }

 public void playSounds(int repeatTime, Context context) {
  AudioManager am = (AudioManager) context.getApplicationContext()
    .getSystemService(Context.AUDIO_SERVICE);
  // 獲取最大音量
  float audMaxVolumn = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
  // 獲取目前音量
  float audCurrentVolumn = am.getStreamVolume(AudioManager.STREAM_MUSIC);
  // 左右聲道值範圍為 0.0 - 1.0
  float volRatio = audCurrentVolumn / audMaxVolumn;
  // 下面參數分別為播放音頻,左聲道,右聲道,設置優先級,重撥次數,速率(速率最低0.5,最高為2,1代表正常速度)
  sp.play(sourceid, volRatio, volRatio, 1, repeatTime, 1);
 }
}
播放音效的作法,請參考先前的文章

3. 在Layout裡加入一個按鈕, 來啟動鬧鐘
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_marginBottom="54dp"
        android:text="1分鍾後,鬧鍾啟動" />

</RelativeLayout>
4. 最後在AndroidManifest.xml 的 application 區段寫入要接收廣播的程式:
<receiver android:name="com.example.s.PlayReceiver" >
            <intent-filter>
                <action android:name="play_voice" />
            </intent-filter>
</receiver>

reference
http://oldgrayduck.blogspot.tw/2012/10/androidalarmmanager.html

2 則留言:

  1. Hello 你好
    我依你的程式, 複製一份
    手機接在goodle的studio 發展系統 上, 就沒問題
    但手機不接上電腦後
    待機之後 , wake up 時間 會晚大概2分鐘
    我可以傳我的 project 給你看看到底是哪裡出錯嗎?
    謝謝

    回覆刪除
  2. 或者你可以傳你的整個project (使用google studio) 給我嗎?

    回覆刪除