使用通知
當某個應用程式希望向用戶發出一些提示資訊,而該應用程式又不在前臺運行時,就可以借助通知來實作,發出一條通知后,手機最上方的狀態欄中會顯示一個通知的圖示,下拉狀態欄后可以看到通知的詳細內容,
基本用法
構建一個通知
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendNotice = (Button)findViewById(R.id.send_notice);
sendNotice.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.send_notice:
//通過Context的getSystemService方法獲得NotificationManager 可以對通知進行管理
//傳入的引數用于確定獲取系統的哪個服務
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//需要Builder構造器來創建Notification物件
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
//指定通知的標題內容 下拉狀態欄就可以看到這部分內容
.setContentTitle("This is content title")
//指定通知正文內容 下拉狀態欄就可以看到這部分內容
.setContentText("This is content text")
//用于指定通知被創建的時間 以毫秒為單位
.setWhen(System.currentTimeMillis())
//設定通知的小圖示 只能使用純alpha圖層的圖片進行設定 小圖示會顯示在系統狀態欄上
.setSmallIcon(R.mipmap.ic_launcher)
//用于設定通知的大圖示
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.build();
//讓通知訊息顯示出來 第一個引數是id 第二個是Notification物件
manager.notify(1, notification);
break;
default:
break;
}
}
}
實作通知的點擊效果,
使用PendingIntent.從名字上看起來就和Intent有些類似,它們之間也確實存在著不少共同點,比如它們都可以去指明某一個“意圖”,都可以用于啟動活動、啟動服務以及發送廣播等,不同的是,Intent更加傾向于去立即執行某個動作,而PendingIntent 更加傾向于在某個合適的時機去執行某個動作,所以,也可以把PendingIntent簡單地理解為延遲執行的Intent,
PendingIntent的用法同樣很簡單,它主要提供了幾個靜態方法用于獲取PendingIntent的實體,可以根據需求來選擇是使用getActivity()方法、getBroadcast()方法, 還是getService()方法,這幾個方法接收的物件都相同,第一個引數是context,第二個一般傳入0,第三個是一個Intent物件,可以通過這個物件構建出PendingIntent的“意圖”,第四個引數用于確定PendingIntent的行為,有FLAG_ONE_SHOT,FLAG_UPDATE_CURRENT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,通常情況下傳入0,
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.send_notice:
//創建一個意圖 使用intent表達出我們的意圖
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
//通過Context的getSystemService方法獲得NotificationManager 可以對通知進行管理
//傳入的引數用于確定獲取系統的哪個服務
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//需要Builder構造器來創建Notification物件
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
//指定通知的標題內容 下拉狀態欄就可以看到這部分內容
.setContentTitle("This is content title")
//指定通知正文內容 下拉狀態欄就可以看到這部分內容
.setContentText("This is content text")
//用于指定通知被創建的時間 以毫秒為單位
.setWhen(System.currentTimeMillis())
//設定通知的小圖示 只能使用純alpha圖層的圖片進行設定 小圖示會顯示在系統狀態欄上
.setSmallIcon(R.mipmap.ic_launcher)
//用于設定通知的大圖示
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
//通過pendingIntent構建出一個延遲的意圖
.setContentIntent(pendingIntent)
.build();
//讓通知訊息顯示出來 第一個引數是id 第二個是Notification物件
manager.notify(1, notification);
break;
default:
break;
}
}
點擊后狀態欄通知消失
- 顯式的呼叫NotificationManager的cancel方法
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//點擊后狀態欄通知消失 想取消哪條通知傳入該通知id
manager.cancel(1);
- 在NotificationCompat.Builder后連綴setAutoCancel
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//點擊后狀態欄通知消失
.setAutoCancel(true)
.build();
通知的進階
設定收到訊息的音頻
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//指定收到訊息的音頻 接受一個Uri引數
.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
.build();
設定收到訊息時震動
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//指定收到時手機的震動 傳入一個長整型的陣列 用于設定手機靜止和震動的時長 一毫秒為單位
//單數下標代表震動的時長 雙數代表靜止的時長
.setVibrate(new long[] {0, 1000, 1000, 1000, 1000, 1000})
.build();
控制震動需要宣告權限
<uses-permission android:name="android.permission.VIBRATE"/>
設定收到訊息時LED燈
三個引數,第一個用于指定顏色,第二個指定亮起的時長,第三個指定暗的時長,
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//指定收到訊息時的LED燈
.setLights(Color.WHITE, 1000, 1000)
.build();
默認效果
可以根據當前手機環境來決定播放什么鈴聲,以及如何震動
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//默認模式
.setDefaults(NotificationCompat.DEFAULT_ALL)
.build();
創建渠道并設定重要性
在 Android 8.0 及更高版本上使用通知,必須先通過向 createNotificationChannel() 傳遞 NotificationChannel 的實體在系統中注冊應用的通知渠道
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel=new NotificationChannel("my_channel_01","R.string.channel_name", NotificationManager.IMPORTANCE_DEFAULT);
//notificationChannel.setDescription(CHANNEL_DESCRIPTION);
NotificationManager notificationManager=getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(notificationChannel);
}
通知的高級功能
先來看看setStyle()方法,這個方法允許我們構建出富文本的通知內容,也就是說通知中不光可以有文字和圖示,還可以包含更多的東西,setStyle()方法接收 一個NotificationCompat.Style引數,這個引數就是用來構建具體的富文本資訊的,如長文字、圖片等,
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//添加富文本資訊 創建一個NotificationCompat.BigTextStyle物件 這個物件用于封裝長文字資訊 呼叫bigText并將文字內容傳入即可
.setStyle(new NotificationCompat.BigTextStyle().bigText("街頭的血液等待著迸發,屹立在懸崖邊盛開的紅花 "))
//顯示一張大圖片
.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.big_image)))
.build();
設定訊息的重要程度
Notification notification = new NotificationCompat.Builder(MainActivity.this,"my_channel_01")
...
//設定訊息的重要程度
.setPriority(NotificationCompat.PRIORITY_MAX)
.build();
呼叫攝像頭和相冊
呼叫攝像頭拍照
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button takePhoto = (Button) findViewById(R.id.take_photo);
picture = (ImageView)findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//創建File物件 用于存盤拍照后的圖片
//將圖片命名為"output_image.jpg" 并將它存放在手機SD卡的應用關聯快取目錄下 getExternalCacheDir()可以得到這個目錄
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if(outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
}catch (IOException e) {
e.printStackTrace();
}
if(Build.VERSION.SDK_INT >= 24) {
//呼叫FileProvider.getUriForFile方法將File物件轉換成一個封裝過的Uri物件
//接收三個引數,第一個Context物件 第二個可以是任意唯一的字串 第三個時創建的File物件
//對資料進行保護
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalbumtest.fileprovider", outputImage);
}else {
imageUri = Uri.fromFile(outputImage);
}
//啟動相機程式 指定action 隱式Intent
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//putExtra指定圖片的輸出地址 填入Uri物件
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
//啟動活動
startActivityForResult(intent, TAKE_PHOTO);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
//如果拍照成功 呼叫BitmapFactory.decodeStream將照片決議成Bitmap物件
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
}
應用關聯快取目錄就是指SD卡中專門用于存放當前應用快取資料的位置,呼叫getExternalCacheDir()方法可以得到這個目錄,具體的路徑是/sdcard/Android/data/<package name>/cache,
使用應用關聯緩目錄來存放圖片是因為從Android 6.0系統開始,讀寫SD卡被列為了危險權限,如果將圖片存放在SD卡的任何其他目錄,都要進行運行時權限處理才行,而使用應用關聯目錄則可以跳過這一步,
接著會進行一個判斷,如果運行設備的系統版本低于Android 7.0,就呼叫Uri的fromFile()方法將File物件轉換成Uri物件,這個Uri物件標識著output_ jimage.jpg 這張圖片的本地真實路徑,否則,就呼叫FileProvider 的getUriForFile()方法將File 物件轉換成一個封裝過的Uri物件,getUriForFile()方法接收3個引數,第一個引數要求傳人Context物件,第二個引數可以是任意唯一的字串, 第三個引數則是我們剛剛創建的File物件,
之所以要進行這樣一層轉換,是因為從Android7.0系統開始,直接使用本地真實路徑的Uri被認為是不安全的,會拋出一個FileUriExposedException 例外,而FileProvider 則是一種特殊的內容提供器,它使用了和內容提供器類似的機制來對資料進行保護,可以選擇性地將封裝過的Uri共享給外部,從而提高了應用的安全性,
接下來構建出了一個Intent物件,并將這個Intent的action指定為android.media.action. IMAGE_ CAPTURE, 再呼叫Intent的putExtra()方法指定圖片的輸出地址,這里填入剛剛得到的Uri物件,最后呼叫startActivityForResult()來啟動活動,由于我們使用的是個隱式Intent,系統會找出能夠回應這個Intent 的活動去啟動,這樣照相機程式就會被打開,拍下的照片將會輸出到output_image.jpg 中,
注意,剛才我們是使用startActivityForResult()來啟 動活動的,因此拍完照后會有結果回傳到onActivityResult()方法中,如果發現拍照成功,就可以呼叫BitmapFactory 的decodeStream( )方法將output_ image.jpg這張照片決議成Bitmap物件,然后把它設定到Image-View中顯示出來,
在AndroidManifest.xml中對內容提供器進行注冊了,如下所示:
<application
...
<provider
android:authorities="com.example.cameraalbumtest.fileprovider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
...
</application>
其中,android:name 屬性的值是固定的,android: authorities屬性的值必須要和剛才FileProvider.getUriForFile()方法中的第二個引數一致,另外,這里還在<provider>標簽的內部使用<meta- data>來指定Uri的共享路徑,并參考了一個@xml/file_ paths 資源,
file_paths.xml
<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="my_images"
path="/" />
</paths>
其中,external-path 就是用來指定Uri共享的,name 屬性的值可以隨便填,path屬性的值表示共享的具體路徑,這里設定/就表示將整個SD卡進行共享,當然你也可以僅共享我們存放output_image.jpg 這張圖片的路徑,
另外還有一點要注意,在Android 4.4系統之前,訪問SD卡的應用關聯目錄也是要宣告權限的,從4.4系統開始不再需要權限宣告,那么我們為了能夠兼容老版本系統的手機,還需要在AndroidManifest.xml中宣告一下訪問SD卡的權限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
從相冊中選擇照片
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
private static final int CHOOSE_PHOTO = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button takePhoto = (Button) findViewById(R.id.take_photo);
Button chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);
picture = (ImageView)findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//創建File物件 用于存盤拍照后的圖片
//將圖片命名為"output_image.jpg" 并將它存放在手機SD卡的應用關聯快取目錄下 getExternalCacheDir()可以得到這個目錄
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if(outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
}catch (IOException e) {
e.printStackTrace();
}
if(Build.VERSION.SDK_INT >= 24) {
//呼叫FileProvider.getUriForFile方法將File物件轉換成一個封裝過的Uri物件
//接收三個引數,第一個Context物件 第二個可以是任意唯一的字串 第三個時創建的File物件
//對資料進行保護
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalbumtest.fileprovider", outputImage);
}else {
imageUri = Uri.fromFile(outputImage);
}
//啟動相機程式 指定action 隱式Intent
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//putExtra指定圖片的輸出地址 填入Uri物件
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
//啟動活動
startActivityForResult(intent, TAKE_PHOTO);
}
});
chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//進行運行時權限處理 動態申請WRITE_EXTERNAL_STORAGE 從SD卡中讀取資料需要這個權限
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
//打開相冊
openAlbum();
}
}
});
}
//打開相冊
private void openAlbum() {
//隱式intent
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
//打開相冊 第二個引數表示選擇完圖片回到onActivityResult方法時 會進入CHOOSE_PHOTO的case來處理圖片
startActivityForResult(intent, CHOOSE_PHOTO);
}
//動態設定權限的選擇欄
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//選擇可以后打開相冊
openAlbum();
} else {
//拒絕認可
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
//活動結果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
//如果拍照成功 呼叫BitmapFactory.decodeStream將照片決議成Bitmap物件
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
case CHOOSE_PHOTO:
if(resultCode == RESULT_OK) {
//判斷手機系統版本號
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//4.4及以上的系統 Android系統從4.4版本開始,選取相冊中的圖片不在回傳圖片真實的Uri 而是一個封裝過的 需要決議
handleImageOnKitKat(data);
}else {
handleImageBeforeKitKat(data);
}
break;
}
default:
break;
}
}
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
//獲取真實的路徑
String imagePath = getImagePath(uri, null);
//將圖片顯示到界面上
displayImage(imagePath);
}
//將圖片顯示到界面上
private void displayImage(String imagePath) {
if(imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
picture.setImageBitmap(bitmap);
}else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
private void handleImageOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
if(DocumentsContract.isDocumentUri(this, uri)) {
String docId = DocumentsContract.getDocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())) {
//決議出數字格式的id
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
}else if("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
}else if("content".equalsIgnoreCase(uri.getScheme())) {
//如果是content型別的Uri 使用普通方法解決
imagePath = getImagePath(uri, null);
}else if("file".equalsIgnoreCase(uri.getScheme())) {
//如果是file型別的Uri 直接獲取圖片路徑
imagePath = uri.getPath();
}
//根據圖片路徑顯示圖片
displayImage(imagePath);
}
private String getImagePath(Uri uri, String selection) {
String path = null;
//通過Uri和selection來獲取真實的圖片路徑
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if(cursor != null) {
if(cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
}
可以看到,在Choose From Album按鈕的點擊事件里我們先是進行了一個運行時權限處理,動態申請WRITE_EXTERNAL_ STORAGE 這個危險權限,因為相冊中的照片都是存盤在SD卡上的,我們要從SD卡中讀取照片就需要申請這個權限,WRITE_EXTERNAL_ STORAGE表示同時授予程式對SD卡讀和寫的能力,
當用戶授權了權限申請之后會呼叫openAlbum()方法,這里我們先是構建出了一個Intent物件,并將它的action指定為android. intent . action . GET_ CONTENT, 接著給這個Intent物件設定引數,然后調startActivityForResult() 方法就可以打開相冊程式選擇照片了,注意在呼叫startActivityForResult()方法的時候, 我們給第二個引數傳人的值變成了CHOOSE_ PHOTO,這樣當從相冊選擇完圖片回到onActivityResult()方法時,就會進人CHOOSE_ PHOTO 的case來處理圖片,
為了兼容新老版本的手機,我們做了一個判斷,如果是4.4及以上系統的手機就呼叫handleImage0nKitKat()方法來處理圖片,否則就呼叫handleImageBeforeKitKat()方法來處理圖片,因為Android系統從4.4 版本開始,選取相冊中的圖片不再回傳圖片真實的Uri了,而是個封裝過的Uri,因此如果是4.4版本以上的手機就需要對這個Uri進行決議才行,
那么handleImage0nKitKat()方法中的邏輯就基本是如何決議這個封裝過的Uri了,這里有好幾種判斷情況,如果回傳的Uri是document型別的話,那就取出document id進行處理,如果不是的話,那就使用普通的方式處理,另外,如果Uri的authority是media格式的話, documentid還需要再進行一次決議,要通過字串分割的方式取出后半部分才能得到真正的數字id,取出的id用于構建新的Uri和條件陳述句,然后把這些值作為引數傳人到getImagePath()方法當中, 就可以獲取到圖片的真實路徑了,拿到圖片的路徑之后,再呼叫displayImage()方法將圖片顯示到界面上,
播放多媒體檔案
播放音頻
Android中播放音頻檔案一般都是使用MediaPlayer類來實作,它對多種格式的音頻檔案提供了非常全面的控制方法,下面列出比較常用的控制方法

MediaPlayer的作業流程,首先創建出一個MediaPlayer物件,呼叫setDataSource()方法來設定音頻檔案的路徑,呼叫prepare()方法使MediaPlayer進入準備狀態,呼叫start()就可以開始播放音頻,呼叫pause()方法會暫停播放,reset()會停止播放,
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//創建MediaPlayer實體
private MediaPlayer mediaPlayer = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button play = (Button)findViewById(R.id.play);
Button stop = (Button) findViewById(R.id.stop);
Button pause = (Button)findViewById(R.id.pause);
play.setOnClickListener(this);
stop.setOnClickListener(this);
pause.setOnClickListener(this);
//運行時權限處理 訪問SD卡
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
//初始化MediaPlayer
initMediaPlayer();
}
}
private void initMediaPlayer() {
try {
//通過File物件來指定音頻檔案的路徑
File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
//指定音頻檔案的路徑
mediaPlayer.setDataSource(file.getPath());
//讓MediaPlayer進入到準備狀態
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
//請求許可的結果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//初始化MediaPlayer物件
initMediaPlayer();
}else {
//拒絕后關閉程式
Toast.makeText(this, "拒絕權限將無法使用程式", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.play:
if(!mediaPlayer.isPlaying()) {
//開始播放
mediaPlayer.start();
}
break;
case R.id.pause:
if(mediaPlayer.isPlaying()) {
//暫停播放
mediaPlayer.pause();
}
break;
case R.id.stop:
if(mediaPlayer.isPlaying()) {
//停止播放
mediaPlayer.reset();
initMediaPlayer();
}
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
可以看到,在類初始化的時候我們就先創建了一個MediaPlayer的實體,然后在onCreate()方法中進行了運行時權限處理,動態申請WRITE_ EXTERNAL_ STORAGE 權限,這是由于待會我們會在SD卡中放置一個音頻檔案,程式為了播放這個音頻檔案必須擁有訪問SD卡的權限才行,
注意,在onRequestPermissionsResult()方法中,如果用戶拒絕了權限申請,那么就呼叫finish()方法將程式直接關掉,因為如果沒有SD卡的訪問權限,我們這個程式將什么都干不了,
用戶同意授權之后就會呼叫initMediaPlayer()方法為MediaPlayer 物件進行初始化操作,在initMediaPlayer()方法中,首先是通過創建一個File物件來指定音頻檔案的路徑,從這里可以看出,我們需要事先在SD卡的根目錄下放置一個名為music.mp3的音頻檔案,后面依次呼叫了setDataSource ()方法和prepare()方法,為MediaPlayer做好了播放前的準備,
接下來我們看一下各個按鈕的點擊事件中的代碼,當點擊Play按鈕時會進行判斷,如果當前MediaPlayer沒有正在播放音頻,則呼叫start()方法開始播放,當點擊Pause按鈕時會判斷,如果當前MediaPlayer正在播放音頻,則呼叫pause()方法暫停播放,當點擊Stop按鈕時會判斷,如果當前MediaPlayer正在播放音頻,則呼叫reset()方法將MediaPlayer重置為剛剛創建的狀態,然后重新呼叫一-遍initMediaPlayer()方法,
最后在onDestroy()方法中,我們還需要分別呼叫stop()方法和 release()方法,將與MediaPlayer相關的資源釋放掉,
添加權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
播放視頻
主要使用VideoView類來實作,這個類將視頻的顯示與控制集于一身,

這部分代碼相信你理解起來會很輕松,因為它和前面播放音頻的代碼非常類似,首先在onCreate()方法中同樣進行了一個運行時權限處理,因為視頻檔案將會放在SD卡上,當用戶同意授權了之后就會呼叫initVideoPath()方法來設定視頻檔案的路徑,這里我們需要事先在SD卡的根目錄下放置-一個名為movie.mp4的視頻檔案,
VideoView幫我們做了一個很好的封裝,背后使用的仍然是MediaPlayer來對視頻進行控制
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoView = (VideoView) findViewById(R.id.video_view);
Button play = (Button)findViewById(R.id.play);
Button pause = (Button)findViewById(R.id.pause);
Button replay = (Button)findViewById(R.id.replay);
play.setOnClickListener(this);
pause.setOnClickListener(this);
replay.setOnClickListener(this);
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
//初始化MediaPlayer
initVideoPath();
}
}
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "video.mp4");
//Toast.makeText(this, "lll",Toast.LENGTH_SHORT).show();
//指定視頻檔案的路徑
//videoView.setVideoPath(file.getPath());
Log.d("TAG", file.getPath());
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initVideoPath();
}else {
Toast.makeText(this, "拒絕權限將無法使用程式", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.play:
if(!videoView.isPlaying()) {
//開始播放
videoView.start();
}
break;
case R.id.pause:
if(videoView.isPlaying()) {
//暫停播放
videoView.pause();
}
break;
case R.id.replay:
if(videoView.isPlaying()) {
//開始播放
videoView.resume();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(videoView != null) {
videoView.suspend();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/293386.html
標籤:其他
