標籤:建圖 stop ons sdc 畫圓 tar 中間人 緩衝 private
多媒體概念(瞭解)
電腦圖片大小的計算(掌握)
圖片大小 = 圖片的總像素 * 每個像素佔用的大小
- 單色圖:每個像素佔用1/8個位元組
- 16色圖:每個像素佔用1/2個位元組
- 256色圖:每個像素佔用1個位元組
- 24位元影像:每個像素佔用3個位元組
載入大圖片到記憶體(掌握)
Android系統以ARGB表示每個像素,所以每個像素佔用4個位元組,很容易記憶體溢出
對圖片進行縮放(掌握)
擷取螢幕寬高
Display dp = getWindowManager().getDefaultDisplay(); int screenWidth = dp.getWidth(); int screenHeight = dp.getHeight();
擷取圖片寬高
Options opts = new Options();//請求圖片屬性但不申請記憶體opts.inJustDecodeBounds = true;BitmapFactory.decodeFile("sdcard/dog.jpg", opts);int imageWidth = opts.outWidth;int imageHeight = opts.outHeight;
圖片的寬高除以螢幕寬高,算出寬和高的縮放比例,取較大值作為圖片的縮放比例
int scale = 1;int scaleX = imageWidth / screenWidth;int scaleY = imageHeight / screenHeight;if(scaleX >= scaleY && scaleX > 1){ scale = scaleX;}else if(scaleY > scaleX && scaleY > 1){ scale = scaleY;}
按縮放比例載入圖片
//設定縮放比例opts.inSampleSize = scale;//為圖片申請記憶體opts.inJustDecodeBounds = false;Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);iv.setImageBitmap(bm);
在記憶體中建立圖片的副本(掌握)
直接載入的bitmap對象是唯讀,無法修改,要修改圖片只能在記憶體中建立出一個一模一樣的bitmap副本,然後修改副本
//載入原圖 Bitmap srcBm = BitmapFactory.decodeFile("sdcard/photo3.jpg"); iv_src.setImageBitmap(srcBm); //建立與原圖大小一致的空白bitmap Bitmap copyBm = Bitmap.createBitmap(srcBm.getWidth(), srcBm.getHeight(), srcBm.getConfig()); //定義畫筆 Paint paint = new Paint(); //把紙鋪在畫版上 Canvas canvas = new Canvas(copyBm); //把srcBm的內容繪製在copyBm上 canvas.drawBitmap(srcBm, new Matrix(), paint); iv_copy.setImageBitmap(copyBm);
對圖片進行特效處理(熟悉)
首先定義一個矩陣對象
Matrix mt = new Matrix();
縮放效果
//x軸縮放1倍,y軸縮放0.5倍mt.setScale(1, 0.5f);
旋轉效果
//以copyBm.getWidth() / 2, copyBm.getHeight() / 2點為軸點,順時旋轉30度mt.setRotate(30, copyBm.getWidth() / 2, copyBm.getHeight() / 2);
平移
//x軸座標+10,y軸座標+20mt.setTranslate(10, 20);
鏡面
//把X座標都變成負數mt.setScale(-1, 1);//圖片整體向右移mt.postTranslate(copyBm.getWidth(), 0);
倒影
//把Y座標都變成負數mt.setScale(1, -1);//圖片整體向下移mt.postTranslate(0, copyBm.getHeight());
畫畫板(掌握)
記錄使用者觸摸事件的XY座標,繪製直線 * 給ImageView設定觸摸偵聽,得到使用者的觸摸事件,並獲知使用者觸摸ImageView的座標
iv.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub switch (event.getAction()) { //觸控螢幕幕 case MotionEvent.ACTION_DOWN: //得到觸控螢幕幕時手指的座標 startX = (int) event.getX(); startY = (int) event.getY(); break; //在螢幕上滑動 case MotionEvent.ACTION_MOVE: //使用者滑動手指,座標不斷的改變,擷取最新座標 int newX = (int) event.getX(); int newY = (int) event.getY(); //用上次onTouch方法得到的座標和本次得到的座標繪製直線 canvas.drawLine(startX, startY, newX, newY, paint); iv.setImageBitmap(copyBm); startX = newX; startY = newY; break; } return true; } });
刷子效果,加粗畫筆
paint.setStrokeWidth(8);
調色盤,改變畫筆顏色
paint.setColor(Color.GREEN);
儲存圖片至SD卡
FileOutputStream fos = null;try { fos = new FileOutputStream(new File("sdcard/dazuo.png"));} catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace();}//儲存圖片copyBm.compress(CompressFormat.PNG, 100, fos);
- 系統每次收到SD卡就緒廣播時,都會去遍曆sd卡的所有檔案和檔案夾,把遍曆到的所有多媒體檔案都在MediaStore資料庫儲存一個索引,這個索引包含多媒體檔案的檔案名稱、路徑、大小
- 圖庫每次開啟時,並不會去遍曆sd卡擷取圖片,而是通過內容提供者從MediaStore資料庫中擷取圖片的資訊,然後讀取該圖片
系統開機或者點擊載入sd卡按鈕時,系統會發送sd卡就緒廣播,我們也可以手動發送就緒廣播
Intent intent = new Intent();intent.setAction(Intent.ACTION_MEDIA_MOUNTED);intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));sendBroadcast(intent);
撕衣服(掌握)
原理:把穿內衣和穿外衣的照片重疊顯示,內衣照在下面,使用者滑動螢幕時,觸摸的是外衣照,把手指經過的像素都置為透明,內衣照就顯示出來了
iv.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: int newX = (int) event.getX(); int newY = (int) event.getY(); //把指定的像素變成透明 copyBm.setPixel(newX, newY, Color.TRANSPARENT); iv.setImageBitmap(copyBm); break; } return true; }});
每次只設定一個像素點太慢,以觸摸的像素為圓心,半徑為5畫圓,圓內的像素全部置為透明
for (int i = -5; i < 6; i++) { for (int j = -5; j < 6; j++) { if(Math.sqrt(i * i + j * j) <= 5) copyBm.setPixel(newX + i, newY + j, Color.TRANSPARENT); }}
音樂播放器播放服務(掌握)
- 播放音訊代碼應該運行在服務中,定義一個播放服務MusicService
服務裡定義play、stop、pause、continuePlay等方法
private void play() { // TODO Auto-generated method stub player.reset(); try { player.setDataSource("sdcard/bzj.mp3"); player.prepare(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } player.start(); } private void pause() { player.pause(); } private void stop() { player.stop(); } private void continuePlay() { player.start(); }
- 把這幾個方法抽取成一個介面MusicInterface
- 定義一個中間人類,繼承Binder,實現MusicInterface
先start啟動MusicService,再bind
Intent intent = new Intent(this, MusicService.class);startService(intent);bindService(intent, conn, BIND_AUTO_CREATE);
根據播放進度設定進度條(掌握)
擷取當前的播放時間和當前音訊最長時間
int currentPosition = player.getCurrentPosition();int duration = player.getDuration();
- 播放進度需要不停的擷取,不停的重新整理進度條,使用計時器每500毫秒擷取一次播放進度
發訊息至Handler,把播放進度放進Message對象中,在Handler中更新SeekBar的進度
Timer timer = new Timer();timer.schedule(new TimerTask() { @Override public void run() { int currentPosition = player.getCurrentPosition(); int duration = player.getDuration(); Message msg = Message.obtain(); //把播放進度存入Message中 Bundle data = new Bundle(); data.putInt("currentPosition", currentPosition); data.putInt("duration", duration); msg.setData(data); MainActivity.handler.sendMessage(msg); }}, 5, 500);
在Activity中定義Handler
static Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { //取出訊息攜帶的資料 Bundle data = msg.getData(); int currentPosition = data.getInt("currentPosition"); int duration = data.getInt("duration"); //設定播放進度 sb.setMax(duration); sb.setProgress(currentPosition); };};
拖動進度條改變播放進度
//給sb設定一個拖動偵聽 sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { //停止拖動時調用 @Override public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub int progress = seekBar.getProgress(); mi.seekTo(progress); } //開始拖動時調用 @Override public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } //拖動的時候不斷調用 @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub } });
視頻播放器(熟悉)SurfaceView
- 對畫面的即時更新要求較高
- 雙緩衝技術:記憶體中有兩個畫布,A畫布顯示至螢幕,B畫布在記憶體中繪製下一幀畫面,繪製完畢後B顯示至螢幕,A在記憶體中繼續繪製下一幀畫面
播放視頻也是用MediaPlayer,不過跟音頻不同,要設定顯示在哪個SurfaceView
SurfaceView sv = (SurfaceView) findViewById(R.id.sv);SurfaceHolder sh = sv.getHolder();MediaPlayer player = new MediaPlayer();player.reset();try { player.setDataSource("sdcard/2.3gp"); player.setDisplay(sh); player.prepare();} catch (Exception e) { e.printStackTrace();}player.start();
- SurfaceView是重量級組件,可見時才會建立
給SurfaceHolder設定CallBack,類似於偵聽,可以知道SurfaceView的狀態
sh.addCallback(new Callback() { //SurfaceView銷毀時調用 @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub } //SurfaceView建立時調用 @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub }});
- SurfaceView一旦不可見,就會被銷毀,一旦可見,就會被建立,銷毀時停止播放,再次建立時再開始播放
網路攝影機(熟悉)
啟動系統提供的拍照程式
//隱式啟動系統提供的拍照ActivityIntent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//設定照片的儲存路徑File file = new File(Environment.getExternalStorageDirectory(), "haha.jpg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); startActivityForResult(intent, 0);
啟動系統提供的攝像程式
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);File file = new File(Environment.getExternalStorageDirectory(), "haha.3gp"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); //設定儲存視頻檔案的品質intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);startActivityForResult(intent, 0);
使用Camera類完成照相(熟悉)
Android基礎總結(九)