背景

多媒体开发,包含图片,音频,视频等领域。近期参与的新项目,正好涉及在Android客户端上进行多媒体开发,借此一步一步尝试学习和整理资料。

第一步就从最简单的图片展示来入门:尝试用三种方式来展示图片——ImageView,自定义View,SurfaceView。

实现

ImageView

这个最简单,稍有Android基础的开发者都会,可以通过在layout文件中定义ImageView的时候指定src为对应图片,亦可在java代码中通过ImageView的setImageDrawable或者setImageBitmap来设置图片,用于展示。

代码过于简单,这里不细述。

自定义View

自定义View,就是要自定义View的三个方法,onMeasure, onLayout, onDraw,前两个方法用来定义View的size和位置,后一个onDraw才是绘制的具体实现,所以自定义View绘制图片,就要在onDraw中来绘制。

public class MyView extends View {
private Bitmap mBitmap;
private Paint mPaint;
public MyView(Context context) {
super(context);
//读取图片为bitmap实例
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
//Paint可以定义画笔的颜色粗细等,在画线条,形状等的时候生效,而在画图片的时候颜色粗细等属性无效,所以只需要new一个实例就好
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas意为“画布”,即是View的可绘制区域
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
}
}

复制代码

onDraw会View初始化后进行调用,将图片绘制到View上。

除此之外,View的postInvalidate方法也会导致重绘,调用onDraw。

SurfaceView

SurfaceView在Android系统算是比较复杂的存在,它与View有所不同。最大的区别就是 View只能在主线程渲染,SurfaceView则可以自定义渲染线程。

我们知道,如果在主线程做过于耗时的操作,超过16ms,就会引起掉帧甚至ANR。而SurfaceView可以不在主线程渲染,所以用SurfaceView来做渲染视频之类的耗时操作,就可以不影响到主线程的渲染。

public class SurfaceMainActivity extends Activity implements Callback {
private SurfaceView mSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mSurfaceView = new SurfaceView(this);
setContentView(mSurfaceView);
//SurfaceView有自己的生命周期,不能直接使用,要通过callback监听到Surface在create之后,destroy之前,才能在其上绘制
mSurfaceView.getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//Surface已经创建,可以绘制我们的图片了
drawBitmap(holder);
}
private void drawBitmap(SurfaceHolder holder) {
Bitmap bitmap = null;
try {
//从assets中读test.png创建bitmap实例
bitmap = BitmapFactory.decodeStream(getAssets().open("test.png"));
} catch (IOException e) {
e.printStackTrace();
}
//获取画布
Canvas canvas = holder.lockCanvas();
//画一个大红色背景(清空画布)
canvas.drawColor(Color.RED);
if (bitmap != null) {
//将图片绘制到画布上
canvas.drawBitmap(bitmap,0,0,new Paint());
}
//完成绘制
holder.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//Surface销毁,在这之后,不能再获取画布绘制了
}
}

复制代码

以上是在SurfaceView上绘制一张图片的例子,如果是在surfaceCreated之后,另起一个独立的线程,将视频解析成一帧一帧绘制到Canvas上,那也就做成了一个视频播放器。