標籤:android style blog color 使用 os strong 檔案
上一篇文章對近期做的小鬧鐘做了功能闡述,現在來總結下整個開發過程中所用到的一些知識點:
1.TimePicker的監聽
TimePicker控制項是整個應用的核心,其它的操作都得基於對該控制項的正確操控。對該控制項的操作重要就是為其設定監聽器,在監聽事件中擷取使用者佈建的時間。
private Calendar calendar=Calendar.getInstance();//建立calendar對象private class OnTimeChangedListenerImpl implements OnTimeChangedListener { @Override public void onTimeChanged(TimePicker view, int hour_of_day, int minutes) { // TODO Auto-generated method stub calendar.setTimeInMillis(System.currentTimeMillis());//將timePciker的目前時間轉換為Calender對象 calendar.set(Calendar.HOUR_OF_DAY,hour_of_day);//設定小時 calendar.set(Calendar.MINUTE,minutes);//設定分鐘 calendar.set(Calendar.SECOND,0);//設定秒 calendar.set(Calendar.MILLISECOND,0);//設定毫秒 hour=hour_of_day;//儲存設定的小時 minute=minutes;//儲存設定的分鐘 } }
該設計中使用Calendar類來代表特定的時間(即使用者設定的鬧鐘時間)。Calendar類是一個抽象類別,其構造方法的許可權是protected,所以無法通過構造方法來建立對象,因此只能調用getInstance()進行建立。通過setTime()和getTime()兩個方法實現Date和Calendar類之間的轉換。
2.PendingIntent的使用
本設計中通過PendingIntent實現定時發送廣播,從而實現鬧鐘功能:
Intent intent=new Intent(MainActivity.this,MyAlarmReceiver.class);//指定跳轉的Inetent intent.setAction("com.example.action.setalarm");//指定intent的action PendingIntent sender=PendingIntent.getBroadcast(MainActivity.this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);//指定PendingIntentalarm.set(AlarmManager.RTC_WAKEUP,MainActivity.this.calendar.getTimeInMillis(),sender);//設定鬧鐘
PendingIntent字面意思為:未決定的、待定的Intent。這是第一次接觸到PendingIntent,在網上也看了很多資料,但都感覺糊裡糊塗的,後來看到一官網的定義,就恍然大悟了:An Intent is something that is used right now; a PendingIntent is something that may create an Intent in the future. You will use a PendingIntent with Notifications, AlarmManager, etc.關鍵的是其中的in the future,結合本執行個體,也就是當鬧鐘時間到的時候,PendingIntent攜帶的Broadcast才會被廣播出去。
3.利用Cursor資料庫查詢音頻檔案清單
使用者可以選擇裝置的SD卡上的音頻檔案作為鬧鐘的鈴聲,本設計中通過Cursor實現這一功能:
//擷取SD卡上的音頻檔案 public void scannerMusic(){ //查詢媒體資料庫 Cursor cursor=MainActivity.this.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); //遍曆資料庫 if(cursor.moveToFirst()) { while(!cursor.isAfterLast()) { int id=cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));//擷取歌曲編號 int trackid=cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));//擷取歌曲ID String album=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));//擷取歌曲專輯名 String artist=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));//擷取歌曲歌手名 String url=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));//擷取歌曲路徑 String duration=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));//擷取歌曲播放時間長度 int size=cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));//擷取歌曲大小 String disName=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));//擷取歌曲檔案顯示名字 items.add(disName); urls.add(url);//儲存歌曲路徑 cursor.moveToNext(); } cursor.close(); } fileList=new ArrayAdapter<String>(this,R.layout.list_item,items); }
android裝置在載入SD卡時候會自動將檔案分類存放,其中音頻檔案就存放在MediaStore資料庫中,可以通過ContentResolver來調用這些封裝好的介面,接著調用qurey()方法就可以獲得音頻檔案的列表及相關資訊,query()方法原型為:
query(_uri, prjs, selections, selectArgs, order);
該方法第一個參數為:要查詢的資料庫的名稱加上表的名稱。第二個參數為從表中選擇的列。第三個參數為查詢條件。第五個參數為排序條件。
擷取所有音頻檔案後,將音頻檔案的名稱和相對應的路徑儲存在動態數組中,方便後期的調用。
4.SharePreference完成資料存放區
本設計中使用者選定了音頻檔案後,需要在另一個activity播放,因此用到了SharePreference來儲存使用者選擇的音頻對應的路徑。
SharedPreferences sp=getSharedPreferences("mrsoft",MODE_PRIVATE);//獲得私人類型的SharedPreferencesEditor editor=sp.edit();//獲得Editor對象 //editor對象採用KEY-VALUE形式存放
editor.putString("musicurl", urls.get(item));//增加音樂地址editor.commit();//確認提交
SharePreferences是應用程式內部輕量級的儲存方案,最常被用來儲存應用的配置參數。採用SharePreference儲存資料,實質上就是採用XML檔案進行儲存,存放的路徑為:/data/data/<package name>/shared_prefs。SharePreference使用起來很方便:利用getSharePreferences()擷取SharePreferences對象,該方法擷取的對象可以被同應用程式下的其它組件訪問。該方法有兩個參數,第一個參數設定共用檔案的名稱,第二個參數設定共用檔案的類型。接著通過edit()方法獲得Editor對象,再利用Editor對象的putString()方法增加要儲存的值,最後調用commit()方法提交。相應地,當需要讀取已儲存的資料時候可以調用getstring()方法。
5.Adapter、AlertDialog、ListView結合使用
Adapter其實就是資料和視圖之間的橋樑,資料經過Adapter進行相應的處理後送到視圖上顯示出來。本設計用到的是一個String類型的數組適配器:
ArrayAdapter<String> fileList
fileList=new ArrayAdapter<String>(this,R.layout.list_item,items);
ArrayAdapter<String>裡面有三個參數,第一個參數是上下文,也就是當前的activtiy,第二個參數是自訂的一個布局,說白了就是一個TextView,每一條資料都以這個布局檔案的形式呈現出來,第三個參數就是要顯示的資料。本設計將讀取到的音頻檔案清單顯示在一個alertdialog上,所以還需要設定Adapter與AlertDialog之間的串連:
builder.setAdapter(fileList, new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int item) { } });
fileList為資料配接器,第二個參數為ListView列表的單擊事件監聽器,當使用者單擊ListView列表上的內容,將採取相應的操作。
6.Recording進行錄音
使用者可以通過本應用錄製自己喜歡的音頻作為鬧鐘鈴聲。錄音的操作和音頻檔案的播放差不多,實現起來也相對簡單:
private void startRecording() { //擷取MediaRecorder對象 mRecorder=new MediaRecorder(); //設定音頻源為Micphone mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //設定封裝格式 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //設定音頻檔案輸出路徑 mRecorder.setOutputFile(mFileName); //設定編碼格式 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); try { mRecorder.prepare(); mRecorder.start(); } catch(IOException e) { e.printStackTrace(); } } private void stopRecording() { try { mRecorder.stop(); } catch(IllegalStateException e) { e.printStackTrace(); } mRecorder.release();//釋放資源 mRecorder=null;//清空MediaRecorder對象,這步不能少 }
錄製過程和採用MediaPlayer播放音頻過程很相似,值得注意的是,錄音完畢後必須調用mRecorder.release()來釋放資源,並清空mRecorder對象,否則使用者再次進行錄音操作時候會出現硬體資源衝突的異常,導致應用程式非正常關閉。
7.BroadcastReceiver
本設計通過BroadcastReceiver來啟動“鬧鐘時間到”介面:
public class MyAlarmReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub if(intent.getAction().equals("com.example.action.setalarm")) { Intent it=new Intent(context,AlarmMessage.class);//定製要跳轉的activity it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 傳遞一個新的任務標記 context.startActivity(it);//啟動Intent } }}
廣播接收者(BroadcastReceiver)用於接收廣播的Intent,通常一個廣播Intent可以被訂閱了該廣播的多個BroadcastReceiver接收。廣播是一種應用程式間進行訊息傳輸的機制,而BroadcastReceiver是對發送出來的廣播進行過濾接收並響應的一類組件,BroadcastReceiver自身並不實現圖形化介面。每次廣播到來時,都會重新建立BroadcastReceiver對象,並調用其onReceive方法,在該方法中不能進行一些相對耗時的操作,因為BroadcastReceiver的生命週期只有十秒鐘左右的時間。有關廣播的知識還有很多,這裡不進行詳細介紹。
7.Vibrator
本設計中,鬧鐘響起時,使用者裝置也伴隨著震動現象。在android中,通過調用Vibrator類實現震動。
vibrator=(Vibrator) getSystemService(Context.VIBRATOR_SERVICE);//擷取震動服務 long pattern[]={100,400,100,400};//停止 開啟 停止 開啟 //控制手機震動的毫秒數,其中第二個參數指定第一個數組參數的索引,-1表示只震動一次,非-1表示從指定下標(第二個參數)開始重複震動 vibrator.vibrate(pattern,2);
首先擷取裝置的震動服務,接著定義一個存放震動時間的數組,在Vibrator中,震動時間是以毫秒(1/1000秒)計算,因此可以通過數值的大小來控制震動的啟停。最後調用vibrate方法來實現震動功能,該方法第二個參數為-1時表示只震動一次,為非-1時表示重複震動。
8.ExitApplication
本設計中,涉及到兩個activity,因此當使用者想要關閉應用時候,需要一次性將所有activity都關閉,如果在當前介面調用finish()方法,只能退出當期的activity。所以採用了以下方法來完成這一功能:
public class ExitApplication extends Application{ private List<Activity> activityList=new LinkedList<Activity>(); private static ExitApplication instance; private ExitApplication() { } //單例模式中,擷取唯一的ExitApplication執行個體 public static ExitApplication getInstance() { if(null == instance) { instance = new ExitApplication(); } return instance; } //添加activity到容器 public void addActivity(Activity activity) { activityList.add(activity); } //遍曆所有Activity 並finish public void exit() { for(Activity activity:activityList) { activity.finish(); } System.exit(0); }}
接著在每個在Activity的onCreate()方法中調用ExitApplication.getInstance().addActivity(this)方法。這樣就可以在任意一個activity退出時調用ExitApplication.getInstance().exit()方法,完全退出應用程式了。