在开发的工程中,我们经常会遇到,在项目的一些方法执行时,我们想知道,此时的这个方法处于什么阶段,然后将这个阶段返回给前台UI。通俗的举个例子来说,比如我们播放音频,有这个几个过程
然后,我们执行播放的不同状态中,更新我们上面定义的4个状态,然后回调给Activity,此时Activity就可以进行提示展示。
为什么我们要搞得这么麻烦呢?
比如,我现在实现一个音视频直播。在这个过程中,包含了编解码的过程,音视频频播放的过程以及RTMP推流的过程。我们分别写了3个类,分别是编解码、音视频播放、RTMP推流,然后我们主Activity要知道,这些过程中到底走到哪一步了。此时,我们可以通过状态回调的方式返回给Activity,然后在回调中去处理。
下来看看代码,这样会比较清晰的多
MainActivity.java
package test.com.livetest;
import android.app.Activity;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.github.faucamp.simplertmp.RtmpHandler;
import com.seu.magicfilter.utils.MagicFilterType;
import net.ossrs.yasea.SrsCameraView;
import net.ossrs.yasea.SrsEncodeHandler;
import net.ossrs.yasea.SrsPublisher;
import net.ossrs.yasea.SrsRecordHandler;
import java.io.IOException;
import java.net.SocketException;
/**
* Created by Sikang on 2017/5/2.
*/
public class CameraActivity extends Activity implements SrsEncodeHandler.SrsEncodeListener, RtmpHandler.RtmpListener, SrsRecordHandler.SrsRecordListener, View.OnClickListener {
private static final String TAG = "CameraActivity";
private SrsPublisher mPublisher;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_camera);
```
mPublisher = new SrsPublisher();
//编码状态回调
mPublisher.setEncodeHandler(new SrsEncodeHandler(this));
//播放状态回调
mPublisher.setRecordHandler(new SrsRecordHandler(this));
//rtmp推流状态回调
mPublisher.setRtmpHandler(new RtmpHandler(this));
```
}
// 这下面就是这三个类回调的状态
@Override
public void onNetworkWeak() {
Toast.makeText(getApplicationContext(), "网络型号弱", Toast.LENGTH_SHORT).show();
}
@Override
public void onNetworkResume() {
}
@Override
public void onEncodeIllegalArgumentException(IllegalArgumentException e) {
handleException(e);
}
private void handleException(Exception e) {
try {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
mPublisher.stopPublish();
mPublisher.stopRecord();
mPublishBtn.setText("开始");
} catch (Exception e1) {
//
}
}
@Override
public void onRtmpConnecting(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onRtmpConnected(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onRtmpVideoStreaming() {
}
@Override
public void onRtmpAudioStreaming() {
}
@Override
public void onRtmpStopped() {
Toast.makeText(getApplicationContext(), "已停止", Toast.LENGTH_SHORT).show();
}
@Override
public void onRtmpDisconnected() {
Toast.makeText(getApplicationContext(), "未连接服务器", Toast.LENGTH_SHORT).show();
}
@Override
public void onRtmpVideoFpsChanged(double fps) {
}
@Override
public void onRtmpVideoBitrateChanged(double bitrate) {
}
@Override
public void onRtmpAudioBitrateChanged(double bitrate) {
}
@Override
public void onRtmpSocketException(SocketException e) {
handleException(e);
}
@Override
public void onRtmpIOException(IOException e) {
handleException(e);
}
@Override
public void onRtmpIllegalArgumentException(IllegalArgumentException e) {
handleException(e);
}
@Override
public void onRtmpIllegalStateException(IllegalStateException e) {
handleException(e);
}
@Override
public void onRecordPause() {
Toast.makeText(getApplicationContext(), "Record paused", Toast.LENGTH_SHORT).show();
}
@Override
public void onRecordResume() {
Toast.makeText(getApplicationContext(), "Record resumed", Toast.LENGTH_SHORT).show();
}
@Override
public void onRecordStarted(String msg) {
Toast.makeText(getApplicationContext(), "Recording file: " + msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onRecordFinished(String msg) {
Toast.makeText(getApplicationContext(), "MP4 file saved: " + msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onRecordIOException(IOException e) {
handleException(e);
}
@Override
public void onRecordIllegalArgumentException(IllegalArgumentException e) {
handleException(e);
}
}
上面的Activity里面,主要就是注册回调,以及实现回调,在各自的方法当中弹出提示
SrsPublisher.java
public void setRtmpHandler(RtmpHandler handler) {
mFlvMuxer = new SrsFlvMuxer(handler);
```
}
public void setRecordHandler(SrsRecordHandler handler) {
mMp4Muxer = new SrsMp4Muxer(handler);
```
}
public void setEncodeHandler(SrsEncodeHandler handler) {
mEncoder = new SrsEncoder(handler);
```
}
SrsFlvMuxer、SrsMp4Muxer、SrsEncoder这三个类是真正执行的类,我们在里面的不同方法中调用即可
比如说 mMp4Muxer .java
构造方法将SrsRecordHandler 传进来
public SrsMp4Muxer(SrsRecordHandler handler) {
mHandler = handler;
}
然后在,在真正执行的方法中,去更新状态
/**
* pause recording.
*/
public void pause() {
if (bRecording) {
bPaused = true;
mHandler.notifyRecordPause();
}
}
/**
* resume recording.
*/
public void resume() {
if (bRecording) {
bPaused = false;
needToFindKeyFrame = true;
mHandler.notifyRecordResume();
}
}
/**
* finish recording.
*/
public void stop() {
bRecording = false;
bPaused = false;
needToFindKeyFrame = true;
aacSpecConfig = false;
frameCache.clear();
if (worker != null) {
try {
worker.join();
} catch (InterruptedException e) {
e.printStackTrace();
worker.interrupt();
}
worker = null;
finishMovie();
mHandler.notifyRecordFinished(mRecFile.getPath());
}
Log.i(TAG, "SrsMp4Muxer closed");
}
上面的 mHandler.notifyRecordResume()等方法是什么呢?我们在跟进去看看SrsRecordHandler类看看
SrsRecordHandler.java
package net.ossrs.yasea;
import android.os.Handler;
import android.os.Message;
import java.io.IOException;
import java.lang.ref.WeakReference;
/**
* Created by leo.ma on 2016/11/4.
*/
public class SrsRecordHandler extends Handler {
private static final int MSG_RECORD_PAUSE = 0;
private static final int MSG_RECORD_RESUME = 1;
private static final int MSG_RECORD_STARTED = 2;
private static final int MSG_RECORD_FINISHED = 3;
private static final int MSG_RECORD_ILLEGEL_ARGUMENT_EXCEPTION = 4;
private static final int MSG_RECORD_IO_EXCEPTION = 5;
private WeakReference mWeakListener;
public SrsRecordHandler(SrsRecordListener listener) {
mWeakListener = new WeakReference<>(listener);
}
public void notifyRecordPause() {
sendEmptyMessage(MSG_RECORD_PAUSE);
}
public void notifyRecordResume() {
sendEmptyMessage(MSG_RECORD_RESUME);
}
public void notifyRecordStarted(String msg) {
obtainMessage(MSG_RECORD_STARTED, msg).sendToTarget();
}
public void notifyRecordFinished(String msg) {
obtainMessage(MSG_RECORD_FINISHED, msg).sendToTarget();
}
public void notifyRecordIllegalArgumentException(IllegalArgumentException e) {
obtainMessage(MSG_RECORD_ILLEGEL_ARGUMENT_EXCEPTION, e).sendToTarget();
}
public void notifyRecordIOException(IOException e) {
obtainMessage(MSG_RECORD_IO_EXCEPTION, e).sendToTarget();
}
@Override // runs on UI thread
public void handleMessage(Message msg) {
SrsRecordListener listener = mWeakListener.get();
if (listener == null) {
return;
}
switch (msg.what) {
case MSG_RECORD_PAUSE:
listener.onRecordPause();
break;
case MSG_RECORD_RESUME:
listener.onRecordResume();
break;
case MSG_RECORD_STARTED:
listener.onRecordStarted((String) msg.obj);
break;
case MSG_RECORD_FINISHED:
listener.onRecordFinished((String) msg.obj);
break;
case MSG_RECORD_ILLEGEL_ARGUMENT_EXCEPTION:
listener.onRecordIllegalArgumentException((IllegalArgumentException) msg.obj);
break;
case MSG_RECORD_IO_EXCEPTION:
listener.onRecordIOException((IOException) msg.obj);
break;
default:
throw new RuntimeException("unknown msg " + msg.what);
}
}
public interface SrsRecordListener {
void onRecordPause();
void onRecordResume();
void onRecordStarted(String msg);
void onRecordFinished(String msg);
void onRecordIllegalArgumentException(IllegalArgumentException e);
void onRecordIOException(IOException e);
}
}
这个类是重点 ,在这个类里面,我们通过真正执行方法的调用以后,向外层发送handler,不同的更新就有不同类型的handler,然后在通过接口回调,返回个主Activity。