您的位置:首页 > 移动开发 > Android开发

android屏幕录像

2015-11-16 21:21 441 查看
实现原理:

利用Java反射机制,获取WindowManagerImpl,该类里面有一个mViews的参数,它就是存放最终输出到界面的view视图,把这些视图保存在文件中为png,最后播放的时候从文件中拿出来即可。

一个Activity,一个后台Service既可以完成:

package com.jack.screenrecorder;

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import com.jack.service.RecoderService;

public class MainActivity extends Activity implements OnClickListener{
	
	private static final String TAG = "MainActivity";
	private EditText input;
	private File[] arrayOfFile2;
	private ImageView playView;
	private MainActivityHandler mHandler;
	private boolean flagPlay = false;
	private boolean flagRecorder = false;
	private Button play,recorder,delete;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        input = (EditText)this.findViewById(R.id.input);
        playView = (ImageView)this.findViewById(R.id.playView);
        playView.setImageResource(R.drawable.ic_launcher);
        mHandler = new MainActivityHandler();
        
        play = (Button)this.findViewById(R.id.startPlay);
        recorder = (Button)this.findViewById(R.id.startRecorder);
        delete = (Button)this.findViewById(R.id.delete);
        play.setOnClickListener(this);
        recorder.setOnClickListener(this);
        delete.setOnClickListener(this);
        Log.i(TAG, Environment.getExternalStorageState());
    }

    
    
    @Override
	protected void onStart() {
		// TODO Auto-generated method stub
    	super.onStart();
    	int[] lo = new int[2];
    	input.getLocationOnScreen(lo);
    	Log.i(TAG, "input x y :" + lo[0] + lo[1]);
    	
    	playView.getLocationOnScreen(lo);
    	Log.i(TAG, "playView x y :" + lo[0] + lo[1]);
    	
    	playView.getLocationInWindow(lo);
    	Log.i(TAG, "playView x y :" + lo[0] + lo[1]);
	}

	/**
     * 开始录制方法
     */
    public void startRecorder(){
    	Log.i(TAG, "startRecorder");
    	flagRecorder = true;
    	recorder.setText("停止录制");
    	Intent intent = new Intent(this,RecoderService.class);
    	intent.putExtra("isStart", flagRecorder);
    	startService(intent);
    }
    
    public void endRecorder(){
    	Log.i(TAG, "endRecorder");
    	flagRecorder = false;
    	recorder.setText("开始录制");
    	Intent intent = new Intent(this,RecoderService.class);
    	stopService(intent);
    }
    
    /**
     * 开始播放方法
     */
    public void startPlay(){
    	flagPlay = true;
    	Log.i(TAG, "startPlay");
    	play.setText("停止播放");
    	arrayOfFile2 = getFileList();
    	
    	mHandler.setCount(0);
    	
    	mHandler.sendEmptyMessageDelayed(RecoderService.MSG_WHAT, RecoderService.MSG_DELEAY);
    }
    
    /**
     * 停止播放
     */
    public void endPlay(){
    	flagPlay = false;
    	Log.i(TAG, "endPlay");
    	play.setText("开始播放");
    	mHandler.removeMessages(RecoderService.MSG_WHAT);
    }

    /**
     * 获取存储卡里面路径下的文件列表
     * @return
     */
    public File[] getFileList(){
    	
    	File localFile1 = Environment.getExternalStorageDirectory();
    	File localFile2 = new File(localFile1, RecoderService.PATH);
    	
    	//该路径创建不成功
    	if(!localFile2.exists()){
    		return null;
    	}
    	//返回该路径下的文件列表
    	File[] fileList = localFile2.listFiles();
    	
    	//把文件拿来排序,存放文件时名字为日期,将日期转为long型数据进行排序
    	Arrays.sort(fileList, new Comparator<File>() {

			@Override
			public int compare(File arg0, File arg1) {
				// TODO Auto-generated method stub
				Long preFileLength1 = Long.valueOf(getPreFileName(arg0.getName()));
				
				long preFileLength2 = Long.valueOf(getPreFileName(arg1.getName()));
				
				
				return (int)(preFileLength1-preFileLength2);
			}
    		
		});
    	
    	
    	return fileList;
    }
    
    /**
     * 获取filename的前缀名
     * @param filename
     * @return
     * 如:20150305.jpg    === >>>  20150305
     */
    public String getPreFileName(String filename){
    	String preFileName = null;
    	
    	if(filename == null || filename.length() < 1){
    		Log.i(TAG, "当前文件名为空或长度小于1");
    		return null;
    	}
    	
    	int i = filename.lastIndexOf('.');
    	if(i != -1){
    		int j = filename.length();
    		if(i < j){
    			preFileName = filename.substring(0, i);
    		}
    	}
    	
    	return preFileName;
    }
    
    private class MainActivityHandler extends Handler{

    	private int count = 0;
    	
    	public void setCount(int value){
    		count = value;
    	}
    	
    	public int getCount(){
    		return count;
    	}
    	
		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			if(arrayOfFile2 != null && count < arrayOfFile2.length){
				Bitmap localBitmap = BitmapFactory.decodeFile(arrayOfFile2[count++].getAbsolutePath());		//获取该路径下的文件   并转换为bitmap
				playView.setImageBitmap(localBitmap);
				localBitmap.recycle();
				
				//延迟发送message
				if(flagPlay){
					mHandler.sendEmptyMessageDelayed(RecoderService.MSG_WHAT, RecoderService.MSG_DELEAY);
				}
				
			}
		}
    	
    }

	@Override
	public void onClick(View arg0) {
		// TODO Auto-generated method stub
		switch(arg0.getId()){
		case R.id.startPlay:
			if(flagPlay){
				endPlay();
			}else{
				if(!flagRecorder){
					startPlay();
				}else{
					Toast.makeText(MainActivity.this, "请先关闭录制功能", Toast.LENGTH_SHORT).show();
				}
				
			}
			break;
			
		case R.id.startRecorder:
			if(flagRecorder){
				endRecorder();
			}else{
				if(!flagPlay){
					startRecorder();
				}else{
					Toast.makeText(MainActivity.this, "请先关闭播放功能", Toast.LENGTH_SHORT).show();
				}
			}
			break;
		case R.id.delete:
			if(!flagRecorder && !flagPlay){
				Log.i(TAG, "delete file");
				deleteRecorderFile();
			}else{
				Toast.makeText(MainActivity.this, "请关闭录制和播放功能", Toast.LENGTH_SHORT);
			}
			break;
			
		default:
			break;
		}
	}

	public void deleteRecorderFile(){
		File[] file1 = this.getFileList();
		
		for(File file : file1){
			if(file.isFile() || file.exists()){
				file.delete();
			}
		}
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		int[] lo = new int[2];
    	input.getLocationOnScreen(lo);
    	Log.i(TAG, "input x y :" + lo[0] + lo[1]);
    	
    	playView.getLocationOnScreen(lo);
    	Log.i(TAG, "playView x y :" + lo[0] + lo[1]);
    	
    	playView.getLocationInWindow(lo);
    	Log.i(TAG, "playView x y :" + lo[0] + lo[1]);
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onResume();
		int[] lo = new int[2];
    	input.getLocationOnScreen(lo);
    	Log.i(TAG, "onPause input x y :" + lo[0] + lo[1]);
    	
    	playView.getLocationOnScreen(lo);
    	Log.i(TAG, "playView x y :" + lo[0] + lo[1]);
    	
    	playView.getLocationInWindow(lo);
    	Log.i(TAG, "playView x y :" + lo[0] + lo[1]);
	}
    
	
	
}


后台Service:
package com.jack.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;

public class RecoderService extends Service{

	private static final String TAG = "RecoderService";
	public static final int MSG_WHAT = 256;
	public static final long MSG_DELEAY = 100L;
	public static final String PATH = "/recoder/";
	private boolean isStart = false;
	
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.i(TAG, "onCreate()...");
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		Log.i(TAG, "end Service()===========================================");
		Log.i(TAG, "end Service()===========================================");
		Log.i(TAG, "end Service()===========================================");
		isStart = false;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onStartCommand()===========================================");
		Log.i(TAG, "onStartCommand()===========================================");
		Log.i(TAG, "onStartCommand()===========================================");
		boolean flag = intent.getBooleanExtra("isStart", false);
		
		//如果传递过来的值时开启就开启  否则不开启
		if(flag != isStart){
			isStart = flag;
			if(isStart){
				mHandler.sendEmptyMessageDelayed(MSG_WHAT, MSG_DELEAY);
			}else{
				mHandler.removeMessages(MSG_WHAT);
			}
		}
		
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		return super.onUnbind(intent);
	}
	
	/**
	 * 排序views,以view的绝对坐标
	 * @param viewArray
	 * @return
	 */
	public View[] sortViews(View[] viewArray){
		if(viewArray == null || viewArray.length <= 0){
			Log.i(TAG, "sortView() paramter viewArray is null");
			return null;
		}
		
		int i = 0;
		View[] views = new View[viewArray.length];
		for(View view : viewArray){
			views[i++] = view;
		}
		
		//sort the view
		int length = views.length;
		int[] arrayInt = new int[2];
		for(i = 0; i < length; i++){
			View localView = views[i];
			localView.getLocationOnScreen(arrayInt);
			if(arrayInt[0] > 0 && arrayInt[1] > 0){
				for(int j = i+1; j < views.length; i++){
					views[j-1] = views[j];
				}
				views[views.length-1] = localView;
				i--;
				length--;
			}
		}
		
		return views;
	}

	/**
	 * 
	 * @return views[]s
	 */
	public View[] getWindowDecorViewDownApi15(){
		View[] view = null;
		try {
			Log.i(TAG, "getWindowDecorViewDownApi15");
			Class<?> windowManager = Class.forName("android.view.WindowManagerImpl");
			Field viewFiled = windowManager.getDeclaredField("mViews");
			Field instanceFiled = windowManager.getDeclaredField("mWindowManager");
			viewFiled.setAccessible(true);
			instanceFiled.setAccessible(true);		//可修改
			
			Object instance = instanceFiled.get(null);
			view = (View[]) viewFiled.get(instance);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			Log.i(TAG, "getWindowDecorViewDownApi15() ClassNotFoundException " + e.toString());
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			Log.i(TAG, "getWindowDecorViewDownApi15() NoSuchFieldException " + e.toString());
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return sortViews(view);
	}
	
	/**
	 * 
	 * @return
	 */
	public View[] getWindowDecorViewsApi14_16(){
		View[] view = null;
		try {
			Log.i(TAG, "getWindowDecorViewsApi14_16");
			Class<?> windowManager = Class  
	                .forName("android.view.WindowManagerImpl");       
	        Field viewsField = windowManager.getDeclaredField("mViews");  
	        Field instanceField = windowManager.getDeclaredField("sWindowManager"); 
	        viewsField.setAccessible(true);
	        instanceField.setAccessible(true);		//可修改
			
			Object instance = instanceField.get(null);
			view = (View[]) viewsField.get(instance);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			Log.i(TAG, "getWindowDecorViewDownApi15() ClassNotFoundException " + e.toString());
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			Log.i(TAG, "getWindowDecorViewDownApi15() NoSuchFieldException " + e.toString());
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return sortViews(view);
	}
	
	public View[] getWindowDecorViewsApiUp17(){
		View[] view = null;
		try {
			Log.i(TAG, "getWindowDecorViewsApiUp17");
			Class<?> windowManager = Class  
	                .forName("android.view.WindowManagerGlobal");         
	        Field viewsField = windowManager.getDeclaredField("mViews");  
	        Field instanceField = windowManager.getDeclaredField("sDefaultWindowManager");  
	        viewsField.setAccessible(true);
	        instanceField.setAccessible(true);		//可修改
			
			Object instance = instanceField.get(null);
			view = (View[]) viewsField.get(instance);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			Log.i(TAG, "getWindowDecorViewDownApi15() ClassNotFoundException " + e.toString());
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			Log.i(TAG, "getWindowDecorViewDownApi15() NoSuchFieldException " + e.toString());
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return sortViews(view);
	}
	
	/**
	 * 根据不同的sdk版本采取不同的方法获取图片
	 * @return
	 */
	private View[] getWindowDecorViews(){
		View[] views = null;
		
		if(android.os.Build.VERSION.SDK_INT >= 14 && android.os.Build.VERSION.SDK_INT < 17){
			views = getWindowDecorViewsApi14_16();
		}else if(android.os.Build.VERSION.SDK_INT >= 17){
			views = getWindowDecorViewsApiUp17();
		}else{
			views = getWindowDecorViewDownApi15();
		}
		
		return views;
	}
	
	/**
	 * 从底层获取view在转换为bitmap,在保存到文件
	 */
	public void screenShot(){
		try {
			View[] views = getWindowDecorViews();
			
			Bitmap bitmap = viewsToBitmap(views);
			
			new Thread(new SavePicThread(bitmap)).start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.i(TAG, "screenshot() has a error. " + e.toString()); 
		}
	}
	
	/**
	 * 
	 * @param view
	 * @return Bitmap
	 */
	public Bitmap viewToBitmap(View view){
		Log.i(TAG, "turn view to bitmap");
		/**
		 * set缓冲方便下次调用getDrawingCache把view画到一个bitmap里面去
		 */
		view.setDrawingCacheEnabled(true);
		view.buildDrawingCache();
		Bitmap bitmap1 = view.getDrawingCache();
		Bitmap bitmap2 = null;
		if(bitmap1 != null){
			bitmap2 = Bitmap.createBitmap(bitmap1);
		}
		view.destroyDrawingCache();
		
		return bitmap2;
	}
	
	/**
	 * 将几个view画到一个bitmap有点不懂为什么
	 * @param arrayView
	 * @return
	 */
	public Bitmap viewsToBitmap(View[] arrayView){
		Log.i(TAG, "turn viewssss to bitmap");
		Canvas localCanvas = null;
		Paint mPaint = null;
		Bitmap newBitmap = null;
		int[] location = new int[2];
		
		Bitmap localBitmap = null;
		for(View view : arrayView){
			localBitmap = viewToBitmap(view);
			view.getLocationOnScreen(location);
			//画一个和view尺寸大小的画布
			if(null == localCanvas){
				newBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Config.ARGB_8888);
				localCanvas = new Canvas(newBitmap);
				mPaint = new Paint();
				mPaint.setAntiAlias(true);
			}
			
			localCanvas.drawBitmap(localBitmap, location[0], location[1], mPaint);
			localBitmap.recycle();
			localBitmap = null;
		}
		
		if(localCanvas != null){
			localCanvas.save(Canvas.ALL_S***E_FLAG);
			localCanvas.restore();
		}
		
		return newBitmap;
	}
	
	/**
	 * b保存bitmap为图片
	 * @param paramBitmap
	 * @param paramString
	 */
	public void savePic(Bitmap paramBitmap, String paramString){
		FileOutputStream fsStream = null;
		
		try {
			fsStream = new FileOutputStream(paramString);
			if(fsStream != null){
				paramBitmap.compress(Bitmap.CompressFormat.PNG, 90, fsStream);			//压缩保存
				
				fsStream.flush();
				fsStream.close();
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			
			Log.i(TAG, e.toString());
			Log.i(TAG, "savePic() paramString is not exist" + paramString);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.i(TAG, "savePic() close() flush() is error!");
		}
	}
	
	/**
	 * 保存图片线程
	 * @author JackZhouYu
	 * 将内存中的bitmap写到file里面去,因为是一个比较耗时的工作,所以开线程存储
	 */
	private class SavePicThread implements Runnable{

		private Bitmap bitmap;
		
		public SavePicThread(Bitmap bitmap){
			this.bitmap = bitmap;
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			File file1 = Environment.getExternalStorageDirectory();
			File file2 = new File(file1,PATH);
			//创建目录
			if(!file2.exists()){
				file2.mkdir();
			}
			
			String filename = file2.getAbsolutePath() + "/" + System.currentTimeMillis() + ".png";
			Log.i(TAG, "save pic to file " + filename);
			
			savePic(bitmap, filename);
			
			bitmap.recycle();
			bitmap = null;
		}
		
	}
	
	

	private Handler mHandler = new Handler(){

		@Override
		public void handleMessage(Message msg) {
			
			Log.i(TAG, "mHandler i got message");
			// TODO Auto-generated method stub
			if(msg.what == MSG_WHAT){
				RecoderService.this.screenShot();
				if(isStart){
					mHandler.sendEmptyMessageDelayed(MSG_WHAT, MSG_DELEAY);
				}
			}
		}
		
	};
	
}


但是,这只能录制当前App下的图像
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: