实习杂记(21):LocalBroadcastManager的使用、优点在哪里?

LocalBroadcastManager。

       它来自Android 的support包,类名是android.support.v4.content.LocalBroadcastManager,是用来在同一个应用内的不同组件间发送Broadcast的,刚好与我们的场景相符合。同时,它发送的广播只在app内传播,不会泄漏到其他的应用,安全性也有了保证。而且它的使用方式很简单,与普通的广播类似。

其实这里面说的仅仅是数据安全的问题,还有一个非常的优点  也是非常的重要,当然数据安全是最重要的,

在动态广播里面,广播的范围仅仅是自己的activity里面才有用,或者是自己定义的view里面才有用,(虽然一般很少有人在自定义view里面放广播,因为涉及到VIEW更新,因为把UI更新放在这个层级来做,有点虎,),主要说的是范围太小

在静态广播里面,及时APP被关了,如果收到这个消息,还是会有广播的,这个范围太广,就涉及到上面的那个数据安全,而且需要在xml中注册这个接受者,就是receiver属性,这个也不安全,有可能会被进程给干掉,

现在如果有个业务需求是这样的,自定义一个类(工具、视图等),会被重复的使用,或者当前正在使用的有很多个实例,但是从对象这个方面去看,这么多实例中,某个资源同一个时刻仅能有一个实例对象持有这种资源,其他的都只能等,而且这种资源跟用户的操作有很大的关系,举个例子就是:当上一个实例在用这个资源的时候,由于用户的行为新建一个实例需要立马使用这个资源,那么就需要把上一个实例给停了,

看到这里大家肯定会想到使用  单利模式啊,使用static变量啊,使用同步方法啊,等等,

我的意思是想说使用  LocalBroadCastManager也可以解决这个问题,他可以让类对象自己发自己收,其他的实例对象复本也可以收到,然后让他做自己的操作即可,

下面举个例子就是:需要在  ListView中放视频,每个item都是一个视频,但是只能有一个同时在播放,并且用户点击了一个播放没有关闭的情况下,继续点击另外的播放,需要自动把上面的暂停了,并且保存相关状态(记录位置,暂停进度条,显示暂停图标等等),

在这样的背景下,使用LocalBroadCastManager是可以解决问题的,

下面是item那个view自身需要做的处理类的相关代码,这份代码只是demo,而且我没有处理相关状态,只是以释放和播放来解决问题,请不要直接使用。

public class VideoPlayView extends LinearLayout{ private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; public MediaPlayer mediaPlayer; private boolean isReady = false; private boolean mIsPlaying = false; private boolean mIsPause = false; private Context context; public String path; public static String time; LocalBroadcastManager mLocalBroadcastManager;  public static final String STATICACTION  = "xxxxx.dynamic.view"; @SuppressLint("NewApi") public VideoPlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); this.context = context; initView(context); } @SuppressLint("NewApi") public VideoPlayView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; initView(context); } public VideoPlayView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; initView(context); } public VideoPlayView(Context context) { super(context); this.context = context; initView(context); } private void initView(Context context) { LayoutInflater.from(context).inflate(R.layout.public_infoflow_video_play, this, true); mSurfaceView =(SurfaceView) findViewById(R.id.surfaceview); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(new CustomCallBack()); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); MySetOnClickListener(mSurfaceView); mLocalBroadcastManager = LocalBroadcastManager.getInstance(context); IntentFilter intentFilter = new IntentFilter(STATICACTION); mLocalBroadcastManager.registerReceiver(dynamicReceiver, intentFilter); } private void MySetOnClickListener(View view) { if(view==null){ return ; }else{ view.setOnClickListener(mClickListener); } } private OnClickListener mClickListener = new OnClickListener(){ @Override public void onClick(View v) { Intent intent = new Intent();               intent.setAction(STATICACTION);               intent.putExtra("msg", getPath());               mLocalBroadcastManager.sendBroadcast(intent); if(path!=null && isReady && !mIsPlaying){ mIsPlaying =true; mIsPause = false; isReady = false; play(0); }else if(mediaPlayer!=null && mediaPlayer.isPlaying()&& mIsPlaying && !mIsPause ){ mediaPlayer.pause(); mIsPlaying = false; mIsPause = true; isReady = true; release(); }else{ mIsPlaying =true; mIsPause = false; isReady = false; play(0); } } }; private BroadcastReceiver dynamicReceiver = new BroadcastReceiver() {           @Override           public void onReceive(Context context, Intent intent) {               if(intent.getAction().equals(STATICACTION)){                  String receive_path = intent.getStringExtra("msg");                 if(!path.equals(receive_path)){ release();                 }             }           }       };  private class CustomCallBack implements Callback{ @Override public void surfaceCreated(SurfaceHolder holder) { isReady = true; mIsPlaying = false; if (mediaPlayer != null) { if (mediaPlayer.isPlaying()) { mIsPlaying = false; release(); } } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { release(); mIsPlaying = false; } @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsPlaying = false; release(); mLocalBroadcastManager.unregisterReceiver(dynamicReceiver); } } public String getPath() { return path; } public void play(int position) { try { if(mediaPlayer == null){ mediaPlayer = new MediaPlayer(); } mediaPlayer.reset(); mediaPlayer.setDataSource(path); mediaPlayer.setDisplay(mSurfaceView.getHolder()); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new PrepareListener(position)); mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { mp.release(); mIsPlaying = false; return true; } }); mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { release(); } }); } catch (Exception e) { e.printStackTrace(); }  } protected void release() { if(mediaPlayer!=null){ mediaPlayer.setOnErrorListener(null); try { mediaPlayer.stop(); mediaPlayer.release(); } catch (Exception e) { } } mediaPlayer = null; } private final class PrepareListener implements OnPreparedListener{ private int position; public PrepareListener(int position){ this.position = position; } @Override public void onPrepared(MediaPlayer mp) { mediaPlayer.start(); } } public void freeResource() { if(mediaPlayer.isPlaying()){ mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } } public void setPath(String path) { this.path = path; } }

需要工程包的请留言,暂时代码还没有整理,后面补发。

其实使用这种方式比  单利模式,static变量,同步方法要好些,因为资源最后还是  两份直接轮换,一个current和一个next,双层机制,

音乐播放的时候是使用当前的mediaPlayer和预加载的mediaPlayer,

大视频的无缝播放也是采用两个mediaPlayer来实现的,

而且这种方式附带的在处理相关属性的过程中将会更加的独立,自己处理自己的事多好,如果使用static,判断条件实在太多,而且在退出的时候还需要考虑释放的问题,

当然这种做法也有不好的地方,全屏(如果是使用activity跳转的话)的时候再回来就麻烦了,

w

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券