Android_Day07

音樂播放器:

1.查看api:DevGuide-->MultimediaandCamera-->Mediaplayback(多媒體)--UsingMediaPlayer這是多媒體的應用示例代碼

UrimyUri=....;//initializeUrihere

MediaPlayermediaPlayer=newMediaPlayer();

//指定播放的數據源類型

mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

//設置播放的數據

mediaPlayer.setDataSource(getApplicationContext(),myUri);

//加載數據,因爲上面的操作沒有真實的加載數據,殷富prepare()方法後系統才真正的加載播放器數據到內存中

mediaPlayer.prepare();

//開啓播放器

mediaPlayer.start();

.得到上面的代碼後開始修改代碼爲我們的代碼服務,上面的代碼可以正常運行但是我們現在傳進來的是一個文件的路徑,不畢這麼麻煩的轉成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的源代碼文件放在我們正在開發的androidsdk的根目錄

SoundPool音樂播放池

MediaPlayer相比,SoundPool的優勢在於CPU資源佔用量低和縶延遲小,缺點SoundPool最大隻能申請1M的內存空間,所以我閃只能播放一些很短的聲音片段,在差的機器上會有很長的延遲,提供的pausestop方法最好不要用,會有問題

應用場景:

1.應用程序中的聲效(按鍵提示音,消息等)

2.遊戲中密集而短暫的聲音(如多個飛船同時爆炸)

3.發射子彈的聲音

播放發射子彈的音效

1.定義按鈕事件

2.mp3資源放入android工程,如果是非圖片文字的資源,我們一般爲這些資源新建一個raw(未經處理的文件夾),把這個文件夾放在androidres資源文件夾下,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.52.0範圍之內

注意的問題:soundPool.load這個方法是非阻塞式的方法,如果把loadplay放在一起的話,那麼會有問題,因爲聲音還沒有加載完成,就播放,會播放沒有聲音,所以聲音池創建的工作應該放在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)

注意在androidIntent傳遞對象的兩種方法(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)//這裏的optsBitmapFactory.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:notificationflags,如果指定FLAG_UPDATE_CURRENT如果有新的notification會更新當前的notification

6.利用notification的管理器把notification顯示出來

nm.notify(id,notification);

id:指定notificationid,如果指定了這個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:指定notificationid,如果指定了這個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文件中的progressBarid

max:最大值

progress:當前的進度

indeterminate:如果是true不確定進度的,如果是false是可以顯示具體進度的,可以設置false;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章