android四大元件(3)(BroadcastReceiver)
一、aandroid的四大元件BroadcastReceiver廣播接收器(用於接收程式所發出的Broadcast Intent),其本生就是一個全域性的監聽器,用於監聽系統全域性的廣播訊息。由於BroadcastReceiver是全域性的監聽器,所以它可以非常方便地實現系統中不同元件之間地通訊。
例如:客戶端於一個service(用startService())啟動的服務通訊,就可以藉助於BroadcastReceiver來實現通訊。
二、傳送廣播
1、需要建立BroadcastReceiver的Intent
2、需要為intent新增Action屬性,intent.setAction(".........");
3、呼叫Context的sendBroadcast(Intent intent)(傳送普通廣播)或者sendOrderedBroadcast(Intent intent)(傳送有序廣播)。
其中普通廣播是完全非同步的,可同一時刻被所有接受者收到,訊息傳遞的效率比較高。
其中有序廣播,接收者將按照預先宣告的優先順序依次接收廣播資訊,優先順序高的可以切斷廣播,阻止其向下傳播(abortBroadcast()),其中設定優先順序是在, <intent-filter......./>元素的android:priority屬性中,數越大優先順序越大,取值範圍在-1000~1000中,也可以呼叫IntentFilter物件的setPriority()設定優先順序。
收到訊息的廣播可以通過setResultExtras(Bundle )的方法將處理的結果傳如Broadcast中,然後傳遞給下一個接收者,下一個接收者通過,Bundle bundle=getResultExtras(true)來獲取上一個接收者存入的資料。
三、重寫廣播接收器:BroadcastReceive
重寫BroadcastReceive的子類,繼承BroadcastReceive
只需要重寫onReceive(Context context,Intent intent)方法。
四:註冊BroadcastReceive
有兩種方法:
1、重寫了BroadcastReceive的子類後,靜態註冊,在androidManifest.xml檔案中靜態註冊:
<receiver android:name=".SmsReceiver.SmsReceiver"> <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> </receiver>
2、重寫了BroadcastReceive的子類後,在java程式碼中動態註冊:
IntentFilter intentFilter=new IntentFilter(); //建立IntentFilter物件 intentFilter.addAction("android.totole"); //給IntentFilter物件新增action SmsReceiver receiver=new SmsReceiver(); //接收者例項 registerReceiver(receiver,intentFilter); //註冊廣播接收器
五、接收系統廣播資訊:
六、本地廣播
本地廣播的幾個優勢:
1、只在自己的程式中傳送廣播,不但行資料的洩露
2、其他程式的廣播無法送進我們的程式
3、本地廣播比傳送全域性廣播更有效
本地廣播是要使用一個LocalBroadcastManager來對廣播進行管理,並提供,傳送廣播,和註冊廣播接收器。
LocalBroadcastManager例項:是通過LocalBroadcastManager.getInstance(this)獲取
傳送廣播:LocalBroadcastManager.sendBroadcast(intent) ;//傳送
註冊廣播:LocalBroadcastManager.registerReceiver(localReceiver,intentFilter); //註冊
例項:後臺服務播放的音樂,前臺傳送廣播給後臺服務,服務收到訊息,就開始播放或者其他動作,中間的資訊傳遞通過廣播來實現:
1、後臺的service
public class MusicService extends Service { MyReceiver receiver=new MyReceiver(); MediaPlayer mediaPlayer=new MediaPlayer(); private List<String> mMusicList=new ArrayList(); //定義音樂播放器,0x11代表沒有播放,0x12代表正在播放,0x13代表暫停播放,0x14代表下一曲,0x15代表上一曲 int status=0x11; int current=0; MyBinder binder=new MyBinder(); class MyBinder extends Binder{ public void init(List<String> list){ mMusicList=list; Toast.makeText(MusicService.this,"資料傳輸成功",Toast.LENGTH_SHORT).show(); } } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } public void onCreate(){ super.onCreate(); //註冊廣播接受器,監聽前臺發過來的訊息 IntentFilter filter=new IntentFilter(); filter.addAction(MainActivity.CTL_ACTION); registerReceiver(receiver,filter); //mediaPlayer註冊監聽器,監聽是否播放完畢,如果播放發完畢,播放下一曲,並通知Activity更新ui mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { current++; if(current>=mMusicList.size()) current=0; //播放完一曲,播放下一曲,併發出廣播Activity介面更新 Intent intent=new Intent(MainActivity.UPDATE_ACTION); intent.putExtra("current",current); intent.putExtra("status",status); sendOrderedBroadcast(intent,null); Toast.makeText(MusicService.this,"向前臺發廣播資訊",Toast.LENGTH_SHORT).show(); //播放下一曲 preparedAndPlay(mMusicList.get(current)); } }); } //廣播接受器,接受Activity介面傳過來的訊息 public class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Toast.makeText(MusicService.this,"接收到前臺的廣播資訊",Toast.LENGTH_SHORT).show(); int control=intent.getIntExtra("control",-1); switch (control){ case 1:{ //前臺Activity按下Start按鈕 if(status==0x11){ //後臺還處於沒有播放音樂,按下Start按鈕 //準備並播放 preparedAndPlay(mMusicList.get(current)); status=0x12; } else if (status==0x12){ //後臺處於播放狀態,按下Start按鈕 //暫停 mediaPlayer.pause(); status=0x13; } else if(status==0x13){// 後臺原來處於暫停狀態,按下Start按鈕 //播放 mediaPlayer.start(); status=0x12; } Toast.makeText(MusicService.this,"播放:"+mMusicList.get(current),Toast.LENGTH_SHORT).show(); break; } case 2:{ //前臺Activity按下Stop按鈕 if(status==0x12||status==0x13){ //後臺如果正在播放或者暫停,按下Stop按鈕 //停止播放 mediaPlayer.stop(); status=0x11; } break; } case 3:{ //前臺Activity按下front按鈕 current++; if(current>=mMusicList.size()){ current=0; } preparedAndPlay(mMusicList.get(current)); status=0x14; break; } case 4:{ //前臺Activity按下next按鈕 current--; if(current<0) { current = mMusicList.size() - 1; } preparedAndPlay(mMusicList.get(current)); status=0x15; break; } default: break; } abortBroadcast(); //發出廣播通知activity更新ui Intent intent1=new Intent(MainActivity.UPDATE_ACTION); intent1.putExtra("update",status); intent1.putExtra("current",current); sendOrderedBroadcast(intent1,null); Toast.makeText(MusicService.this,"向前臺發廣播資訊",Toast.LENGTH_SHORT).show(); } } private void preparedAndPlay(String music){ try{ mediaPlayer.reset(); mediaPlayer.setDataSource(mMusicList.get(current)); mediaPlayer.prepare(); mediaPlayer.start(); } catch (IOException e) { e.printStackTrace(); } } }
2、在xml的介面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.asus.musicplay.MainActivity"> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/list" android:layout_weight="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="播放" android:id="@+id/Start" android:layout_margin="5px"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="暫停" android:layout_margin="5px" android:id="@+id/Stop"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="上一曲" android:layout_margin="5px" android:id="@+id/front"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下一曲" android:layout_margin="5px" android:id="@+id/next"/> </LinearLayout> </LinearLayout>
3、activity
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button Start=null; private Button Stop=null; private Button front=null; private Button next=null; private ListView list=null; //資料 private List<String> mMusicList=new ArrayList();//前端 private List<String> mMusicList1=new ArrayList();//後臺服務 //前臺Activity按下按鈕時,發出的廣播資訊 (也是後臺服務的廣播接受器,接受前臺打過來的廣播) public static final String CTL_ACTION="CTL_ACTION"; //前臺Activity接受後臺服務發過來的廣播資訊 (也是後臺向前臺傳送的廣播資訊) public static final String UPDATE_ACTION="UPDATE_ACTION"; public int statu=0x11; //定義音樂播放器,0x11代表沒有播放,0x12代表正在播放,0x13代表暫停播放,0x14代表下一曲,0x15代表上一曲 private static final String MUSIC_PATH=new String("/sdcard/"); private MusicService.MyBinder binder; private ServiceConnection connection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { binder=(MusicService.MyBinder)iBinder; Toast.makeText(MainActivity.this,"服務連線成功",Toast.LENGTH_SHORT).show(); binder.init(mMusicList1); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Start=findViewById(R.id.Start); Stop=findViewById(R.id.Stop); front=findViewById(R.id.front); next=findViewById(R.id.next); list=findViewById(R.id.list); Start.setOnClickListener(this); Stop.setOnClickListener(this); front.setOnClickListener(this); next.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{ musicList(); } //註冊廣播接受器,監聽後臺服務打過來的訊息 ActivityReceive receive=new ActivityReceive(); IntentFilter filter=new IntentFilter(); filter.addAction(UPDATE_ACTION); registerReceiver(receive,filter); Intent intent=new Intent(this,MusicService.class); bindService(intent,connection,BIND_AUTO_CREATE); } public void onRequestPermissionsResult(int requestCode,String []permissions,int []grantResults){ switch (requestCode){ case 1:{ if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){ musicList(); }else{ Toast.makeText(this,"拒絕授權",Toast.LENGTH_SHORT).show(); } } break; default: } } public void musicList(){ File home=new File(MUSIC_PATH); if(home.listFiles(new MusicFilter()).length>0){ for(File file:home.listFiles(new MusicFilter())) { Log.i("TAG",file.getAbsolutePath()); mMusicList.add(file.getName()); mMusicList1.add(file.getPath()); } } ArrayAdapter<String> adapter=new ArrayAdapter<String>(MainActivity.this,R.layout.musicitem,mMusicList); list.setAdapter(adapter); } @Override public void onClick(View view) { //介面Activity發出廣播訊息,後臺服務的廣播接受到訊息,服務進行相應的播放 Intent intent=new Intent(); intent.setAction(CTL_ACTION); switch (view.getId()){ case R.id.Start:{ intent.putExtra("control",1); break; } case R.id.Stop:{ intent.putExtra("control",2); break; } case R.id.front:{ intent.putExtra("control",3); break; } case R.id.next:{ intent.putExtra("control",4); break; } default: break; } //傳送訊息 sendOrderedBroadcast(intent,null); Toast.makeText(MainActivity.this,"向後臺發廣播資訊",Toast.LENGTH_SHORT).show(); } // public class ActivityReceive extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Toast.makeText(MainActivity.this,"接收到後臺發廣播資訊",Toast.LENGTH_SHORT).show(); //獲取Intent中的update訊息,update代表播放狀態 int update=intent.getIntExtra("update",-1); int current=intent.getIntExtra("current",-1); if(current>=0){ Toast.makeText(MainActivity.this,mMusicList.get(current)+"",Toast.LENGTH_SHORT).show(); } //根據後臺服務傳送的廣播資訊,看播放的情況是什麼(播放還是暫停),更新ui switch (update){ case 0x11: statu=0x11; break; case 0x12: statu=0x12; break; case 0x13: statu=0x13; break; case 0x14: statu=0x14; break; case 0x15: statu=0x15; break; default: break; } abortBroadcast(); } } class MusicFilter implements FilenameFilter { public boolean accept(File dir,String name){ return (name.endsWith(".mp3")); } } }