<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                **這一章在處理相片與錄音檔名稱的時候有錯誤,建議在完成這一章的內容以后,再參考[錯誤修正:4-1 使用照相機與麥克風](https://github.com/macdidi5/AndroidTutorial/blob/master/AndroidTutorial4_1Update.md)修正錯誤。** 現在行動裝置的硬件設備技術已經越來越好了,螢幕的尺寸不斷的增加,提供使用者清楚又美觀的畫面。觸控螢幕也幾乎是目前行動裝置的標準設備,使用觸控的方式操作應用程式快速又方便。Android系統內建的音樂播放應用程式,也可以讓行動裝置成為隨身的音樂播放設備。還有畫素也越來越高的照像功能,一臺行動裝置幾乎可以應付所有的需求。 行動裝置提供高畫質的攝影鏡頭,讓使用者隨時可以拍攝照片與錄影,也幾乎已經是行動裝置基本的設備與功能了。使用Android系統內建的API與元件,可以在應用程式需要的時候,讓使用者拍攝照片與錄影,并且把照片或影片檔案儲存在指定的位置。例如在記事本應用程式中,可以加入照片與錄影備忘的功能。 應用程式需要錄音的時候,可以使用內建的API執行錄音的工作,并且把錄音完成的檔案儲存在指定的位置,例如在記事本應用程式中,可以加入錄制語音備忘的功能,讓使用者可以隨時查詢與播放這些錄音資訊。 這一章為記事資料加入照相與錄音的功能,讓這個應用程式的功能可以更完整,使用者可以在新增或修改記事資料的時候,啟動相機拍照,還有使用麥克風錄制語音備忘。 ## 12-1 使用相機拍攝照片 不論是移動電話或平板電腦,幾乎都有高畫質的攝錄鏡頭設備,讓使用者可以隨時拍攝與錄影。加入拍攝照片的功能可以讓應用程式的功能更完整,例如在記事本應用程式加入拍照的功能,記錄影像會比文字更清楚與方便。 應用程式需要執行拍照的功能,可以啟動系統相機元件執行拍照的工作,它的系統Action名稱變量是“MediaStore.ACTION_IMAGE_CAPTURE”,使用這個Action名稱建立好的Intent物件,可以呼叫putExtra方法加入照片檔案儲存位置的設定資料,資料的名稱是“MediaStore.EXTRA_OUTPUT”,如果沒有指定的話,會使用系統默認的名稱儲存在默認的位置。 應用程式要執行拍照的功能,裝置必須有攝錄鏡頭的設備才可以正確的執行,所以需要在應用程式設定檔中加入硬件設備需求的設定。如果需要儲存照片檔案到外部儲存設備,例如記憶卡,需要在應用程式設定檔中加入授權設定: ~~~ <!-- 需要攝錄鏡頭設備 --> <uses-feature android:name="android.hardware.camera" /> <!-- 寫入外部儲存設備 --> <uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE"/> ~~~ Android模擬裝置也可以測試相機的功能,不過要先確認模擬裝置的設定,關閉已經啟動的模擬裝置,在Android Studio選擇功能表“Tools -> Android -> AVD Manager”,選擇模擬裝置的編輯圖示: [![AndroidTutorial5_04_01_01](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_01-300x171.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_01.png) 在模擬裝置編輯視窗選擇“Show Advanced Settings”: [![AndroidTutorial5_04_01_02](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_02-300x152.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_02.png) 如果你的電腦沒有連接WebCam,在“Front”與“Back”選擇“Emulated”。如果電已經連接WebCam,就可以選擇“Webcam0”。完成設定后選擇“Finish”: [![AndroidTutorial5_04_01_03](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_03-300x152.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_03.png) 回到AVD Manager視窗后,選擇模擬裝置的啟動圖示: [![AndroidTutorial5_04_01_04](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_04-300x171.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_04.png) 模擬裝置啟動以后,開啟“照相”應用程式,就可以看到模擬照相機的畫面: [![AndroidTutorial5_04_01_05](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_05-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_05.png) 因為記事元件的畫面加入照片以后,在螢幕比較小的裝置運作時,畫面會超過螢幕的范圍,所以需要調整畫面的設計。另外也要加入顯示照片用的ImageView元件。開啟“res/layout/activity_item.xml”,參考下列的內容修改這個畫面配置檔: ~~~ <?xml version="1.0" encoding="utf-8"?> <!-- 使用ScrollView為最外層的元件 --> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 刪除xmlns:android的設定 --> <TableLayout xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:stretchColumns="1" tools:context="net.macdidi.myandroidtutorial.ItemActivity"> <TableRow> ... </TableRow> <TableRow> ... </TableRow> <!-- 顯示圖片 --> <ImageView android:id="@+id/picture" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/retangle_drawable" android:padding="6sp" android:layout_margin="2sp" android:visibility="invisible" /> <TableLayout ...> <TableRow> ... </TableRow> </TableLayout> <TableLayout ...> <TableRow> ... </TableRow> </TableLayout> </TableLayout> <!-- ScrollView的結束標簽 --> </ScrollView> ~~~ 因為需要儲存照片與錄音檔案,所以撰寫一個檔案公用類別。在“net.macdidi.myandroidtutorial”套件按鼠標右鍵,選擇“New -> Java CLass”,在Name輸入“FileUtil”后選擇“OK”。參考下列的內容完成這個程式碼: ~~~ package net.macdidi.myandroidtutorial; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.util.Log; import android.widget.ImageView; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; public class FileUtil { // 應用程式儲存盤案的目錄 public static final String APP_DIR = "androidtutorial"; // 外部儲存設備是否可寫入 public static boolean isExternalStorageWritable() { // 取得目前外部儲存設備的狀態 String state = Environment.getExternalStorageState(); // 判斷是否可寫入 if (Environment.MEDIA_MOUNTED.equals(state)) { return true; } return false; } // 外部儲存設備是否可讀取 public static boolean isExternalStorageReadable() { // 取得目前外部儲存設備的狀態 String state = Environment.getExternalStorageState(); // 判斷是否可讀取 if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { return true; } return false; } // 建立并傳回在公用相簿下參數指定的路徑 public static File getPublicAlbumStorageDir(String albumName) { // 取得公用的照片路徑 File pictures = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); // 準備在照片路徑下建立一個指定的路徑 File file = new File(pictures, albumName); // 如果建立路徑不成功 if (!file.mkdirs()) { Log.e("getAlbumStorageDir", "Directory not created"); } return file; } // 建立并傳回在應用程式專用相簿下參數指定的路徑 public static File getAlbumStorageDir(Context context, String albumName) { // 取得應用程式專用的照片路徑 File pictures = context.getExternalFilesDir( Environment.DIRECTORY_PICTURES); // 準備在照片路徑下建立一個指定的路徑 File file = new File(pictures, albumName); // 如果建立路徑不成功 if (!file.mkdirs()) { Log.e("getAlbumStorageDir", "Directory not created"); } return file; } // 建立并傳回外部儲存媒體參數指定的路徑 public static File getExternalStorageDir(String dir) { File result = new File( Environment.getExternalStorageDirectory(), dir); if (!isExternalStorageWritable()) { return null; } if (!result.exists() && !result.mkdirs()) { return null; } return result; } // 讀取指定的照片檔案名稱設定給ImageView元件 public static void fileToImageView(String fileName, ImageView imageView) { if (new File(fileName).exists()) { Bitmap bitmap = BitmapFactory.decodeFile(fileName); imageView.setImageBitmap(bitmap); } else { Log.e("fileToImageView", fileName + " not found."); } } // 產生唯一的檔案名稱 public static String getUniqueFileName() { // 使用年月日_時分秒格式為檔案名稱 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); return sdf.format(new Date()); } } ~~~ 開啟在“net.macdidi.myandroidtutorial”套件下的“ItemActivity”類別,加入照相功能需要的字段變量: ~~~ // 檔案名稱 private String fileName; // 照片 private ImageView picture; ~~~ 同樣在“ItemActivity”類別,找到“processViews”方法,參考下列的程式碼,加入取得顯示照片ImageView元件的程式碼: ~~~ private void processViews() { title_text = (EditText) findViewById(R.id.title_text); content_text = (EditText) findViewById(R.id.content_text); // 取得顯示照片的ImageView元件 picture = (ImageView) findViewById(R.id.picture); } ~~~ 同樣在“ItemActivity”類別,找到“clickFunction”方法,參考下列的程式碼,加入啟動相機元件的程式碼: ~~~ public void clickFunction(View view) { int id = view.getId(); switch (id) { case R.id.take_picture: // 啟動相機元件用的Intent物件 Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 照片檔案名稱 File pictureFile = configFileName("P", ".jpg"); Uri uri = Uri.fromFile(pictureFile); // 設定檔案名稱 intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, uri); // 啟動相機元件 startActivityForResult(intentCamera, START_CAMERA); break; ... } } private File configFileName(String prefix, String extension) { // 如果記事資料已經有檔案名稱 if (item.getFileName() != null && item.getFileName().length() > 0) { fileName = item.getFileName(); } // 產生檔案名稱 else { fileName = FileUtil.getUniqueFileName(); } return new File(FileUtil.getExternalStorageDir(FileUtil.APP_DIR), prefix + fileName + extension); } ~~~ 同樣在“ItemActivity”類別,找到“onActivityResult”方法,參考下列的程式碼,處理完成照相工作后的程式碼: ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { switch (requestCode) { // 照像 case START_CAMERA: // 設定照片檔案名稱 item.setFileName(fileName); break; ... } } } ~~~ 同樣在“ItemActivity”類別,新增覆寫“onResume”方法的程式碼,執行顯示照片的工作: ~~~ @Override protected void onResume() { super.onResume(); // 如果有檔案名稱 if (item.getFileName() != null && item.getFileName().length() > 0) { // 照片檔案物件 File file = configFileName("P", ".jpg"); // 如果照片檔案存在 if (file.exists()) { // 顯示照片元件 picture.setVisibility(View.VISIBLE); // 設定照片 FileUtil.fileToImageView(file.getAbsolutePath(), picture); } } } ~~~ 完成照相功能的工作了,執行應用程式,新增一個記事資料后選擇照相功能: [![AndroidTutorial5_04_01_06](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_06-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_06.png) 畫面出現像這樣的相機模擬畫面,選擇照像按鈕: [![AndroidTutorial5_04_01_07](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_07-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_07.png) 選擇確定按鈕: [![AndroidTutorial5_04_01_08](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_08-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_08.png) 記事資料顯示拍好的照片,儲存記事資料后也會儲存照片: [![AndroidTutorial5_04_01_09](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_09-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_09.png) ## 12-2 錄制語音備忘 在行動裝置的應用程式使用錄音功能,可以讓很多工作變得更方便,例如語音備忘錄的功能,可以省掉很多輸入文字的時間。如果應用程式需要執行錄音的工作,使用宣告在“android.media”套件下的“MediaRecorder”類別,應用程式可以設定錄音的來源、輸出格式、編碼和儲存盤案的位置。這些是執行設定與錄音的方法,要特別注意在程式碼中呼叫它們的順序: * setAudioSource(int) – 設定錄音來源,必須在setOutputFormat方法之前呼叫。設定為“MediaRecorder.AudioSource.MIC”表示錄音來源是麥克風。 * setOutputFormat(int) –設定輸出格式,必須在setAudioSource方法之后。設定為“MediaRecorder.OutputFormat.THREE_GPP”表示輸出為3GP壓縮格式。 * setAudioEncoder(int) –設定編碼方式,必須在setOutputFormat方法之后。一般設定為“MediaRecorder.AudioEncoder.AMR_NB”。 * setOutputFile(String) –設定輸出的檔案名稱,必須在setOutputFormat方法之后。 * prepare() – 使用設定的內容準備錄音。 * start() – 開始錄音。 * stop() – 停止錄音。 * release() – 清除錄音資源。 如果應用程式需要使用裝置的錄音設備,必須在應用程式設定檔“AndroidManifest.xml”加入授權的設定: ~~~ <uses-permission android:name="android.permission.RECORD_AUDIO"/> ~~~ 加入錄音功能的記事應用程式,可以讓使用者選擇錄音功能按鈕,啟動一個負責錄音的Activity元件,按下錄音按鈕就可以開始錄音: [![AndroidTutorial5_04_01_10](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_10-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_10.png) 錄音的時候,錄音按鈕會切換為紅色的圖示,錄音的音量變化會在右側顯示: [![AndroidTutorial5_04_01_11](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_11-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_11.png) 設計錄音元件的畫面配置檔,使用的圖形資源可以在GitHub中取得,需要“record_dard_icon.png”與“record_red_icon.png”兩個圖示檔案。開啟“res/values/strings.xml”,加入這個元件需要的文字資源: ~~~ <string name="title_record">語音備忘</string> ~~~ 在“res/layout”目錄按鼠標右鍵,選擇“New -> Layout resrouce file”,在File name輸入“activity_record”候選擇“OK”。參考下列的內容,完成這個畫面資源的設計: ~~~ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/retangle_drawable" android:layout_margin="6sp" android:padding="6sp"> <ImageButton android:id="@+id/record_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/record_sound_icon" android:onClick="clickRecord" /> <ProgressBar android:id="@+id/record_volumn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="6dp" android:layout_marginRight="6dp" android:max="15" style="@android:style/Widget.ProgressBar.Horizontal" /> </LinearLayout> <TableLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:stretchColumns="*"> <TableRow> <Button android:text="@android:string/cancel" android:onClick="onSubmit" /> <Button android:id="@+id/record_ok" android:text="@android:string/ok" android:onClick="onSubmit" /> </TableRow> </TableLayout> </LinearLayout> ~~~ 在“net.macdidi.myandroidtutorial”套件按鼠標右鍵,選擇“New -> Java CLass”,在Name輸入“RecordActivity”后選擇“OK”。參考下列的內容完成這個Activity元件的程式碼:(這里提供的設計包含顯示錄音中的音量,你可以考慮移除這個部份的程式碼,這個元件的設計就會比較簡單一些) ~~~ package net.macdidi.myandroidtutorial; import android.app.Activity; import android.content.Intent; import android.media.MediaRecorder; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ImageButton; import android.widget.ProgressBar; import java.io.IOException; public class RecordActivity extends Activity { private ImageButton record_button; private boolean isRecording = false; private ProgressBar record_volumn; private MyRecoder myRecoder; private String fileName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_record); processViews(); // 讀取檔案名稱 Intent intent = getIntent(); fileName = intent.getStringExtra("fileName"); } public void onSubmit(View view) { if (isRecording) { // 停止錄音 myRecoder.stop(); } // 確定 if (view.getId() == R.id.record_ok) { Intent result = getIntent(); setResult(Activity.RESULT_OK, result); } finish(); } private void processViews() { record_button = (ImageButton) findViewById(R.id.record_button); record_volumn = (ProgressBar) findViewById(R.id.record_volumn); // 隱藏狀態列ProgressBar setProgressBarIndeterminateVisibility(false); } public void clickRecord(View view) { // 切換 isRecording = !isRecording; // 開始錄音 if (isRecording) { // 設定按鈕圖示為錄音中 record_button.setImageResource(R.drawable.record_red_icon); // 建立錄音物件 myRecoder = new MyRecoder(fileName); // 開始錄音 myRecoder.start(); // 建立并執行顯示麥克風音量的AsyncTask物件 new MicLevelTask().execute(); } // 停止錄音 else { // 設定按鈕圖示為停止錄音 record_button.setImageResource(R.drawable.record_dark_icon); // 麥克風音量歸零 record_volumn.setProgress(0); // 停止錄音 myRecoder.stop(); } } // 在錄音過程中顯示麥克風音量 private class MicLevelTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... args) { while (isRecording) { publishProgress(); try { Thread.sleep(200); } catch (InterruptedException e) { Log.d("RecordActivity", e.toString()); } } return null; } @Override protected void onProgressUpdate(Void... values) { record_volumn.setProgress((int) myRecoder.getAmplitudeEMA()); } } // 執行錄音并且可以取得麥克風音量的錄音物件 private class MyRecoder { private static final double EMA_FILTER = 0.6; private MediaRecorder recorder = null; private double mEMA = 0.0; private String output; // 建立錄音物件,參數為錄音儲存的位置與檔名 MyRecoder(String output) { this.output = output; } // 開始錄音 public void start() { if (recorder == null) { // 建立錄音用的MediaRecorder物件 recorder = new MediaRecorder(); // 設定錄音來源為麥克風,必須在setOutputFormat方法之前呼叫 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 設定輸出格式為3GP壓縮格式,必須在setAudioSource方法之后, // 在prepare方法之前呼叫 recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); // 設定錄音的編碼方式,必須在setOutputFormat方法之后, // 在prepare方法之前呼叫 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 設定輸出的檔案名稱,必須在setOutputFormat方法之后, // 在prepare方法之前呼叫 recorder.setOutputFile(output); try { // 準備執行錄音工作,必須在所有設定之后呼叫 recorder.prepare(); } catch (IOException e) { Log.d("RecordActivity", e.toString()); } // 開始錄音 recorder.start(); mEMA = 0.0; } } // 停止錄音 public void stop() { if (recorder != null) { // 停止錄音 recorder.stop(); // 清除錄音資源 recorder.release(); recorder = null; } } public double getAmplitude() { if (recorder != null) return (recorder.getMaxAmplitude() / 2700.0); else return 0; } // 取得麥克風音量 public double getAmplitudeEMA() { double amp = getAmplitude(); mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA; return mEMA; } } } ~~~ 開啟應用程式設定檔“AndroidManifest.xml”,加入錄音元件的設定: ~~~ <!-- 錄音元件 --> <activity android:name="net.macdidi.myandroidtutorial.RecordActivity" android:theme="@android:style/Theme.Dialog" android:label="@string/title_record"/> ~~~ 完成錄音元件的設計后,開啟在“net.macdidi.myandroidtutorial”套件下的“ItemActivity”類別,找到“clickFunction”方法,加入啟動錄音元件的程式碼,還有負責錄音的goToRecord方法: ~~~ public void clickFunction(View view) { int id = view.getId(); switch (id) { case R.id.take_picture: ... case R.id.record_sound: // 錄音檔案名稱 final File recordFile = configFileName("R", ".mp3"); // 如果已經有錄音檔,詢問播放或重新錄制 if (recordFile.exists()) { // 詢問播放還是重新錄制的對話框 AlertDialog.Builder d = new AlertDialog.Builder(this); d.setTitle(R.string.title_record) .setCancelable(false); d.setPositiveButton(R.string.record_play, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 播放 // 在后面的說明才會處理 } }); d.setNeutralButton(R.string.record_new, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { goToRecord(recordFile); } }); d.setNegativeButton(android.R.string.cancel, null); // 顯示對話框 d.show(); } // 如果沒有錄音檔,啟動錄音元件 else { goToRecord(recordFile); } break; ... } } private void goToRecord(File recordFile) { // 錄音 Intent recordIntent = new Intent(this, RecordActivity.class); recordIntent.putExtra("fileName", recordFile.getAbsolutePath()); startActivityForResult(recordIntent, START_RECORD); } ~~~ 為記事資料完成錄音的功能了,在完成后面的播放功能后,再一起執行測試的工作。 ## 12-3 播放語音備忘 在前面已經完成的功能,如果使用者選擇的記事資料已經錄制過語音備忘,應用程式可以選擇播放或是重新錄制: [![AndroidTutorial5_04_01_12](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_12-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_12.png) 使用者選擇播放功能,應用程式啟動播放語音備忘元件,這個元件提供播放、暫停與停止三個功能按鈕: [![AndroidTutorial5_04_01_13](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_13-167x300.png)](http://www.codedata.com.tw/wp-content/uploads/2015/02/AndroidTutorial5_04_01_13.png) 現在設計錄音元件的畫面配置檔,使用的圖形資源可以在GitHub中取得,需要“play_icon.png”、“pause_icon”與“stop_icon.png”三個圖示檔案。開啟“res/values/strings.xml”,加入這個元件需要的文字資源: ~~~ <string name="title_play">播放語音備忘</string> <string name="record_play">播放</string> <string name="record_new">重新錄制</string> ~~~ 在“res/layout”目錄按鼠標右鍵,選擇“New -> Layout resrouce file”,在File name輸入“activity_play”候選擇“OK”。參考下列的內容,完成這個畫面資源的設計: ~~~ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/retangle_drawable" android:layout_margin="6sp" android:padding="6sp" > <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/play_icon" android:onClick="clickPlay" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/pause_icon" android:onClick="clickPause" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/stop_icon" android:onClick="clickStop" /> <SeekBar android:id="@+id/control" android:layout_width="100dp" android:layout_height="wrap_content" android:layout_marginTop="8sp" /> </LinearLayout> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ok_add_teim" android:text="@android:string/ok" android:onClick="onSubmit" /> </LinearLayout> ~~~ 在“net.macdidi.myandroidtutorial”套件按鼠標右鍵,選擇“New -> Java CLass”,在Name輸入“PlayActivity”后選擇“OK”。參考下列的內容完成這個Activity元件的程式碼: ~~~ package net.macdidi.myandroidtutorial; import android.app.Activity; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.net.Uri; import android.os.Bundle; import android.view.View; public class PlayActivity extends Activity { private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_play); Intent intent = getIntent(); String fileName = intent.getStringExtra("fileName"); // 建立指定資源的MediaPlayer物件 Uri uri = Uri.parse(fileName); mediaPlayer = MediaPlayer.create(this, uri); } @Override protected void onStop() { if (mediaPlayer.isPlaying()) { // 停止播放 mediaPlayer.stop(); } // 清除MediaPlayer物件 mediaPlayer.release(); super.onStop(); } public void onSubmit(View view) { // 結束Activity元件 finish(); } public void clickPlay(View view) { // 開始播放 mediaPlayer.start(); } public void clickPause(View view) { // 暫停播放 mediaPlayer.pause(); } public void clickStop(View view) { // 停止播放 if (mediaPlayer.isPlaying()) { mediaPlayer.stop(); } // 回到開始的位置 mediaPlayer.seekTo(0); } } ~~~ 開啟應用程式設定檔“AndroidManifest.xml”,加入這個Activity元件的設定: ~~~ <!-- 播放元件 --> <activity android:name="net.macdidi.myandroidtutorial.PlayActivity" android:theme="@android:style/Theme.Dialog" android:label="@string/title_play"/> ~~~ 完成元件的設計后,開啟在“net.macdidi.myandroidtutorial”套件下的“ItemActivity”類別,找到“clickFunction”方法,加入啟動這個元件的程式碼: ~~~ public void clickFunction(View view) { int id = view.getId(); switch (id) { case R.id.take_picture: ... case R.id.record_sound: // 錄音檔案名稱 final File recordFile = configFileName("R", ".mp3"); // 如果已經有錄音檔,詢問播放或重新錄制 if (recordFile.exists()) { // 詢問播放還是重新錄制的對話框 AlertDialog.Builder d = new AlertDialog.Builder(this); d.setTitle(R.string.title_record) .setCancelable(false); d.setPositiveButton(R.string.record_play, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 播放 Intent playIntent = new Intent( ItemActivity.this, PlayActivity.class); playIntent.putExtra("fileName", recordFile.getAbsolutePath()); startActivity(playIntent); } }); d.setNeutralButton(R.string.record_new, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { goToRecord(recordFile); } }); d.setNegativeButton(android.R.string.cancel, null); // 顯示對話框 d.show(); } // 如果沒有錄音檔,啟動錄音元件 else { goToRecord(recordFile); } break; ... } } ~~~ 同樣在“net.macdidi.myandroidtutorial”套件下的“ItemActivity”類別,找到“onActivityResult”方法,加入設定檔案名稱的程式碼: ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { switch (requestCode) { ... case START_RECORD: // 設定錄音檔案名稱 item.setFileName(fileName); break; ... } } } ~~~ 完成這一章所有的工作了,錄音與播放的功能比較建議在實體的裝置上測試,試試看加入的功能是不是都可以正確的運作。 ## 錯誤修正:4-1 使用照相機與麥克風 這一章加入的照相與錄音功能,把照片與錄音檔案名稱儲存在同一個字段。在完成這一章的內容后依照下列的步驟修正錯誤: 1. 開啟“Item.java”,加入下列的字段與方法宣告: ~~~ // 錄音檔案名稱 private String recFileName; public String getRecFileName() { return recFileName; } public void setRecFileName(String recFileName) { this.recFileName = recFileName; } ~~~ 2. 同樣在“Item.java”,為建構子加入錄音檔案名稱參數: ~~~ // 錄音檔案名稱參數:String recFileName public Item(long id, long datetime, Colors color, String title, String content, String fileName, String recFileName, double latitude, double longitude, long lastModify) { this.id = id; this.datetime = datetime; this.color = color; this.title = title; this.content = content; this.fileName = fileName; // 錄音檔案名稱 this.recFileName = recFileName; this.latitude = latitude; this.longitude = longitude; this.lastModify = lastModify; } ~~~ 3. 開啟“ItemDAO.java”,加入與修改下列的字段宣告: ~~~ ... // 錄音檔案名稱 public static final String RECFILENAME_COLUMN = "recfilename"; ... // 在“FILENAME_COLUMN”下方加入錄音檔案名稱字段 public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ... FILENAME_COLUMN + " TEXT, " + RECFILENAME_COLUMN + " TEXT, " + // 增加錄音檔案名稱 ..."; ~~~ 4. 同樣在“ItemDAO.java”,修改“insert”方法: ~~~ public Item insert(Item item) { ContentValues cv = new ContentValues(); ... cv.put(FILENAME_COLUMN, item.getFileName()); // 錄音檔案名稱 cv.put(RECFILENAME_COLUMN, item.getRecFileName()); ... } ~~~ 5. 同樣在“ItemDAO.java”,修改“update”方法: ~~~ public boolean update(Item item) { ContentValues cv = new ContentValues(); ... cv.put(FILENAME_COLUMN, item.getFileName()); // 錄音檔案名稱 cv.put(RECFILENAME_COLUMN, item.getRecFileName()); ... } ~~~ 6. 同樣在“ItemDAO.java”,修改“getRecord”方法: ~~~ public Item getRecord(Cursor cursor) { ... result.setFileName(cursor.getString(5)); // 錄音檔案名稱 result.setRecFileName(cursor.getString(6)); // 后續的編號都要加一 result.setLatitude(cursor.getDouble(7)); ... } ~~~ 7. 同樣在“ItemDAO.java”,修改“sample”方法: ~~~ public void sample() { // 增加錄音檔案名稱參數“""” Item item = new Item(0, new Date().getTime(), Colors.RED, "關于Android Tutorial的事情.", "Hello content", "", "", 0, 0, 0); Item item2 = new Item(0, new Date().getTime(), Colors.BLUE, "一只非常可愛的小狗狗!", "她的名字叫“大熱狗”,又叫\n作“奶嘴”,是一只非常可愛\n的小狗。", "", "", 25.04719, 121.516981, 0); Item item3 = new Item(0, new Date().getTime(), Colors.GREEN, "一首非常好聽的音樂!", "Hello content", "", "", 0, 0, 0); Item item4 = new Item(0, new Date().getTime(), Colors.ORANGE, "儲存在數據庫的資料", "Hello content", "", "", 0, 0, 0); ... } ~~~ 8. 開啟“MyDBHelper.java”,增加數據庫版本編號: ~~~ // 數據庫版本,資料結構改變的時候要更改這個數字,通常是加一 public static final int VERSION = 2; ~~~ 9. 開啟“ItemActivity.java”,增加錄音檔案名稱字段變量: ~~~ // 錄音檔案名稱 private String recFileName; ~~~ 10. 同樣在“ItemActivity.java”,增加取得錄音檔案名稱的方法: ~~~ private File configRecFileName(String prefix, String extension) { // 如果記事資料已經有檔案名稱 if (item.getRecFileName() != null && item.getRecFileName().length() > 0) { recFileName = item.getRecFileName(); } // 產生檔案名稱 else { recFileName = FileUtil.getUniqueFileName(); } return new File(FileUtil.getExternalStorageDir(FileUtil.APP_DIR), prefix + recFileName + extension); } ~~~ 11. 同樣在“ItemActivity.java”,修改啟動錄音元件的方法: ~~~ public void clickFunction(View view) { int id = view.getId(); switch (id) { ... case R.id.record_sound: // 修改呼叫方法的名稱為“configRecFileName” final File recordFile = configRecFileName("R", ".mp3"); if (recordFile.exists()) { ... } // 如果沒有錄音檔,啟動錄音元件 else { goToRecord(recordFile); } break; ... } } ~~~ 12. 同樣在“ItemActivity.java”,找到“onActivityResult”方法,修改設定錄音檔案名稱呼叫的方法: ~~~ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { switch (requestCode) { ... case START_RECORD: // 修改設定錄音檔案名稱 item.setRecFileName(recFileName); break; ... } } } ~~~ 完成全部的修改以后執行應用程式,測試同一個記事資料照相與錄音的功能。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看