音乐播放器:
1.查看api:DevGuide-->MultimediaandCamera-->Mediaplayback(多媒体)-->UsingMediaPlayer这是多媒体的应用示例代码
UrimyUri=....;//initializeUrihere
MediaPlayermediaPlayer=newMediaPlayer();
//指定播放的数据源类型
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//设置播放的数据
mediaPlayer.setDataSource(getApplicationContext(),myUri);
//加载数据,因为上面的操作没有真实的加载数据,殷富prepare()方法后系统才真正的加载播放器数据到内存中
mediaPlayer.prepare();
//开启播放器
mediaPlayer.start();
2.得到上面的代码后开始修改代码为我们的代码服务,上面的代码可以正常运行但是我们现在传进来的是一个文件的路径,不毕这么麻烦的转成uri,直接使用
mediaPlayer.setDataSource(path);这个重载方法把新建一个音乐播放器
3.定义播放,暂停,重播,停止动作方法
1>播放
调用上面的方法
2>暂停
1)判断一下播放器对象不为空并且正在播放
if(mediaPlayer!=null&&mediaPlayer.isPlaying())
2)如果是让程序暂停
mediaPlayer.pause();
3)更改按钮的文字,设置为继续播放
4)由于这个按钮有两个状态,暂停跟继续播放,所以如果是继续播放就不操作前面的代码,在第一步前还要加上代码判断按钮是否是续继播放并且mediaPlayer对象不为空时,调用mediaPlayer.start()开启播放器并返回return,不执行下面的语句
3>重播
1)判断一下播放器对象不为空并且正在播放那么我们让程序跳到最开始的位置
mediaPlayer.seekTo(0);
2)else如果对象是空或者不在播放,那么我们调用播放的方法
4>停止
1)判断一下播放器对象不为空并且正在播放那么我们停止播放器资源,释放资源并手动把播放器对象置为空
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
问题:
1)多次点击播放会出现内存溢出错误,因为mediaPlayer.start()开启一个播放器是android低层的一个c语言写的程序,跑到另一个线程上,如果多次点开启音乐播放器,那么系统中会存在多个音乐播放器对象,这样内存就会溢出而出错
2)因为问题1中把播放按钮设置成灰色,如果音乐播放完,他还是灰色不可用
3)播放音乐出现错误,程序应该怎么处理
解决
1)我们可以在第一次按下播放时就把按钮置成灰色不可用button.setEnabled(false)
在停止的时候要把按钮设置为true即可用状态,
2)解决音乐播放完按钮还是灰色的问题,可以设置mediaPlayer的监听器
音乐播放完毕的事件为:setOnCompletionListener(),然后实现这里的方法,把按钮设置为可用,把播放器释放资源,对象置为null
3)在mediaPlayer的播放器类中有一个错误监听事件setOnErrorListener()处理方式是把播放按钮置为空,释放播放资源,把播放类置为空,返回false
设置播放声音的大小:
mediaPlayer.setVolume(设置左声道大小,设置右声道大小)//1.0代表声音最大,0.0声音最小
设置屏幕不锁屏一直常亮状态,原理是每隔几秒钟就模拟按一个按键的事件给系统,让系统认为用户在使用不关闭屏草幕
mediaPlayer.setScreenOnWhilePlaying(true);
用命令行把一个资源放在手机sd卡上命令
adbpushfileName.mp3/sdcard/fileName.mp3
eclipse关联android源代码
可以把source的源代码文件放在我们正在开发的android的sdk的根目录
SoundPool音乐播放池
与MediaPlayer相比,SoundPool的优势在于CPU资源占用量低和絷延迟小,缺点SoundPool最大只能申请1M的内存空间,所以我闪只能播放一些很短的声音片段,在差的机器上会有很长的延迟,提供的pause和stop方法最好不要用,会有问题
应用场景:
1.应用程序中的声效(按键提示音,消息等)
2.游戏中密集而短暂的声音(如多个飞船同时爆炸)
3.发射子弹的声音
播放发射子弹的音效
1.定义按钮事件
2.mp3资源放入android工程,如果是非图片文字的资源,我们一般为这些资源新建一个raw(未经处理的文件夹),把这个文件夹放在android的res资源文件夹下,R文件中就生成关联
3.定义声音池
SoundPoolsoundPool=newSoundPool(maxStreams,streamType,srcQuality);
maxStreams:最多可以放多少声音实例一般5-10个
streamType:AudioManager.STREAM_MUSIC,一般流媒体都是用这个的
srcQuality:当前播放声音的质量,现在google工程师没有实现,现在设置为0,为以后预留
4.要把声音预先的加载到声音池里面
1>load(Strignpath,intpriority)把某个文件路径的声音资源加载进来如sd卡上的声音资源
2>load(Contextcontext,intresId,intpriority)
resId:要播放的资源文件的id(R.raw.ring)
priority:声音优先级,现在也没有实现的,一般填写1为以后升级做准备
5.在按钮事件中实现播放音效
1>播放音效
soundPool.play(soundID,leftVolume,rightVoume,priority,loop,rate);
soundID:播放声音的id,是上面soundPool.load()方法返回的一个播放声音的id
leftVolume:左声音大小
rigthVolume:右声音大小
priority:播放优先级0是等级最低的
loop:如果指定0那么不循环,-1就一直循环
rate:声音播放的速度0.5到2.0范围之内
注意的问题:soundPool.load这个方法是非阻塞式的方法,如果把load跟play放在一起的话,那么会有问题,因为声音还没有加载完成,就播放,会播放没有声音,所以声音池创建的工作应该放在activity类的onCreate()方法中进行初始化的
视频播放器:
播放:
1.定义一个媒体播放器类
MediaPlayermediaPlayer=newMediaPlayer();
2.指定播放的数据源类型
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
3.指定展现的数据放在那个SurfaceHoler里面
mediaPlayer.setDisplay(holer);
4.因为我们要用mediaPlayer的框架去显示数据,不去自己维护surfaceHoler的缓存区,而是等待系统的mediaplayer去把数据推到这个缓冲
1>定义显示组件SurfaceView
SurfaceViewsv=findViewById(R.id.sv);
2>定义SurfaceHoler的容器,在这个容器里展现界面
SurfaceHolerholder=sv.getHoler();//得到当前手机屏幕的画布
3>设置用mediaPlayer框架推送数据到画布中
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
上面三步是写在onCreate()方法中的
5.设置播放数据
mediaPlayer.setDataSource(path);//这里传播放文件的path
6.视频文件准备,就是加载视频文件到内存中
mediaPlayer.prepare();
7.播放视频
mediaPlayer.start();
暂停,停止,重置的处理代码跟音频播放器处理方法大同小异
视频播放器的问题与解决
问题:
1.上面的视频播放器写完以后会有问题,如果按home返回,再打开视频就没有画面了
解决:
1.上面问题的原因是因为SurfaceView这个控件很占内存,开销很大.只要用户看不到这个组件时系统就会回收这个组件,然后再次开播放器holder被回收了,画面就显示不出来了,所以做以下处理:
1>在holder.setType()方法下面定义一个回调事件
holder.addCallback(newCallback())
里面有三个方法
surfaceDestroyed():
当前holder被销毁,一般是按了home键
holder被销毁了这里我们应该判断视频播放对象是不为空并且正在播放,那么我们就停止视频播放器回收资源,并且记录当前播放的进度
mediaPlayer.stop();
mediaPlayer.release();
intpostion=mediaPlayer.getCurrentPosition();
surfaceCreated():
holder被创建了,长按home回到播放程序,这时我们要重装创建视频播放器对象在播放前设置播放的位置
判断关闭前记录的位置是否大于零,如果大于那么设置播放的位置从记录的位置开始,如果不是那么从零开始播放,然后开启播放器
mediaPlayer.seekTo(postion);
surfaceChanged():这个是数据被更改时调用
adb连接失败处理:
在dos下先杀死连接桥服务
adbkill-server
再打印adb日志相当于开启连接桥服务
adblogcat
mediaplayer的生命周期:
1.Idle这是空闲状态,这个状态是因为新建一个MediaPlayer
MediaPlayerplayer=newMediaPlayer();
还有一种情况是对象重置了
player.reset();
2.InitiaLized:初始化MediaPlayer,用setDataSource()方法,这个方法执行完就表示MediaPlayer初始化完毕了
3.Prepared:调用prepare(),让MediaPlayer准备进入状态,在这个状态下有两个方法
1>seekTo()这是个让视频准备定位到那个位置开始播放的方法,在start()方法前执行
2>start()方法是进入started状态
4.started状态:在started这个状态中有一个Looping是否为true的参数,如果为真就一直播放,里面还有一些状态,可以paused()暂停并且可以start()重新开启,也可以stop()停止再重新开启,不过这里开启就要重头开启了(prepare()到prepared准备),还有一个回调,如果我们设置OnCompletionListener播放完毕的监听,可以在Playbackcompleted下执行重新播放,停止,seekTo()都是可以的
5Preparing:异步的准备状态,如果我们在初始化完成以后直接prepare()我们进行同步准备Prepared状态,如果调用prepareAsync()这时我们进行异步准备
6.在异步准备状态时要调用OnPreparedListener.onPrepared()方法去开启播放器
7.在播放器播放音乐时会有一个错误监听事件,如果事件播放失败(如不支持的情况),可以调用OnErrorListener.onError()的方法进行捕捉处理
8.在程序结束时要调用release()方法释放资源
同步和异步的区别是什么,多次调用异步方法会出现什么问题?
同步就相当于打电话:必须要用应答是阻塞状态的
异步就相当于广播,重复发送一个信息,只为让一个信息被接收,发送广播这个事件是不阻塞状态,但是必须要有回调事件,相当于广播的一个信息要重复很多次,只为让我们接收到这个信息
把程序中的prepare()方法的准备代码替换成prepareAsync()的异步代码,因为是异步的所以后面不能紧可开启播放器,否则播放器还没有准备好就播放了肯定是有问题的,所以要调用异步方法的回调事件,在回调事件中去开启播放服务
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(newOnPreparedListener())在这个接口中只有一个onPrepared的方法(准备完毕后的方法),我们在这个方法中实现开启播放器的操作
现在市面上的播放器大多采用这个异步的操作,如果同步操作那么加载会有一段时候的黑屏的,(因为在主线程中运行的),如果采用异步,不是在主线程中运行的,会另开一个线程,那么我们可以在加载的时候放一个进度条,提示用户正在加载中,这样用户体验会好很多
在线播放器:
传一个网络的URI,然后用mediaPlayer进行播放跟上面的视频播放器不同的地方是mediaPlayer.setDataSource(link);这是一个网络地址,而前面的是一个本地文件的地址
上面的操作会有问题,网络上的播放的文件不能是一般的mp4文件,要是渐进式下载的文件格式,可以用苹果的QuickTime软件把一个普通的mp4转换成支持渐进式下载播放的视频播放软件
步骤:加载文件-->选择导出-->在导出时选择转成"3G"的-->选项-->可以选详细参数,也可以默认-->选择确定就可以了,成功异出一个3gp
摄像头拍照:
1.界面创建一个拍照按钮跟<ImageView>标签用来显示图片
2.设置点击显示图片事件
1>打开照像机
Cameracamera=Camera.open();
因为打开照像机是侵犯用户的隐私的需要加权限,如果也可以设置自动对集,这个需要手机支持的,在说明文档中有说明
//文档说明
<uses-permissionandroid:name="android.permission.CAMERA"/>
<uses-featureandroid:name="android.hardware.camera"/>
<uses-featureandroid:name="android.hardware.camera.autofocus"/>//自动对焦实现
2>准备开始预览
camera.startPreview();
3>照像动作
camera.takePicture(shutter,raw,jpeg);
shutter:SutterCallback接口也是一个回调函数,快门按下响应的事件,如果不关心就设置一个null
raw:PictureCallback,未经处理的原始照片,一般都不需要得到这个未经处理的照片,因为现在拍摄的照片都太大了,很消耗sd卡空间的和内存的
jpeg:PictureCallback接口,这个也得到压缩后的jpeg照片
4>前两个参数可以设置为null,最后一个jpeg的参数实现PictureCallback()接口的onPictureTaken(byte[]data,Cameracamera)方法
data:照片所对应二进制数据
camera:照像机
5.在这个方法中把得到的二进制图片数据转成位图用Bitmap
Bitmapbitmap=BitmapFactory.decodeByteArray(data,0,data.length);
6.把图片设置到imageView组件中
iv.setImageBittmap(bitmap);
7.关闭照像机的预览
camera.stopPreview();
上面的代码是有问题的,报的错误是初始化相机错误,因为我得到照像机后没有初始化照像机的参数.
得到照像机参数:(这是摄像头拍照ppt中的参数设置)
Parametersparams=camera.getParameters();
Stringmode=params.flatten();//像机所以的模式
设置照像机参数
requestWindowFeature(Window.FEATURE_NO_TITLE);//没有标题
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);//设置全屏
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//高亮
/*下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前*/
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().setFixedSize(176,144);//设置分辨率
camera=Camera.open();//打开摄像头
Camera.Parametersparameters=camera.getParameters();
WindowManagerwm=(WindowManager)getSystemService(Context.WINDOW_SERVICE);
Displaydisplay=wm.getDefaultDisplay();
parameters.setPreviewSize(display.getWidth(),display.getHeight());//设置预览照片的大小
parameters.setPreviewFrameRate(3);//每秒3帧
parameters.setPictureFormat(PixelFormat.JPEG);//设置照片的输出格式
parameters.set("jpeg-quality",85);//照片质量
parameters.setPictureSize(display.getWidth(),display.getHeight());//设置照片的大小
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceView.getHolder());//通过SurfaceView显示取景画面
camera.startPreview();
preview=true;
@Override
publicbooleanonKeyDown(intkeyCode,KeyEventevent){
if(camera!=null&&event.getRepeatCount()==0){
switch(keyCode){
caseKeyEvent.KEYCODE_SEARCH:
camera.autoFocus(null);//自动对焦
break;
caseKeyEvent.KEYCODE_DPAD_CENTER:
caseKeyEvent.KEYCODE_CAMERA:
//拍照
camera.takePicture(null,null,newPictureCallbackListener());
break;
}
}
returntrue;
}
//重新浏览
camera.stopPreview();
camera.startPreview();
用系统组件实现照像机的拍照并显示照片
使用上面方法进行照像机编程很容易出错,太麻烦了,我们可以开启系统里的照像机
1.在系统里源代码中找到camera的配置清单,找到如下<intent-filter>配置
<intent-filter><actionandroid:name="android.media.action.IMAGE_CAPTURE"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
2.然后我们用意图开启照像机
Intentintent=newIntent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.setCategory("android.intent.category.DEFAULT");
startActivityForResult(intent,0)//得到照像机开启得到的结果
3.调用onActivityResult()方法,这个方法是当activity开启关闭后得到的结果,在camera源代码中,搜查setResult()这个传递数据的方法看到以下代码:
Bitmapbitmap=createCaptureBitmap(data);setResult(RESULT_OK,newIntent("inline-data").putExtra("data",bitmap));
因为Bitmap实现了Parcelable,所以用data.getParcelableextra("data"):得到的是一个Bitmap
4.设置显示照片组件为我们得到的图片(Bitmap)
注意在android中Intent传递对象的两种方法(Serializable,Parcelable),就是说要想传递数据必须实现这两种接口中的一种
录像的操作
1.创建录像对象
MediaRecorderrecoder=newMediaRecorder();
2.设置录像的声音源,为手机麦克风
recoder.setAudioSource(AudioSource.MIC);
3.设置录像的视频源,为手机相机
recoder.setvideoSource(Videosource.CAMERA);
4.设置保存格式
recoder.setOutputFormat(OutputFormat.THERE_GPP);//这是3GP格式
5设置声音的编码方式
recoder.setAudioEncoder(AudioEncoder.AMR_NB);
6.设置视频编码方式
recoder.setVideoEncoder(VidemEncoder.H264);
7.文件存放路径
recoder.setOutputFile("/sdcard/a.3gp");
8.设置视频大小,这个要手机支持的格式,可以获取手机参数里查看preview-size-values得到支持大小
recoder.setVideoSize(640.480);
9.设置录像的桢数,preview-frame-rate=30这里是最大30,不同的手机不同
recoder.setVideoFrameRate(5);
10.录像准备(相当于加载)
recoder.prepare();
11.开启录像
recoder.start();
12,因为要录声音,视频跟存入sd卡需要把这几个权限加到程序清单中
13.加入预览界面用<SurfaceView>
14.得到SurfaceHolder显示容器
SurfaceHolderholder=sv.getHolder();
15.定义缓冲类型
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
16.在onCreate定义完以后,再在开启录像的步骤中加入指定预览界面,可以在第九步后面加入
recoder.setPreviewDisplay(lolder.getSurface());
经过上面几步就可以开启录像功能了,以后的操作跟视频,音频操作一样了
注意:前面第四步设置保存格式一定要在设置编码方式前,否则会出错
上面用手工代码启动录像很麻烦也很容易出错,我们也可以调用系统的摄像功能去录像
录像的步骤跟开启系统中的照相机的步骤差不多,
1.在系统里源代码中找到camera的配置清单,找到如下<intent-filter>配置
<intent-filter>
<actionandroid:name="android.media.action.VIDEO_CAMERA"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
</intent-filter>
2.然后我们用意图开启照像机
Intentintent=newIntent();
intent.setAction("android.media.action.VIDEO_CAMERA");
intent.setCategory("android.intent.category.DEFAULT");
startActivityForResult(intent,0)//得到照像机开启得到的结果
3.调用onActivityResult()方法,这个方法是当activity开启关闭后得到的结果,在camera源代码中,搜查setResult()这个传递数据的方法看到以下代码:
IntentresultIntent=newIntent();
intresultCode;
if(valid){
resultCode=RESULT_OK;resultIntent.setData(mCurrentVideoUri);
}else{
resultCode=RESULT_CANCELED;
}
setResult(resultCode,resultIntent);
finish();
我们知道他传的是一个mCurrentVideoUri,然后找到这段代码:UrisaveUri=(Uri)myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);说明是一个MediaStore.EXTRA_OUTPUT得到一个uri并传过来,那我们就把数据传过去
Filefile=newFile("/sdcard/aaa"+System.currentTimeMillis()+".3gp");
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(file));
4.最后得到录像的uri
获取一张sd卡上的图片
1.通过点击图库得到以下信息
Startingactivity:Intent{act=android.intent.action.VIEWdat=content://media/internal/images/media?bucketId=1506676782cmp=com.android.gallery/com.android.camera.ImageGallery(hasextras)}
2.从上面的信息得知ImageGallery负责显示这些图片
3.我们就找到了清单文件,开启意图
<intent-filter>
<actionandroid:name="android.intent.action.PICK"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
<dataandroid:mimeType="image/*"/>
<dataandroid:mimeType="video/*"/>
</intent-filter>
Intentintent=newIntent();
intent.setAction("android.intent.action.PICK");
intent.addCategory("android.intent.category.DEFAULT");
intent.setType("image/*");
4.选择先界面后回到activity会执行onActivityResult()方法
5.可以获取当前数据的uri,就是图片的资源路径
Uriuri=data.getData();
6.设置显示图片
iv.setImageURI(uri);
系统的图库程序只有程序被挂载或者重启的时候才会加载图片信息
上面的程序是有问题的,图片太多如果多次加载图片会内存溢出,系统图库的优化是加载图片时用缩略图,只有双击才会显示原图,不过只是原图的一部分(屏幕大小),这样就包证内存不容易溢出
1.创建位图工厂(有参数那个)
Bitmapbitmap=BitmapFactory.decodeFile("/sdcard/bbb.jpg",opts)//这里的opts是BitmapFactory.Options
2.创建BitmapFactory.Options类,设置参数,调用里面的inJustDecodeBounds方法,如果设置true,位图工厂不会真正的加载图片,只加载图片的头信息,在头信息里有这个位图的大小信息返回的是null
BitmapFactory.Optionsopts=newOptions();
opts.inJustDecodeBounds=true;
3.设置完后就可以用得到图片的宽跟高了
intwidth=opts.outWidth;
intheigth=opts.outHeight;
4.得到手机屏幕的宽跟高
getWindowManager().getDefaultdisplay().getWidth()//窗宽
getWindowManager().getDefaultdisplay().getHeight()//窗高
5.得到比例值:
intscalex=图片宽/窗体宽
intscaley=图片高/窗体高
6.判断是水平还是垂直方向
if(scalex>scaley&&scaley>1)//这表示水平缩放比例比较大
if(scaley>scalex&&scalex>1)//表示竖直方向的缩放比例比较大
7.设置缩放比例,按大的来缩放,在上面的判断中加入opts.inSampleSize(加入大的比例),这样的话宽跟高都是最大的比例缩放,那图片就不会出现畸形了,最好是2的倍数
8.把BitmapFactory.Options类的inJustDecodeBounds设置成false;加载原图,但是上面设置了缩略图,所以位图工厂加载的缩略图
Bitmapbitmap=BitampFactory.decodeFile("/sdcard/bbb.jpg",opts);
通过上面的设置就不会出现内存溢出了
图片画画板:
1.启动图库
2.onActivityResult进行处理
3.这里不能直接加载图片了,如果图片太大了固定会有问题的,我现在也要做缩放处理
4.对得uri后用内容解析器得到uri的流
InputStreamis=getcontentResolver().openInputStream(uri);
5.得到流里图片的头信息即宽跟高信息
1>.设置位图工厂不要真正的加载
BitmapFactory.Optionsopts=newOptions();
opts.inJustDecodeBounds=true;
2>位图工厂加载流信息对得宽跟高信息
BitmapFactory.decodeStream(is,outPadding,opts);
is:输入流,需要加载的流
outPadding:这个是newRect()或者null都可以,
opts:BitmapFactory.Options
6.跟上面的显示图片的操作差不多,但是在处理高的时候窗口的高度,我们还要减去标题栏和状态栏,
7.在上面加载位图最后一步也要改成BitmapFactory.decodeStream(is,newRect(),opts);
8.然后把缩放的图片加载在界面上
9.图片加触摸事件:
iv.setOnTouchListener(newOnTouchListener()),实现里面的onTouch(Viewv,MotionEventevent)的方法
View:被触摸的view控件
MotionEvent:当前触摸事件的类型
如果返回是true就会消费当前事件,如果返回是false那就不消费当前事件,我们要返回true,这样才能响应里面的事件
event.getAction()//当前事件
MotionEvent.ACTION_DOWN:手指第一次触摸屏幕的时候
MotionEvent.ACTION_MOVE//手指移动的时候
MOtionEvent.ACTION_UP//手指离开屏幕的事件
10.画图操作
1>创建一个画布,要以Bitmap做为模板
Canvascanvas=newCanvas(bitmap);以那个bitmap为模板创建的画布
2>但是为了不破坏原图,我们创建一个跟原图大小一样的空的位图,然后在这个位图上画原图,最后就可以画线了
BitmapbaseBitmap=Bitmap.createBitmap(原图的宽,原图的高,原图的配置信息)//原图的配置信息用bitmap.getConfig()方法获取
3>把画布改成新建的位图,传的是我们新建的位图
4>画布的背景图设置,设置为原图大小
canvas.drawBitmap(bitmap,matrix,paint);
bitmap:原图对象
matrix:newMatrix()
paint:画笔对象Paintpaint=newPaint();
经过上面操作就把原图加载到我们新建的位图上了
5>然后就可以去得到触摸事件坐标去画线了
event.getX();
event.getY();
上面就得到手指的坐标了
canvas.drawLine(startx,starty,stopx,stopy,paint);
前面两个是开始的坐标是从第一次触摸事件得来,后面两个是移动的时候得到,还要不断的更新位置,把开始位置更换成现在的位置,然后更新界面中的内容
iv.invalidate();
后面那个是画笔对象,我们也可以设置画笔的颜色跟粗细
mPaint.setColor(Color.GREEN);
mPaint.setStrokeWidth(5);
上面的程序有时候会有一个问题,因为图片的左上角跟imageView的左上角有位置偏移的话,那么程序就会有问题,因为我们得到的坐标是触摸事件相对于imageView的,不是相对于图片的
模拟一个sd卡挂载的广播
Intentintent=newIntent();
intent.setAction(Intent.ACTION_MEDIA_MOUNTED);SD卡被挂载
Filesdfile=Environment.getExternalStorageDirectory();
intent.setData(Uri.fromFile(sdfile));//设置那个磁盘被挂载
sendBroadcast(intent);//发送广播
notification通知
在api中有一个devGuide的中选择Userinterface(用户界面设置)可以在里面找到Notifications的介绍在StautsBarNotifications中可以看到如何创建一个通知,下面是创建一个Notifications的步骤在api文档中:
Tocreateastatusbarnotification:
1.GetareferencetotheNotificationManager:
Stringns=Context.NOTIFICATION_SERVICE;
NotificationManagermNotificationManager=(NotificationManager)getSystemService(ns);
2.InstantiatetheNotification:
inticon=R.drawable.notification_icon;
CharSequencetickerText="Hello";
longwhen=System.currentTimeMillis();
Notificationnotification=newNotification(icon,tickerText,when);
3.Definethenotification'smessageandPendingIntent:
Contextcontext=getApplicationContext();
CharSequencecontentTitle="Mynotification";
CharSequencecontentText="HelloWorld!";
IntentnotificationIntent=newIntent(this,MyClass.class);
PendingIntentcontentIntent=PendingIntent.getActivity(this,0,notificationIntent,0);
notification.setLatestEventInfo(context,contentTitle,contentText,contentIntent);
4.PasstheNotificationtotheNotificationManager:
privatestaticfinalintHELLO_ID=1;
mNotificationManager.notify(HELLO_ID,notification);
That'sit.Youruserhasnowbeennotified.
1.得到系统与notification相关服务
NotificationManagernm=getSystemService(NOTIFICATION_SERVICE);
2.初始化一个Notification的对象,让notificationManager显示
Notificationnotification=newNotification(CONTEXT_INCLUDE_CODE,tickerText,when);
CONTEXT_INCLUDE_CODE:这个是通知中显示的小图标
tickerText:这是个当信息到来时在屏幕最上方只显示一次的提示信息
when:是显示的时机,设置通知是立刻显示还是延迟显示System.currentTimeMillis();
3.设置notification的具体的参数
notification.ledARGB:五彩闪光灯(这个要手机支持)
notification.flags=Notification.FLAG_AUTO_CANCEL:当用户去点击,就自动的取消掉
notification.flags=Notification.FLAG_AUTO_CLEAR;这个是不会被清除掉的
notification.sound指定notification的声音
notification.vibrate设定通知到来的震动操作参数是一个数组例:long{200,100,200}这样就会先震动200毫秒,再100毫秒,最后在震动200毫秒
notification.icon:这个是notification显示的具体内容的图标
notification.tickerText:指定显示的文本内容
4.设置里面的内容了
notification.setLatestEventInfo(context,contentTitle,contentText,contentIntent);
context:上下文this
contentTitle:这是正文的标题
contentText:这是正文内容
contentIntent:PendingIntent这是一个延期的意图,代表未来的某一时刻去执行的意图
5.创建一个延期意图:
PendingIntentcontentIntent=PendingIntent.getActivity(context,requestCode,intent,flags);
context:上下文this
requestCode:请求码用不到就0
intent:这个延期的意图开启的是那个组件
Intentintent=newIntent(this,DemoActivity.class);
flags:notification的flags,如果指定FLAG_UPDATE_CURRENT如果有新的notification会更新当前的notification
6.利用notification的管理器把notification显示出来
nm.notify(id,notification);
id:指定notification的id,如果指定了这个id那么我们就可以用nm.cancel(id),这样就可以取消一个notification
notification:这个是上面的notification对象
上面的程序还有一个问题就是多次点击notification对象开启窗口时,要按多次后退,这时我们可以指定启动模式为singleTop,这样就不会开启新的activity了,只会利用以前的了
自定义notification
如加个进度条显示
api中也有提供了自定义的notification的步骤:
CreatingaCustomNotificationLayout
Figure3.Notificationwithacustomlayout.
Bydefault,thenotificationthatappearsinthenotificationswindowincludesatitleandthemessagetext.ThesearedefinedbythecontentTitleandcontentTextparametersofthesetLatestEventInfo()method.However,youcanalsodefineacustomlayoutforthenotificationusingRemoteViews.Figure3showsanexampleofacustomnotificationlayout.Itlookssimilartothedefaultnotification,butisactuallycreatedwithacustomXMLlayout.
Todefineyourownlayoutforthenotification,instantiateaRemoteViewsobjectthatinflatesacustomlayoutfile,thenpasstheRemoteViewstothecontentViewfieldofyourNotification.
Creatingacustomnotificationlayoutisbestunderstoodwithanexample:
5.CreatetheXMLlayoutforthenotification.Forexample,thefollowinglayoutiscalledcustom_notification.xml:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp">
<ImageViewandroid:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_marginRight="10dp"/>
<TextViewandroid:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image"
style="@style/NotificationTitle"/>
<TextViewandroid:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image"
android:layout_below="@id/title"
style="@style/NotificationText"/>
</RelativeLayout>
NoticethatthetwoTextViewelementsincludethestyleattribute.It'simportantthatyouusestyleresourcesforthetextinyourcustomnotifications,becausethebackgroundcolorofthenotificationcanvaryacrossdifferentdevicesandplatformversions.BeginningwithAndroid2.3(APIlevel9),thesystemdefinesastyleforthetextitusesforthedefaultnotificationlayouts.Thus,youshouldapplythatstylewhenrunningonAndroid2.3orhighertoensurethatyourtextisvisibleagainstthebackground.
Forexample,tousethestandardtextcolorsonversionsofAndroidlowerthan2.3,youshouldusethefollowingstylesforres/values/styles.xml:
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
<stylename="NotificationText">
<itemname="android:textColor">?android:attr/textColorPrimary</item>
</style>
<stylename="NotificationTitle">
<itemname="android:textColor">?android:attr/textColorPrimary</item>
<itemname="android:textStyle">bold</item>
</style>
<!--Ifyouwantaslightlydifferentcolorforsometext,
considerusing?android:attr/textColorSecondary-->
</resources>
Then,toapplythesystem'sdefaultcolorsfornotificationsonAndroid2.3andhigher,usethefollowingstylesforres/values-v9/styles.xml:
<?xmlversion="1.0"encoding="utf-8"?>
<resources>
<stylename="NotificationText"parent="android:TextAppearance.StatusBar.EventContent"/>
<stylename="NotificationTitle"parent="android:TextAppearance.StatusBar.EventContent.Title"/>
</resources>
Now,whenrunningonAndroid2.3(APIlevel9)orhigher,thetextinyourcustomviewwillusethesamecolorsthatthesystemdoesfordefaultnotifications.ThisisimportantbecauselaterversionsofAndroidactuallychangethebackgroundcolorofthenotificationstobedark.Inheritingthesystem'sstylesensuresthatyourtextwillbelightinsuchcases,butalsoifthebackgroundissomeotherunexpectedcolor,yourtextwillalsochangeasappropriate.
6.Now,intheapplicationcode,usetheRemoveViewsmethodstodefinetheimageandtext.ThenpasstheRemoteViewsobjecttothecontentViewfieldoftheNotification,asshowninthisexample:
RemoteViewscontentView=newRemoteViews(getPackageName(),R.layout.custom_notification_layout);
contentView.setImageViewResource(R.id.image,R.drawable.notification_image);
contentView.setTextViewText(R.id.title,"Customnotification");
contentView.setTextViewText(R.id.text,"Thisisacustomlayout");
notification.contentView=contentView;
Asshownhere,passtheapplication'spackagenameandthelayoutresourceIDtotheRemoteViewsconstructor.Then,definethecontentfortheImageViewandTextView,usingthesetImageViewResource()andsetTextViewText().Ineachcase,passthereferenceIDoftheappropriateViewobjectthatyouwanttoset,alongwiththevalueforthatView.Finally,theRemoteViewsobjectispassedtotheNotificationinthecontentViewfield.
7.Becauseyoudon'tneedthesetLatestEventInfo()methodwhenusingacustomview,youmustdefinetheIntentfortheNotificationwiththecontentIntentfield,asinthisexample:
IntentnotificationIntent=newIntent(this,MyClass.class);
PendingIntentcontentIntent=PendingIntent.getActivity(this,0,notificationIntent,0);
notification.contentIntent=contentIntent;
8.Thenotificationcannowbesentasusual:
mNotificationManager.notify(CUSTOM_VIEW_ID,notification);
代码:(标准notification步骤)
1.新建上面的布局,在上面的图片高度设置包裹图片
2.得到系统与notification相关服务
NotificationManagernm=getSystemService(NOTIFICATION_SERVICE);
3.初始化一个Notification的对象,让notificationManager显示
Notificationnotification=newNotification(CONTEXT_INCLUDE_CODE,tickerText,when);
4.创建一个RemoteViews的对象
RemoteViewscontentView=newRemoteViews(getPackageName(),R.layout.custom_notification_layout);//远程的View对象,第一个参数当前应该程序包名,第二个参数notification的布局引用,因为notification这个是显示在桌面的应用程序,所以要把当前的view对象传递给桌面的应用程序,然后桌面的应用程序就把传过的view显示出来,RemoteViews是进程间通信的view对象的类型
contentView.setImageViewResource(R.id.image,R.drawable.notification_image);
contentView.setTextViewText(R.id.title,"Customnotification");//设置标题
contentView.setTextViewText(R.id.text,"Thisisacustomlayout");//设置内容
notification.contentView=contentView;//指定显示的对象
5.设置当前notification的点击事件
Intent notificationIntent=new Intent(this,MyClass.class);//设置显示的activity
PendingIntent contentIntent=PendingIntent.getActivity(this,0,notificationIntent,0);
notification.contentIntent=contentIntent;
6.利用notification的管理器把notification显示出来
nm.notify(id,notification);
id:指定notification的id,如果指定了这个id那么我们就可以用nm.cancel(id),这样就可以取消一个notification
notification:这个是上面的notification对象
上面程序的代码问题:
1.在界面布局时不能定义listView,因为RemoteViews是远程view对象的包装,这个远程的view对象只能是RemoteViews对象支持的对象(在RemoteViews源代码中只支持图片,按钮,文本,进度条等可以在源代码中查看)
2.notification显示的高度都是固定的,所以布局时要注意,如果超出高度,有一些布局是看不到的
添加进度条:
1.在布局中把textView的组件换成进度条的组件,并设置成水平方向的进度条
2.在RemoteViews的对象调用setProgressBar(viewId,max,progress,indeterminate);
viewid:R文件中的progressBar的id
max:最大值
progress:当前的进度
indeterminate:如果是true不确定进度的,如果是false是可以显示具体进度的,可以设置false;