1.计算机表示图形的几种方式
bmp:以高质量保存 用于计算机
jpg:以良好的质量保存 用于计算机或者网络
png:以高质量保存
图片大小的计算公式:图片的总像素*每个像素大小
单色:每个像素最多可以表示2种颜色,要么是黑要么是白,那么只需要使用长度为1的二进制位来表示,那么一个像素占1/8个byte
16色:每个像素最多可以表示16种颜色 0000-1111,那么只需要使用长度为4的二进制位来表示,那么一个像素占1/2个byte
256色:每个像素最多可以表示256种颜色 0000 0000-1111 1111 ,那么只需要使用长度为8的二进制位来表示,那么一个像素占1个byte
24位:每个像素最多可以表示1600万种颜色 那么一个像素占3byte
r 1 byte
g 1 byte
b 1 byte
android中采用的是png格式, android中采用ARGB android中一个像素占4byte
2.缩放加载大图片
异常:图片太大 OutOfMemeryError
1)获取图片的分辨率 2400*3200
2)获取手机的分辨率 320*480
3)计算缩放比
宽 7 宽正好
高 6倍
4)按照大的进行缩放
实现步骤:
[1]activity.main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="click"
android:text="load"/>
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
[2]MainActivity:
private int height;
private int width;
private ImageView iv;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//用来显示小狗的图片
iv = (ImageView) findViewById(R.id.iv);
//[1]获取手机的分辨率 WindowManager
WindowManager wm=(WindowManager) getSystemService(WINDOW_SERVICE);
height = wm.getDefaultDisplay().getHeight();
width = wm.getDefaultDisplay().getWidth();
System.out.println("width:"+width+"---"+height);
}
//点击按钮 加载一张大图片
public void click(View v){
//创建一个位图工厂的配置参数
BitmapFactory.Options options=new Options();
//解码器不去真正的解析位图 但是还能获取图片的宽和高信息
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg", options);
//[2]获取图片的宽和高信息
int imgWidth=options.outWidth;
int imgHeight=options.outHeight;
System.out.println("图片的宽和高:"+imgWidth+"---"+imgHeight);
//[3]计算缩放比
int scale=1;
int scaleX=imgWidth/width;
int scaleY=imgHeight/height;
if(scaleX>=scaleY&&scaleX>scale){
scale=scaleX;
}
if(scaleY>scaleX&&scaleY>scale){
scale=scaleY;
}
System.out.println("缩放比:"+scale);
//[4]按照缩放比进行显示
options.inSampleSize=scale;
//[5]按照缩放比 进行解析位图
options.inJustDecodeBounds=false;
Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
//[6]把bitmap显示到iv上
iv.setImageBitmap(bitmap);
}
3.创建原图的副本
原图不能修改,副本可以
[1]activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/iv_src"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/iv_copy"
android:layout_width="wrap_content"
android:layout_marginTop="20dp"
android:layout_height="wrap_content"
/>
</LinearLayout>
[2]MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//显示原图
ImageView iv_src=(ImageView) findViewById(R.id.iv_src);
//显示副本
ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy);
//[1]先把tomcat.png图片转换成bitmap 显示到iv_src
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat);
//[1.1]操作图片
//srcBitmap.setPixel(20, 30, Color.RED);
iv_src.setImageBitmap(srcBitmap);
//[2]创建原图的副本
//[2.1]创建一个模板 相当于 创建一个大小和原图一样的 空白的白纸
Bitmap copyBitmap=Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//[2.2]想作画需要一个画笔
Paint paint=new Paint();
//[2.3]创建一个画布 把白纸铺到画布上
Canvas canvas=new Canvas(copyBitmap);
//[2.4]开始作画
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
//[2.5]操作画出来的小猫图片
for (int i = 0; i < 20; i++) {
copyBitmap.setPixel(20+i, 30, Color.RED);
}
//[3]把copybitmap显示到iv_copy上
iv_copy.setImageBitmap(copyBitmap);
}
4.图形处理的api
旋转:matrix.setRotate(20, srcBitmap.getWidth()/2, srcBitmap.getHeight()/2);
缩放:matrix.setScale(0.5f, 0.5f);
平移:
matrix.setTranslate(30, 0);
镜面:就是使用缩放和平移的一个组合
matrix.setScale(-1f, 1);
//post是在上一次修改的基础上进行再次修改 set 每次操作都是最新的 会覆盖上次的操作
matrix.postTranslate(srcBitmap.getWidth(), 0);
倒影:
matrix.setScale(1.0f, -1);
//post是在上一次修改的基础上进行再次修改 set 每次操作都是最新的 会覆盖上次的操作
matrix.postTranslate(0, srcBitmap.getHeight());
[1]activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/iv_src"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/iv_copy"
android:layout_width="wrap_content"
android:layout_marginTop="20dp"
android:layout_height="wrap_content"/>
</LinearLayout>
[2]MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//显示原图
ImageView iv_src=(ImageView) findViewById(R.id.iv_src);
//显示副本
ImageView iv_copy=(ImageView) findViewById(R.id.iv_copy);
//[1]先把tomcat.png图片转换成bitmap 显示到iv_src
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat);
//[1.1]操作图片
//srcBitmap.setPixel(20, 30, Color.RED);
iv_src.setImageBitmap(srcBitmap);
//[2]创建原图的副本
//[2.1]创建一个模板 相当于 创建了一个大小和原图一样的 空白的白纸
Bitmap copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//[2.2]想作画需要一个画笔
Paint paint=new Paint();
//[2.3]创建一个画布 把白纸铺到画布上
Canvas canvas=new Canvas(copyBitmap);
//[2.4]开始作画
Matrix matrix=new Matrix();
//[2.5]对图片进行旋转
//matrix.setRotate(20, srcBitmap.getWidth()/2, srcBitmap.getHeight()/2);
//[2.5]对图片进行缩放
//matrix.setScale(0.5f, 0.5f);
//[2.6]对图片进行平移
//matrix.setTranslate(30, 0);
//[2.7]镜像效果 如果2个方法一起用
matrix.setScale(-1f, 1);
//post是在上一次修改的基础上进行再次修改 set 每次操作都是最新的 会覆盖上次的操作
matrix.postTranslate(srcBitmap.getWidth(), 0);
//[2.8]倒影效果
//matrix.setScale(1.0f, -1);
//post是在上一次修改的基础上进行再次修改 set 每次操作都是最新的 会覆盖上次的操作
//matrix.postTranslate(0, srcBitmap.getHeight());
canvas.drawBitmap(srcBitmap, matrix, paint);
//[3]把copybitmap显示到iv_copy上
iv_copy.setImageBitmap(copyBitmap);
}
5.画画板小案例
[1]activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/iv"
android:orientation="horizontal">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click1"
android:text="红色"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click2"
android:text="加粗"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click3"
android:text="保存"/>
</LinearLayout>
</RelativeLayout>
[2]MainActivity:
private ImageView iv;
private Bitmap srcBitmap;
private Bitmap copyBitmap;
private Paint paint;
private Canvas canvas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//用来显示我们画的内容
iv = (ImageView) findViewById(R.id.iv);
//[1]获取原图 bg
srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
//[2]获取原图的副本 相当于是一个空白 的白纸
copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//创建画笔
paint = new Paint();
//创建一个画布
canvas = new Canvas(copyBitmap);
//开始作画
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
//convas.drawLine(20, 30, 50, 80, paint);
iv.setImageBitmap(copyBitmap);
//[3]给iv设置一个触摸事件
iv.setOnTouchListener(new OnTouchListener() {
int startX=0;
int startY=0;
@Override
public boolean onTouch(View v, MotionEvent event) {
//获取当前事件类型
int action=event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN://按下
System.out.println("摸view");
//获取开始位置(划线)
startX=(int) event.getX();
startY=(int) event.getY();
break;
case MotionEvent.ACTION_MOVE://移动
System.out.println("移动");
//获取结束位置
int stopX=(int) event.getX();
int stopY=(int) event.getY();
//[不停的画线]
canvas.drawLine(startX, startY, stopX, stopY, paint);
//再次显示到iv上
iv.setImageBitmap(copyBitmap);
//更新一下开始坐标和结束坐标
startX=stopX;
startY=stopY;
break;
case MotionEvent.ACTION_UP://抬起
System.out.println("抬起");
break;
default:
break;
}
// True if the listener has consumed the event, false otherwise
return true;//true 监听器处理完事件了
}
});
}
//点击按钮 改变画笔的颜色
public void click1(View v){
paint.setColor(Color.RED);
}
//点击按钮 对画笔加粗
public void click2(View v){
paint.setStrokeWidth(15);
}
//点击按钮 对图片进行保存
public void click3(View v){
try {
/**
* SystemClock.uptimeMillis() 这个是当前手机的开机后的时间 开机了过了多久
*/
File file = new File(Environment.getExternalStorageDirectory().getPath(),SystemClock.uptimeMillis()+".png");
FileOutputStream fos=new FileOutputStream(file);
/**
* CompressFormat format 保存图片的格式
* int quality 保存图片的质量
*/
copyBitmap.compress(CompressFormat.PNG, 100, fos);
//发送一条广播 欺骗系统图库的应用
Intent intent=new Intent();
//设置action
intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
//发送一条广播
sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
6.撕衣服小案例
原理:2张图片,一张是有衣服,一张没衣服,有衣服的触摸变透明即可(2.3不行,撕的透明是黑色,真机可以)
[1]activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/after19"
/>
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
[2]MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//用来显示 操作后的图片
final ImageView iv = (ImageView) findViewById(R.id.iv);
//[1]获取要操作图片 原图
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pre19);
//[2]创建一个副本 相当于有一个和原图大小的白纸
final Bitmap alterBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//创建画笔
Paint paint = new Paint();
//创建画布 把白纸铺到画布上
Canvas canvas = new Canvas(alterBitmap);
//开始作画
canvas.drawBitmap(srcBitmap, new Matrix(), paint);
iv.setImageBitmap(alterBitmap);
//[3]给vi设置一个触摸事件
iv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//[4]具体判断一下触摸事件
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE://移动事件
for (int i = -7; i < 7; i++) { //增加X轴坐标
for (int j = -7; j < 7; j++) { //增加Y轴坐标
//为了良好的用户体验 撕一个圆
if (Math.sqrt(i*i+j*j)<7) {
try {
alterBitmap.setPixel((int)event.getX()+i, (int)event.getY()+j, Color.TRANSPARENT);
} catch (Exception e) {
}
}
}
}
//更新一下iv
iv.setImageBitmap(alterBitmap);
break;
}
return true;
}
});
}
7.使用mediaplayer播放音频文件
这个类用于播放音频或者视频
[1]activity_main.xml:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="播放"
/>
[2]MainActivity:
//点击按钮 播放一个音频文件
public void click(View v){
//[1]初始化mediaplayer
MediaPlayer mediaPlayer=new MediaPlayer();
//[2]设置要播放的资源位置 path 可以是网络路径 也可是本地路径
try {
mediaPlayer.setDataSource("/mnt/sdcard/xpg.mp3");
//[3]准备播放
mediaPlayer.prepare();
//[4]开始播放
mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
8.百度音乐盒完成
[1]清单文件application加:
<service android:name="com.itheima.baidumusic.MusicService"></service>
[2]activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click1"
android:text="播放" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click2"
android:text="暂停" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click3"
android:text="继续播放" />
<SeekBar
android:id="@+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
[3]Iservice:
public interface Iservice {
//把想暴露的方法都定义在接口中
public void callPlayMusic();
public void callPauseMusic();
public void callRePlayMusic();
public void callSeekTo(int position);
}
[4]MusicService:
public class MusicService extends Service{
private MediaPlayer mediaPlayer;
//[2]把我们定义的中间人对象返回
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
//服务一开启 就执行这个方法
@Override
public void onCreate() {
//1.初始化mediaplayer
mediaPlayer=new MediaPlayer();
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
//实现指定播放的位置
public void seekTo(int position){
mediaPlayer.seekTo(position);
}
//播放音乐的方法
public void playMusic(){
try {
//2.设置要播放的资源位置 path可以是网络路径 也可以是本地路径
mediaPlayer.reset();
mediaPlayer.setDataSource("/mnt/sdcard/xpg.mp3");
//3.准备播放
mediaPlayer.prepare();
//4.开始播放
mediaPlayer.start();
//5.更新进度条
updateSeekBar();
} catch (Exception e) {
e.printStackTrace();
}
}
//更新进度条的方法
private void updateSeekBar(){
//[1]获取到当前播放的总长度
final int duration = mediaPlayer.getDuration();
//[2]使用Timer定时器去定时获取当前进度
final Timer timer=new Timer();
final TimerTask task=new TimerTask() {
@Override
public void run() {
//[3]一秒钟获取一次当前进度
int currentPosition = mediaPlayer.getCurrentPosition();
//[4]拿着我们在MainActivity创建的handler发消息 消息就可以携带数据
Message msg=Message.obtain();
Bundle bundle=new Bundle();
bundle.putInt("duration", duration);
bundle.putInt("currentPosition", currentPosition);
msg.setData(bundle);
//发送一条消息 mainActivity里面的handlemessage方法就会执行
MainActivity.handler.sendMessage(msg);
}
};
//100毫秒后 每隔1秒执行一次run方法
timer.schedule(task, 100,1000);
//当歌曲执行完毕后 把timer和timertask取消
//设置播放完成的监听
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
System.out.println("歌曲播放完成了");
//把timer和timertask取消
timer.cancel();
task.cancel();
}
});
}
//暂停音乐的方法
public void pauseMusic(){
//暂停音乐
mediaPlayer.pause();
}
//继续播放音乐的方法
public void rePlayMusic(){
mediaPlayer.start();
}
//[1]在服务的内部定义一中间人对象(IBinder)
private class MyBinder extends Binder implements Iservice{
//调用播放音乐的方法
@Override
public void callPlayMusic() {
playMusic();
}
//调用暂停音乐的方法
@Override
public void callPauseMusic() {
pauseMusic();
}
//调用继续播放音乐的方法
@Override
public void callRePlayMusic() {
rePlayMusic();
}
//调用跳转到指定位置来放音乐的方法
@Override
public void callSeekTo(int position) {
seekTo(position);
}
}
}
[5]MainActivity:
private Iservice iservice;//这个是我们定义的中间人对象
private Myconn conn;
public static Handler handler=new Handler(){
public void handleMessage(android.os.Message msg) {
//获取我们携带的数据
Bundle data=msg.getData();
//获取歌曲的总时长和当前进度
int duration=data.getInt("duration");
int currentPosition=data.getInt("currentPosition");
//设置seekbar的进度
sbar.setMax(duration);
sbar.setProgress(currentPosition);
};
};
private static SeekBar sbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//混合方式开启服务
//[1]先调用startService目的是可以保证服务在后台长期运行
Intent intent=new Intent(this,MusicService.class);
startService(intent);
//[2]调用bindService目的是为了获取我们定义的中间人对象 就可以间接的调用服务里面的方法
conn=new Myconn();
bindService(intent, conn, BIND_AUTO_CREATE);
//[3]找到seekbar 设置进度
sbar = (SeekBar) findViewById(R.id.seekBar1);
//[4]给seekbar设置监听事件
sbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
//当拖动停止的时候调用
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
iservice.callSeekTo(seekBar.getProgress());
}
//当开始拖动
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
//当进度改变
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});
}
@Override
protected void onDestroy() {
//当Activity销毁的时候 解绑服务 目的是为了不报红色日志
unbindService(conn);
super.onDestroy();
}
//点击按钮 播放音乐
public void click1(View v){
//调用播放音乐的方法
iservice.callPlayMusic();
}
//点击按钮 暂停音乐
public void click2(View v){
//调用暂停音乐的方法
iservice.callPauseMusic();
}
//点击按钮 继续播放音乐
public void click3(View v){
//调用继续播放音乐的方法
iservice.callRePlayMusic();
}
//监听服务的状态
private class Myconn implements ServiceConnection{
//当服务连接成功
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取我们定义的中间人对象
iservice=(Iservice) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
9.mediaplay的生命周期(播放网络音乐)
同步和异步
同步:一般播放本地音乐
异步:播放网络音乐 不用开子线程 准备完成的监听mediaPlayer.setOnPreparedListener
播放网络音乐:
[1]清单文件加权限:<uses-permission android:name="android.permission.INTERNET"/>
[2]activity_main.xml:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="click"
android:text="播放"
/>
[3]MainActivity:
//点击按钮 播放一个音频文件
public void click(View v){
//[1]初始化mediaplayer
final MediaPlayer mediaPlayer=new MediaPlayer();
//[2]设置要播放的资源位置 path可以是网络路径 也可以是本地路径
try {
mediaPlayer.setDataSource("http://192.168.1.102:8081/xpg.mp3");
//[3]准备播放
mediaPlayer.prepareAsync();
//[3.1]设置一个准备完成的监听(准备完数据,即准备好)
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// [4]开始播放
mediaPlayer.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
10.surfaceview介绍
播放视频
mediaplay 只能播放mp4格式或者3gp格式 (低版本模拟器不行,真机可以。真机的mediaplayer还可以播放avi)
surfaceview他是一个重量级控件
内部维护了2个线程
A 加载数据 A负责显示
B 负责显示 B取加载数据
他可以直接在子线程更新ui
播放网络视频:
[1]清单文件加权限:<uses-permission android:name="android.permission.INTERNET"/>
[2]activity_main.xml:
<SurfaceView
android:id="@+id/sfv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
[3]MainActivity:
private MediaPlayer mediaPlayer;
private int currentPosition;//当前视频播放的位置
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[0]找到控件用来显示播放视频的内容
SurfaceView sfv=(SurfaceView) findViewById(R.id.sfv);
//获取holder对象 用来维护视频播放的内容
SurfaceHolder holder = sfv.getHolder();
//[0.1]添加holder生命周期 方法
holder.addCallback(new Callback() {
//当surfaceview销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("surfaceDestroyed");
//停止播放视频
if(mediaPlayer!=null&&mediaPlayer.isPlaying()){
//获取到当前播放视频的位置
currentPosition=mediaPlayer.getCurrentPosition();
mediaPlayer.stop();
}
}
//这个方法执行了 说明surfaceview准备好了
@Override
public void surfaceCreated(SurfaceHolder holder) {
//[1]初始化mediaplayer
System.out.println("surfaceCreated");
mediaPlayer=new MediaPlayer();
try {
//[2]设置要播放的资源位置 path可以是网络路径 也可以是本地路径 cc.MP4 aa.avi
mediaPlayer.setDataSource("http://192.168.1.102:8081/cc.MP4");
//[3]准备播放
mediaPlayer.prepareAsync();
//[3.0]设置显示给sfv surfaceholder 是用来维护视频播放的内容
mediaPlayer.setDisplay(holder);
//[3.1]设置一个准备完成的监听
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//[4]开始播放
mediaPlayer.start();
//[5]继续上次的位置继续播放
mediaPlayer.seekTo(currentPosition);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
});
}
11.VideoView控件介绍
videoView是对surfaceView和mediaplayer的封装 (低版本模拟器不行,真机可以。真机的mediaplayer还可以播放avi)
avi格式或者rmvb格式
[1]清单文件加权限:<uses-permission android:name="android.permission.INTERNET"/>
[2]activity_main.xml:
<VideoView
android:id="@+id/vv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
[3]MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]找到控件
VideoView vv=(VideoView) findViewById(R.id.vv);
//[2]设置播放的路径cc.MP4
vv.setVideoPath("http://192.168.1.102:8081/aa.avi");
//[3]开始播放
vv.start();
}
12.vitamio框架
Vitamio只支持ARMv6+以上的CPU,如果报以上错误,说明不支持你的机器。(注意:模拟器要使用4.0以上)
使用步骤看资料里面的总结
解码原理:使用的是一个开源项目 ffmpeg 谷歌
[1]先加vitamio框架的类库(在总结部分有)
[2]清单文件加权限:<uses-permission android:name="android.permission.INTERNET"/>
[3]清单文件application加:
<!-- 一定要在清单文件初始化InitActivity -->
<activity android:name="io.vov.vitamio.activity.InitActivity"></activity>
[4]activity_main.xml:
<io.vov.vitamio.widget.VideoView
android:id="@+id/vv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
[5]MainActivity:(import io.vov.vitamio.widget.VideoView;)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//插件vitamio框架检查是否可用
if(!LibsChecker.checkVitamioLibs(this)){
return;
}
final VideoView vv = (VideoView) findViewById(R.id.vv);
vv.setVideoPath("http://192.168.1.102:8081/aa.avi");
vv.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
vv.start();
}
});
//设置video的控制器
vv.setMediaController(new MediaController(this));
}
13.照相机和录像
照相
录像
[1]清单文件加权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
[2]activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:onClick="click1"
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:layout_marginLeft="15dp"
android:layout_marginTop="72dp"
android:text="照相" />
<Button
android:onClick="click2"
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/button1"
android:layout_below="@+id/button1"
android:layout_marginTop="104dp"
android:text="录像" />
</RelativeLayout>
[3]MainActivity:
//点击按钮进行照相
public void click1(View v){
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file=new File(Environment.getExternalStorageDirectory().getPath(),"haha.png");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
// start the image capture Intent
startActivityForResult(intent, 1);
}
//点击按钮进行录像
public void click2(View v){
Intent intent=new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
File file=new File(Environment.getExternalStorageDirectory().getPath(),"hehe.MP4");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
// start the image capture Intent
startActivityForResult(intent, 2);
}
//当开启的Activity关闭的时候调用
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("哈哈哈哈");
super.onActivityResult(requestCode, resultCode, data);
}
今日总结
[1]计算机表示图形的几种方式
[2]缩放加载大图片
[3]创建原图的副本 因为原图不可以修改
[4]画画板 设置触摸事件OnTouchListener
[5]撕衣服小案例
[6]多媒体api
[7]百度音乐盒
[8]surfaceview
[9]videoView 对surfaceview和mediaplayer的封装
[10]类库的概念
[11]照相机和录像 调用系统的照相机
【android加类库】:工程B加类库A
设置工程A,右键->Properties->Android,将Is library项选中,然后Apply。
设置工程B,右键->Properties->Android,在Library中,点击Add按钮,将A工程加入,然后Apply。
此时在B中就引入了A中的资源和代码,这些资源和代码都可以直接调用。
需要注意的是,因为A已经不再是一个完整的Android应用,而是一个类库工程,所以有一些内容还需要在B中配置一下。
比如A中有lib库引用,则B中也要加入该lib库,比如Alib库是appcompat_v7_10,B也要加;比如A中的AndroidManifest.xml文件的内容,在B的AndroidManifest.xml文件中也要相应加上。。。
【MediaPlayer视频异常】
MediaPlayer error (1, -2147483648)
解决方法:(最后用高版本的真机,测试通过)
其实代表MEDIA_ERROR_UNKNOWN.原因在于,MP4有多种编码格式,例如H.264,H.263等,而Android版本较低的机器只支持部分编码。
一旦遭遇不被支持的编码格式,MediaPlayer可能就会抛出上面的错误信息。
可以使用一些视频软件查看视频的编码格式,然后转换为普遍支持的格式。