项目老大让做把截屏的功能做到项目里边,这两天做了很多的准备,参考了不少的资料,准备分享一下
话不多说,先做一个model实现截屏的功能
实现是一个实现截图保存的类Shotter
/** * Created by alongstorm on 17-12-26. */ public class Shotter { //使用软引用有利于尽可能的避免内存泄漏 private final SoftReference代码相信都能看懂mRefContext; private ImageReader mImageReader; private MediaProjection mMediaProjection; private VirtualDisplay mVirtualDisplay; private String mLocalUrl = ""; private OnShotListener mOnShotListener; public Shotter(Context context, Intent data) { this.mRefContext = new SoftReference<>(context); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, data); mImageReader = ImageReader.newInstance( getScreenWidth(), getScreenHeight(), PixelFormat.RGBA_8888,//此处必须和下面 buffer处理一致的格式 ,RGB_565在一些机器上出现兼容问题。 1); } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void virtualDisplay() { mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror", getScreenWidth(), getScreenHeight(), Resources.getSystem().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); } public void startScreenShot(OnShotListener onShotListener, String loc_url) { mLocalUrl = loc_url; startScreenShot(onShotListener); } @TargetApi(Build.VERSION_CODES.KITKAT) public void startScreenShot(OnShotListener onShotListener) { mOnShotListener = onShotListener; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { virtualDisplay(); Handler handler = new Handler(); handler.postDelayed(() -> { Image image = mImageReader.acquireLatestImage(); AsyncTaskCompat.executeParallel(new SaveTask(), image); }, 300); } } public class SaveTask extends AsyncTask , Void, Bitmap> { @TargetApi(Build.VERSION_CODES.KITKAT) @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(); File fileImage = null; if (bitmap != null) { try { if (TextUtils.isEmpty(mLocalUrl)) { mLocalUrl = Environment.getExternalStorageDirectory().getAbsolutePath() //getContext().getExternalFilesDir("screenshot").getAbsoluteFile() + "/" + SystemClock.currentThreadTimeMillis() + "666.png"; } fileImage = new File(mLocalUrl); if (!fileImage.exists()) { fileImage.createNewFile(); } FileOutputStream out = new FileOutputStream(fileImage); if (out != null) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); out.flush(); out.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); fileImage = null; } catch (IOException e) { e.printStackTrace(); fileImage = null; } } if (fileImage != null) { return bitmap; } return null; } @TargetApi(Build.VERSION_CODES.KITKAT) @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); } if (mVirtualDisplay != null) { mVirtualDisplay.release(); } if (mOnShotListener != null) { mOnShotListener.onFinish(); } } } 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; } // a call back listener public interface OnShotListener { void onFinish(); } }
然后就是写一个调用截屏的Activity
public class ScreenShotActivity extends Activity { public static final int REQUEST_MEDIA_PROJECTION = 0x2893; @Override protected void onCreate(Bundle savedInstanceState) { setTheme(android.R.style.Theme_Dialog);//这个在这里设置 之后导致 的问题是 背景很黑 super.onCreate(savedInstanceState); //如下代码 只是想 启动一个透明的Activity 而上一个activity又不被pause requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT)); getWindow().setDimAmount(0f); requestScreenShot(); } @SuppressLint("WrongConstant") public void requestScreenShot() { if (Build.VERSION.SDK_INT >= 21) { startActivityForResult( ((MediaProjectionManager) getSystemService("media_projection")).createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION ); } else { toast("版本过低,无法截屏"); } } private void toast(String str) { Toast.makeText(ScreenShotActivity.this, str, Toast.LENGTH_LONG).show(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_MEDIA_PROJECTION: { if (resultCode == -1 && data != null) { Shotter shotter = new Shotter(ScreenShotActivity.this, data); shotter.startScreenShot(() -> { toast("完成!"); finish(); // don't forget finish activity }); } } default: break; } } }以上就是需要使用的model了,下面开始说一下怎么用,
compile project(':libshot')
首先把这个写到依赖里边
然后就是清单文件添加权限
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
然后声明一下需要调用的model的Activity
android:name="com.androidyuan.lib.screenshot.ScreenShotActivity"
android:theme="@android:style/Theme.Dialog" />
然后在需要的地方去调用
startActivity(new Intent(MainActivity.this, ScreenShotActivity.class));是不是炒鸡简单,但是这么玩只能在安卓5.0以后,诶!
4.4的用户至今仍然不想放弃啊