最近公司需求,截取屏幕图片并将图片上传服务器要连续的发送:
有了一点心得就总结了一下,往大神们指点,QQ783491064
当用户接受到截取屏幕的命令后(这里用TCPC传递命令)
EventBus.getDefault().post(new MessageEvent("JiePing"));//发消息去申请截屏的权限
通过EventBus发送申请截取屏幕的权限,
在BaseActivity 中
/** * 接受到示范命令后先去申请截屏权限 * @param messageEvent */ @Subscribe(threadMode = ThreadMode.MAIN) public void onMoonEvent(MessageEvent messageEvent){ if(messageEvent.getMessage().equals("JiePing")){ mMediaProjectionManager = (MediaProjectionManager)getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE); startIntent(); } }
startIntent()方法就是去申请截屏权限
@TargetApi(Build.VERSION_CODES.LOLLIPOP) private void startIntent(){ if(intent != null && result != 0){ (FloatApplication.getInstence()).setResult(result); (FloatApplication.getInstence()).setIntent(intent); EventBus.getDefault().post(new MessageEvent("ShiFanXueSheng"));//发消息申请截屏的权限成功 }else{ if (Build.VERSION.SDK_INT >= 21) { startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); }else{ ToastUtil.showMessage(this,"版本过低,无法截屏"); EventBus.getDefault().post(new MessageEvent("ShiFanFail"));//发消息申请截屏的权限失败 } } if(mMediaProjectionManager!=null)(FloatApplication.getInstence()).setMediaProjectionManager(mMediaProjectionManager); }
申请的返回结果,在全局FloatAppAplication中保存,成功了同样EventBus发送消息
/** * 申请截屏权限 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_MEDIA_PROJECTION: if (resultCode != Activity.RESULT_OK) { EventBus.getDefault().post(new MessageEvent("ShiFanFail"));//发消息申请截屏的权限失败 return; }else if(data != null && resultCode != 0){ result = resultCode; intent = data; (FloatApplication.getInstence()).setResult(resultCode); (FloatApplication.getInstence()).setIntent(data); EventBus.getDefault().post(new MessageEvent("ShiFanXueSheng"));//发消息去申请截屏的权限 } break; } }
在申请完权限后,接受到了申请成功的消息,执行发送图片的方法share();
@Subscribe(threadMode = ThreadMode.MAIN) public void onMoonEvent(MessageEvent messageEvent) { if (messageEvent.getMessage().equals("ShiFanXueSheng")) { share(); } if (messageEvent.getMessage().equals("ShiFanFail")) { ToastUtil.showMessage(this, "屏幕分享失败"); } }
/** * 屏幕分享的方法; */ private void share() { if (!isShare) shotter = new Shotter(getApplicationContext(), FloatApplication.getInstence().getIntent(), screenHandler); if (!shotter.isSchedule()) { ToastUtil.showMessage(myApplication, "屏幕分享开始"); shotter.startScreenShot(MultiCastUDPService.this); shotter.setSchedule(true); } isShare = true; }
截屏的方法我用的类
Shotter来实现的,当完成后通过接口传递我们要用到的mImageReader;
public class Shotter { private final SoftReference<Context> mRefContext; private MultiCastUDPService.ScreenHandler screenHandler; private Intent data; private ImageReader mImageReader; private static MediaProjection mMediaProjection; private VirtualDisplay mVirtualDisplay; private OnShotListener mOnShotListener; public boolean isSchedule() { return isSchedule; } public void setSchedule(boolean schedule) { isSchedule = schedule; } private boolean isSchedule=false;//屏蔽接受到两次命令; public Shotter(Context context, Intent data,MultiCastUDPService.ScreenHandler screenHandler) { this.mRefContext = new SoftReference<>(context); this.data=data; this.screenHandler=screenHandler; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, data); mImageReader = ImageReader.newInstance( getScreenWidth(), getScreenHeight(), PixelFormat.RGBA_8888,// a pixel两节省一些内存 个2个字节 此处RGB_565 必须和下面 buffer处理一致的格式 2); } } private MediaProjectionManager getMediaProjectionManager() { return (MediaProjectionManager) getContext().getSystemService( Context.MEDIA_PROJECTION_SERVICE); } private Context getContext() { return mRefContext.get(); } private int getScreenWidth() { return Resources.getSystem().getDisplayMetrics().widthPixels; } private int getScreenHeight() { return Resources.getSystem().getDisplayMetrics().heightPixels; } //回调接口 public interface OnShotListener { void onFinish(ImageReader imageReader); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void virtualDisplay() { if(mMediaProjection!=null){ mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror", getScreenWidth(), getScreenHeight(), Resources.getSystem().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, screenHandler); } } @TargetApi(Build.VERSION_CODES.KITKAT) public void startScreenShot(OnShotListener onShotListener) { mOnShotListener = onShotListener; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if(mMediaProjection==null){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, data); } } virtualDisplay(); mOnShotListener.onFinish(mImageReader); } } public void toStop() { if (mMediaProjection != null) { mMediaProjection.stop(); mMediaProjection = null; } if (mVirtualDisplay != null) { mVirtualDisplay.release(); mVirtualDisplay = null; } } }
在接口回调的类中
接受到这个imageReader
新建缓存型的线程池(用来发送图片)
给imageReader添加监听
/** * 获取完图片 */ @Override public void onFinish(final ImageReader imageReader) { this.imageReader = imageReader; executorService = Executors.newCachedThreadPool(); imageReader.setOnImageAvailableListener(listener, screenHandler); }
/** * 给ImageReader添加监听器 当有可用的图片时就发送; */ public ImageReader.OnImageAvailableListener listener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { try { image = imageReader.acquireLatestImage();//取出最新图片S Log.d(TAG_LC, "获取到行的可用imagele" + toSend); if (image != null) { Log.d(TAG_LC, "获取到行的可用imagele" + toSend); width = image.getWidth(); height = image.getHeight(); planes = image.getPlanes(); if (planes[0].getBuffer() == null) { return; } byteBuffer = planes[0].getBuffer(); //每个像素的间距 int pixelStride = planes[0].getPixelStride(); //总的间距 int rowStride = planes[0].getRowStride(); int rowPadding = rowStride - pixelStride * width; bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(byteBuffer); byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 20, byteArrayOutputStream); socketStreamWork = new SocketStreamWork(byteArrayOutputStream, content, SENDPICTURE_PORT, screenHandler); mSocketCache.put("sendSocket",new SoftReference<SocketStreamWork>(socketStreamWork)); Log.d(TAG_LC, "建立了一个任务连接SocketStreamWork"); if (executorService == null) { executorService = Executors.newCachedThreadPool(); Log.d("流程", "新建executorService"); } executorService.submit( socketStreamWork); } } catch (Exception e) { Log.d(TAG, e.toString()); Log.d("流程", e.toString()); } finally { if (null != image) image.close(); if (null != byteBuffer) byteBuffer.clear(); if (null != bitmap) { bitmap.recycle(); bitmap = null; } } } };
private Map<String, SoftReference<SocketStreamWork>> mSocketCache = new HashMap<String, SoftReference<SocketStreamWork>>(); /** * 截屏的图片后台线程处理并发送 */ public class ScreenHandler extends Handler { public ScreenHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case 20://当出现错误时的处理关闭线程池 if (executorService != null) { executorService.shutdown(); executorService = null; Log.d("流程", "置空executorService"); try { Thread.sleep(1000); } catch (InterruptedException e) { } } break; } } }
发送图片的socket, 通过这个类将图片发送出去了
/** * Created by on 2017/7/26. */ public class SocketStreamWork implements Runnable { private static final String TAG = "SocketStreamWork"; private MultiCastUDPService.ScreenHandler mHandler; private byte byteBuffer[] = new byte[1024];//缓冲字节数组 private OutputStream outputStream; private ByteArrayOutputStream byteArrayOutputStream; private String serverIp; private int port; private Socket socket; private ByteArrayInputStream byteArrayInputStream; private int bytesize; public SocketStreamWork(ByteArrayOutputStream byteArrayOutputStream, String serverIp, int port, MultiCastUDPService.ScreenHandler mHandler) { this.byteArrayOutputStream = byteArrayOutputStream; this.serverIp = serverIp; this.port = port; this.mHandler=mHandler; } @Override public void run() { //建立Socket连接 try { socket = new Socket(); socket.connect(new InetSocketAddress(serverIp, port), 5 * 1000); if(socket.isConnected()){ outputStream = socket.getOutputStream(); byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); outputStream.write(byteArrayOutputStream.toByteArray().length); while((bytesize = byteArrayInputStream.read(byteBuffer))!=-1){ outputStream.write(byteBuffer,0,bytesize); } byteArrayOutputStream.flush(); byteArrayOutputStream.close(); socket.close(); Log.d("流程","图片上传完毕"); } } catch (Exception e) { Log.d("流程","出现错误了"+e.toString()); toClose(); mHandler.sendEmptyMessage(20); e.printStackTrace(); }finally { toClose(); } } private void toClose() { try { if(socket!=null){ socket.close(); socket=null; } if(outputStream!=null){ outputStream.close(); outputStream=null; } if(byteArrayInputStream!=null){ byteArrayInputStream.close(); byteArrayInputStream=null; } if(byteArrayOutputStream!=null){ byteArrayOutputStream.close(); byteArrayOutputStream=null; } }catch (Exception e){ Log.d(TAG,e.toString()); } } }