Android实现截屏功能
导言
目前截屏的方法很多,root不适用,要么其他方法就是有局限性,而其中官方给出的方案最好—MediaProjection
介绍
Android 5.0以后开放的录屏API,取视频中的一帧数据,这样就可以实现截屏
步骤
在activity中授权,在service中完成初始化并截图,当然可以后台定时截图,但是6.0系统会有内存溢出的bug
1:build.gradle
compileSdkVersion 21 buildToolsVersion '27.0.3' defaultConfig { applicationId "com.aile.screenshot" multiDexEnabled true minSdkVersion 21 targetSdkVersion 21 versionCode 1 versionName "1.0" }
2:在activity中授权
public void requestCapturePermission() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return; } MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_MEDIA_PROJECTION: if (resultCode == RESULT_OK && data != null) { Service.setResultData(data); startService(new Intent(this, Service.class)); finish(); } break; } }
3:在service中初始化ImageReader,MediaProjection
private void createImageReader() { mImageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 1); } public void setUpMediaProjection() { mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, mResultData); } }
4:在service中完成截图重要步骤:
private void startScreenShot() { Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { startVirtual(); } }, 0); handler.postDelayed(new Runnable() { @Override public void run() { startCapture(); } }, 50); } public void startVirtual() { if (mMediaProjection != null) { virtualDisplay(); } else { setUpMediaProjection(); virtualDisplay(); } } private void virtualDisplay() { mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror", mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); } //异常处理的核心 private void startCapture() { Image image = null; try { image = mImageReader.acquireLatestImage(); } catch (IllegalStateException e) { if (null != image) { image.close(); image = null; image = mImageReader.acquireLatestImage(); } } if (image == null) { startScreenShot(); } else { SaveTask mSaveTask = new SaveTask(); AsyncTaskCompat.executeParallel(mSaveTask, image); new Handler().postDelayed(new Runnable() { @Override public void run() { stopVirtual(); tearDownMediaProjection(); } }, 0); } } public class SaveTask extends AsyncTask<Image, Void, Bitmap> { @Override protected Bitmap doInBackground(Image... params) { if (params == null || params.length < 1 || params[0] == null) { return null; } Image image = params[0]; int width = image.getWidth(); int height = image.getHeight(); final Image.Plane[] planes = image.getPlanes(); final ByteBuffer buffer = planes[0].getBuffer(); int pixelStride = planes[0].getPixelStride(); int rowStride = planes[0].getRowStride(); int rowPadding = rowStride - pixelStride * width; Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888); bitmap.copyPixelsFromBuffer(buffer); //这就是初始截图 bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height); image.close(); return bitmap; } @Override protected void onPostExecute(final Bitmap bitmap) { super.onPostExecute(bitmap); //处理bitmap的业务代码 }
5:Bitmap转IS流,指定区域截图
// 将Bitmap转换成InputStream ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); InputStream inputStream = new ByteArrayInputStream(bos.toByteArray()); //指定区域截图 Rect mRect = new Rect(51, 74, 58, 62); BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, true); Bitmap bm = bitmapRegionDecoder.decodeRegion(mRect, null);
6:定时任务的处理
private Timer timer = new Timer(); public void shootByTime() { final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { startScreenShot(); super.handleMessage(msg); } }; timer.schedule(new TimerTask() { @Override public void run() { Message message = new Message(); message.what = 1; handler.sendMessage(message); } }, 0, 100); }
7:横竖屏的处理
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (newConfig.orientation == this.getResources().getConfiguration().ORIENTATION_PORTRAIT) { mRect = new Rect(51, 775, 745, 47); } else if (newConfig.orientation == this.getResources().getConfiguration().ORIENTATION_LANDSCAPE) { mRect = new Rect(54, 24, 545, 45); } }
8:还有很多,只需按照需求走就OK,没有难的东西,需要不停的学习和积累
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
Android上传多张图片的实例代码(RxJava异步分发)
本篇文章主要介绍了Android上传多张图片的实例代码(RxJava异步分发),具有一定的参考价值,有兴趣的可以了解一下2017-08-08Android Studio不能获取远程依赖包的完美解决方法
这篇文章主要介绍了Android Studio不能获取远程依赖包的解决方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下2017-11-11Android Activity中onStart()和onResume()的区别分析
这篇文章主要介绍了Android Activity中onStart()和onResume()的区别,结合Activity的四种状态简单分析了Android Activity中onStart()和onResume()方法的作用,并补充说明了Activity中六个常用函数,需要的朋友可以参考下2016-01-01Android_RecyclerView实现上下滚动广告条实例(带图片)
本篇文章主要介绍了Android_RecyclerView实现上下滚动广告条实例(带图片),具有一定的参考价值,感兴趣的小伙伴们可以参考一下2017-06-06Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多
这篇文章主要介绍了Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下2016-07-07Android通过XListView实现上拉加载下拉刷新功能
这篇文章主要为大家详细介绍了Android通过XListView实现上拉加载下拉刷新功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2017-12-12Adnroid 自定义ProgressDialog加载中(加载圈)
这篇文章主要介绍了Adnroid 自定义ProgressDialog加载中(加载圈),需要的朋友可以参考下2017-06-06Android 根据EditText搜索框ListView动态显示数据
这篇文章主要介绍了Android 根据EditText搜索框ListView动态显示数据的相关资料,需要的朋友可以参考下2016-09-09
最新评论