Android开发笔记:安卓程序截屏方法
1,基于Android SDK的截屏方法
(1)主要就是利用SDK提供的View.getDrawingCache()方法。网上已经有很多的实例了。首先创建一个android project,然后进行Layout,画一个按键(res/layout/main.xml):
<? xml version = "1.0" encoding = "utf-8" ?> android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < TextView android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "@string/hello" /> < Button android:text = "NiceButton" android:id = "@+id/my_button" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:layout_alignParentBottom = "true" ></ Button > </ LinearLayout > |
HelloAndroid.java实现代码为:
package com.example.helloandroid; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import android.app.Activity; import android.graphics.Bitmap; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class HelloAndroid extends Activity { private Button button; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); this .setContentView(R.layout.main); this .button = (Button) this .findViewById(R.id.my_button); this .button.setOnClickListener( new OnClickListener() { public void onClick(View v) { SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd_HH-mm-ss" , Locale.US); String fname = "/sdcard/" + sdf.format( new Date()) + ".png" ; View view = v.getRootView(); view.setDrawingCacheEnabled( true ); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); if (bitmap != null ) { System.out.println( "bitmap got!" ); try { FileOutputStream out = new FileOutputStream(fname); bitmap.compress(Bitmap.CompressFormat.PNG, 100 , out); System.out.println( "file " + fname + "output done." ); } catch (Exception e) { e.printStackTrace(); } } else { System.out.println( "bitmap is NULL!" ); } } }); } } |
这个代码会在按下app中按键的时候自动在手机的/sdcard/目录下生成一个时间戳命名的png截屏文件。
这种截屏有一个问题,就是只能截到一部分,比如电池指示部分就截不出来了。
(2)在APK中调用“adb shell screencap -pfilepath” 命令
(1). 在AndroidManifest.xml文件中添加<uses-permissionandroid:name="android.permission.READ_FRAME_BUFFER"/>(2). 修改APK为系统权限,将APK放到源码中编译, 修改Android.mkLOCAL_CERTIFICATE := platform
publicvoid takeScreenShot(){
String mSavedPath = Environment.getExternalStorageDirectory()+File. separator + "screenshot.png" ;
try {
Runtime. getRuntime().exec("screencap -p " + mSavedPath);
} catch (Exception e) {
e.printStackTrace();
}
(3).利用系统的API,实现Screenshot,这部分代码是系统隐藏的,需要在源码下编译,
权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public boolean takeScreenShot(String imagePath){ if (imagePath.equals( "" )){ imagePath = Environment.getExternalStorageDirectory()+File. separator+ "Screenshot.png" ; } Bitmap mScreenBitmap; WindowManager mWindowManager; DisplayMetrics mDisplayMetrics; Display mDisplay; mWindowManager = (WindowManager) mcontext.getSystemService(Context.WINDOW_SERVICE); mDisplay = mWindowManager.getDefaultDisplay(); mDisplayMetrics = new DisplayMetrics(); mDisplay.getRealMetrics(mDisplayMetrics); float [] dims = {mDisplayMetrics.widthPixels , mDisplayMetrics.heightPixels }; mScreenBitmap = Surface. screenshot(( int ) dims[ 0 ], ( int ) dims[ 1 ]); if (mScreenBitmap == null ) { return false ; } try { FileOutputStream out = new FileOutputStream(imagePath); mScreenBitmap.compress(Bitmap.CompressFormat. PNG, 100 , out); } catch (Exception e) { return false ; } return true ; } |
2 基于Android ddmlib进行截屏
- public class ScreenShot {
- private BufferedImage image = null;
- /**
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- AndroidDebugBridge.init(false); //
- ScreenShot screenshot = new ScreenShot();
- IDevice device = screenshot.getDevice();
- for (int i = 0; i < 10; i++) {
- Date date=new Date();
- SimpleDateFormat df=new SimpleDateFormat("MM-dd-HH-mm-ss");
- String nowTime = df.format(date);
- screenshot.getScreenShot(device, "Robotium" + nowTime);
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- public void getScreenShot(IDevice device,String filename) {
- RawImage rawScreen = null;
- try {
- rawScreen = device.getScreenshot();
- } catch (TimeoutException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (AdbCommandRejectedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- if (rawScreen != null) {
- Boolean landscape = false;
- int width2 = landscape ? rawScreen.height : rawScreen.width;
- int height2 = landscape ? rawScreen.width : rawScreen.height;
- if (image == null) {
- image = new BufferedImage(width2, height2,
- BufferedImage.TYPE_INT_RGB);
- } else {
- if (image.getHeight() != height2 || image.getWidth() != width2) {
- image = new BufferedImage(width2, height2,
- BufferedImage.TYPE_INT_RGB);
- }
- }
- int index = 0;
- int indexInc = rawScreen.bpp >> 3;
- for (int y = 0; y < rawScreen.height; y++) {
- for (int x = 0; x < rawScreen.width; x++, index += indexInc) {
- int value = rawScreen.getARGB(index);
- if (landscape)
- image.setRGB(y, rawScreen.width - x - 1, value);
- else
- image.setRGB(x, y, value);
- }
- }
- try {
- ImageIO.write((RenderedImage) image, "PNG", new File("D:/"
- + filename + ".jpg"));
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- /**
- * 获取得到device对象
- * @return
- */
- private IDevice getDevice(){
- IDevice device;
- AndroidDebugBridge bridge = AndroidDebugBridge
- .createBridge("adb", true);//如果代码有问题请查看API,修改此处的参数值试一下
- waitDevicesList(bridge);
- IDevice devices[] = bridge.getDevices();
- device = devices[0];
- return device;
- }
- /**
- * 等待查找device
- * @param bridge
- */
- private void waitDevicesList(AndroidDebugBridge bridge) {
- int count = 0;
- while (bridge.hasInitialDeviceList() == false) {
- try {
- Thread.sleep(500);
- count++;
- } catch (InterruptedException e) {
- }
- if (count > 240) {
- System.err.print("等待获取设备超时");
- break;
- }
- }
- }
3 Android本地编程(Native Programming)读取framebuffer
(1)命令行,框架的截屏功能是通过framebuffer来实现的,所以我们先来介绍一下framebuffer。
framebuffer介绍
帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行 读写操作。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。
Linux FrameBuffer 本质上只是提供了对图形设备的硬件抽象,在开发者看来,FrameBuffer 是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。所以说FrameBuffer就是一块白板。例如对于初始化为16 位色的FrameBuffer 来说, FrameBuffer中的两个字节代表屏幕上一个点,从上到下,从左至右,屏幕位置与内存地址是顺序的线性关系。
帧缓存有个地址,是在内存里。我们通过不停的向frame buffer中写入数据, 显示控制器就自动的从frame buffer中取数据并显示出来。全部的图形都共享内存中同一个帧缓存。
Android截屏实现思路
Android系统是基于Linux内核的,所以也存在framebuffer这个设备,我们要实现截屏的话只要能获取到framebuffer中的数据,然后把数据转换成图片就可以了,android中的framebuffer数据是存放在 /dev/graphics/fb0 文件中的,所以我们只需要来获取这个文件的数据就可以得到当前屏幕的内容。
现在我们的测试代码运行时候是通过RC(remote controller)方式来运行被测应用的,那就需要在PC机上来访问模拟器或者真机上的framebuffer数据,这个的话可以通过android的ADB命令来实现。
具体实现 /***********************************************************************
*
* ScreenShot.java
***********************************************************************/
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.internal.Base64Encoder;
import com.google.common.io.Closeables;
import com.google.common.io.LittleEndianDataInputStream; /**
*/
public class ScreenShot { /**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
try {
//分辨率大小,后续可以通过代码来获取到当前的分辨率
int xResolution = 320;
int yResolution = 480;
//执行adb命令,把framebuffer中内容保存到fb1文件中
Runtime.getRuntime().exec("adb pull /dev/graphics/fb0 C:/fb1");
//等待几秒保证framebuffer中的数据都被保存下来,如果没有保存完成进行读取操作会有IO异常
Thread.sleep(15000);
//读取文件中的数据
InputStream in = (InputStream)new FileInputStream("C:/fb1");
DataInput frameBuffer = new LittleEndianDataInputStream(in);
BufferedImage screenImage = new BufferedImage(
xResolution, yResolution, BufferedImage.TYPE_INT_ARGB);
int[] oneLine = new int[xResolution];
for (int y = 0; y < yResolution; y++) {
//从frameBuffer中计算出rgb值
convertToRgba32(frameBuffer, oneLine);
//把rgb值设置到image对象中
screenImage.setRGB(0, y, xResolution, 1, oneLine, 0, xResolution);
}
Closeables.closeQuietly(in);
ByteArrayOutputStream rawPngStream = new ByteArrayOutputStream();
try {
if (!ImageIO.write(screenImage, "png", rawPngStream)) {
throw new RuntimeException(
"This Java environment does not support converting to PNG.");
}
} catch (IOException exception) {
// This should never happen because rawPngStream is an in-memory stream.
System.out.println("IOException=" + exception);
}
byte[] rawPngBytes = rawPngStream.toByteArray();
String base64Png = new Base64Encoder().encode(rawPngBytes);
File screenshot = OutputType.FILE.convertFromBase64Png(base64Png);
System.out.println("screenshot==" + screenshot.toString());
screenshot.renameTo(new File("C:\\screenshottemp.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e);
}
}
public static void convertToRgba32(DataInput frameBuffer, int[] into) {
try {
for (int x = 0; x < into.length; x++) {
try{
int rgb = frameBuffer.readShort() & 0xffff;
int red = rgb >> 11;
red = (red << 3) | (red >> 2);
int green = (rgb >> 5) & 63;
green = (green << 2) | (green >> 4);
int blue = rgb & 31;
blue = (blue << 3) | (blue >> 2);
into[x] = 0xff000000 | (red << 16) | (green << 8) | blue;
}catch (EOFException e){
System.out.println("EOFException=" + e);
}
}
} catch (IOException exception) {
System.out.println("convertToRgba32Exception=" + exception);
}
}
}
(2)
- 首先是直接移植SystemUI的代码,实现截图效果,这部分的代码就不贴出来了,直接去下载代码吧, 关键的代码没有几句,最最主要的是:Surface.screenshot(),请看代码吧。
- [java]
- <SPAN style="FONT-SIZE: 16px">package org.winplus.ss;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Matrix;
- import android.os.Bundle;
- import android.util.DisplayMetrics;
- import android.util.Log;
- import android.view.Display;
- import android.view.Surface;
- import android.view.WindowManager;
- import android.os.SystemProperties;
- public class SimpleScreenshotActivity extends Activity {
- private Display mDisplay;
- private WindowManager mWindowManager;
- private DisplayMetrics mDisplayMetrics;
- private Bitmap mScreenBitmap;
- private Matrix mDisplayMatrix;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- new Thread(new Runnable() {
- @Override
- public void run() {
- takeScreenshot();
- }
- }).start();
- }
- private float getDegreesForRotation(int value) {
- switch (value) {
- case Surface.ROTATION_90:
- return 360f - 90f;
- case Surface.ROTATION_180:
- return 360f - 180f;
- case Surface.ROTATION_270:
- return 360f - 270f;
- }
- return 0f;
- }
- private void takeScreenshot() {
- mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- mDisplay = mWindowManager.getDefaultDisplay();
- mDisplayMetrics = new DisplayMetrics();
- mDisplay.getRealMetrics(mDisplayMetrics);
- mDisplayMatrix = new Matrix();
- float[] dims = { mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels };
- int value = mDisplay.getRotation();
- String hwRotation = SystemProperties.get("ro.sf.hwrotation", "0");
- if (hwRotation.equals("270") || hwRotation.equals("90")) {
- value = (value + 3) % 4;
- }
- float degrees = getDegreesForRotation(value);
- boolean requiresRotation = (degrees > 0);
- if (requiresRotation) {
- // Get the dimensions of the device in its native orientation
- mDisplayMatrix.reset();
- mDisplayMatrix.preRotate(-degrees);
- mDisplayMatrix.mapPoints(dims);
- dims[0] = Math.abs(dims[0]);
- dims[1] = Math.abs(dims[1]);
- }
- mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
- if (requiresRotation) {
- // Rotate the screenshot to the current orientation
- Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(ss);
- c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
- c.rotate(degrees);
- c.translate(-dims[0] / 2, -dims[1] / 2);
- c.drawBitmap(mScreenBitmap, 0, 0, null);
- c.setBitmap(null);
- mScreenBitmap = ss;
- }
- // If we couldn't take the screenshot, notify the user
- if (mScreenBitmap == null) {
- return;
- }
- // Optimizations
- mScreenBitmap.setHasAlpha(false);
- mScreenBitmap.prepareToDraw();
- try {
- saveBitmap(mScreenBitmap);
- } catch (IOException e) {
- System.out.println(e.getMessage());
- }
- }
- public void saveBitmap(Bitmap bitmap) throws IOException {
- String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss")
- .format(new Date(System.currentTimeMillis()));
- File file = new File("/mnt/sdcard/Pictures/"+imageDate+".png");
- if(!file.exists()){
- file.createNewFile();
- }
- FileOutputStream out;
- try {
- out = new FileOutputStream(file);
- if (bitmap.compress(Bitmap.CompressFormat.PNG, 70, out)) {
- out.flush();
- out.close();
- }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- </SPAN>
- package org.winplus.ss;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Matrix;
- import android.os.Bundle;
- import android.util.DisplayMetrics;
- import android.util.Log;
- import android.view.Display;
- import android.view.Surface;
- import android.view.WindowManager;
- import android.os.SystemProperties;
- public class SimpleScreenshotActivity extends Activity {
- private Display mDisplay;
- private WindowManager mWindowManager;
- private DisplayMetrics mDisplayMetrics;
- private Bitmap mScreenBitmap;
- private Matrix mDisplayMatrix;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- new Thread(new Runnable() {
- @Override
- public void run() {
- takeScreenshot();
- }
- }).start();
- }
- private float getDegreesForRotation(int value) {
- switch (value) {
- case Surface.ROTATION_90:
- return 360f - 90f;
- case Surface.ROTATION_180:
- return 360f - 180f;
- case Surface.ROTATION_270:
- return 360f - 270f;
- }
- return 0f;
- }
- private void takeScreenshot() {
- mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- mDisplay = mWindowManager.getDefaultDisplay();
- mDisplayMetrics = new DisplayMetrics();
- mDisplay.getRealMetrics(mDisplayMetrics);
- mDisplayMatrix = new Matrix();
- float[] dims = { mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels };
- int value = mDisplay.getRotation();
- String hwRotation = SystemProperties.get("ro.sf.hwrotation", "0");
- if (hwRotation.equals("270") || hwRotation.equals("90")) {
- value = (value + 3) % 4;
- }
- float degrees = getDegreesForRotation(value);
- boolean requiresRotation = (degrees > 0);
- if (requiresRotation) {
- // Get the dimensions of the device in its native orientation
- mDisplayMatrix.reset();
- mDisplayMatrix.preRotate(-degrees);
- mDisplayMatrix.mapPoints(dims);
- dims[0] = Math.abs(dims[0]);
- dims[1] = Math.abs(dims[1]);
- }
- mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
- if (requiresRotation) {
- // Rotate the screenshot to the current orientation
- Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(ss);
- c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
- c.rotate(degrees);
- c.translate(-dims[0] / 2, -dims[1] / 2);
- c.drawBitmap(mScreenBitmap, 0, 0, null);
- c.setBitmap(null);
- mScreenBitmap = ss;
- }
- // If we couldn't take the screenshot, notify the user
- if (mScreenBitmap == null) {
- return;
- }
- // Optimizations
- mScreenBitmap.setHasAlpha(false);
- mScreenBitmap.prepareToDraw();
- try {
- saveBitmap(mScreenBitmap);
- } catch (IOException e) {
- System.out.println(e.getMessage());
- }
- }
- public void saveBitmap(Bitmap bitmap) throws IOException {
- String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss")
- .format(new Date(System.currentTimeMillis()));
- File file = new File("/mnt/sdcard/Pictures/"+imageDate+".png");
- if(!file.exists()){
- file.createNewFile();
- }
- FileOutputStream out;
- try {
- out = new FileOutputStream(file);
- if (bitmap.compress(Bitmap.CompressFormat.PNG, 70, out)) {
- out.flush();
- out.close();
- }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- PS:1、需要在AndroidManifest.xml中加入代码:android:sharedUserId="android.uid.system"
- 2、由于调用了@hide的API,所以编译得时候请使用makefile编译。或者通过在Eclipse中添加Jar文件通过编译。
- 3、此代码只在Android4.0中使用过,2.3的就没去做测试了。
4 利用TakeScreenShotService截图
Android手机一般都自带有手机屏幕截图的功能:在手机任何界面(当然手机要是开机点亮状态),通过按组合键,屏幕闪一下,然后咔嚓一声,截图的照片会保存到当前手机的图库中,真是一个不错的功能!
以我手头的测试手机为例,是同时按电源键+音量下键来实现截屏,苹果手机则是电源键 + HOME键,小米手机是菜单键+音量下键,而HTC一般是按住电源键再按左下角的“主页”键。那么Android源码中使用组合键是如何实现屏幕截图功能呢?前段时间由于工作的原因仔细看了一下,这两天不忙,便把相关的知识点串联起来整理一下,分下面两部分简单分析下实现流程:
Android源码中对组合键的捕获。
Android源码中对按键的捕获位于文件PhoneWindowManager.java(alps\frameworks\base\policy\src\com\android\internal\policy\impl)中,这个类处理所有的键盘输入事件,其中函数interceptKeyBeforeQueueing()会对常用的按键做特殊处理。以我手头的测试机为例,是同时按电源键和音量下键来截屏,那么在这个函数中我们会看到这么两段代码:
1 |
....... |
可以看到正是在这里(响应Down事件)捕获是否按了音量下键和电源键的,而且两个地方都会进入函数interceptScreenshotChord()中,那么接下来看看这个函数干了什么工作:
1 |
private void interceptScreenshotChord() { |
在这个函数中,用两个布尔变量判断是否同时按了音量下键和电源键后,再计算两个按键响应Down事件之间的时间差不超过150毫秒,也就认为是同时按了这两个键后,算是真正的捕获到屏幕截屏的组合键。
附言:文件PhoneWindowManager.java类是拦截键盘消息的处理类,在此类中还有对home键、返回键等好多按键的处理。
Android源码中调用屏幕截图的接口。
捕获到组合键后,我们再看看android源码中是如何调用屏幕截图的函数接口。在上面的函数interceptScreenshotChord中我们看到用handler判断长按组合键500毫秒之后,会进入如下函数:
1 |
private final Runnable mScreenshotChordLongPress = new Runnable() { |
在这里启动了一个线程来完成截屏的功能,接着看函数takeScreenshot():
1 |
private void takeScreenshot() { |
可以看到这个函数使用AIDL绑定了service服务到"com.android.systemui.screenshot.TakeScreenshotService",注意在service连接成功时,对message的msg.arg1和msg.arg2两个参数的赋值。其中在mScreenshotTimeout中对服务service做了超时处理。接着我们找到实现这个服务service的类TakeScreenshotService,看看其实现的流程:
1 |
public class TakeScreenshotService extends Service { |
在这个类中,我们主要看调用接口,用到了mScreenshot.takeScreenshot()传递了三个参数,第一个是个runnable,第二和第三个是之前message传递的两个参数msg.arg1和msg.arg2。最后我们看看这个函数takeScreenshot(),位于文件GlobalScreenshot.java中(跟之前的函数重名但是文件路径不一样):
1 |
/** |
这段代码的注释比较详细,其实看到这里,我们算是真正看到截屏的操作了,具体的工作包括对屏幕大小、旋转角度的获取,然后调用Surface类的screenshot方法截屏保存到bitmap中,之后把这部分位图填充到一个画布上,最后再启动一个延迟的拍照动画效果。如果再往下探究screenshot方法,发现已经是一个native方法了:
1 |
/** |
使用JNI技术调用底层的代码,如果再往下走,会发现映射这这个jni函数在文件android_view_Surface.cpp中,这个真的已经是底层c++语言了,统一调用的底层函数是:
1 |
static jobject doScreenshot(JNIEnv* env, jobject clazz, jint width, jint height, |
Android开发笔记:安卓程序截屏方法的更多相关文章
- IOS开发-几种截屏方法
IOS开发-几种截屏方法 1. UIGraphicsBeginImageContextWithOptions(pageView.page.bounds.size, YES, zoomSc ...
- 【Android开发笔记】程序崩溃异常总结
广播注册相关(broadcastReceiver) 没有注册广播就注销广播 注册广播但未注销广播 注册广播后重复注销广播 解决办法: 添加一个布尔变量,注册广播后为true,若为true在执行注销,注 ...
- [置顶] Android开发笔记(成长轨迹)
分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API ...
- 【转】Android开发笔记(序)写在前面的目录
原文:http://blog.csdn.net/aqi00/article/details/50012511 知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面希望通过分享自己的经 ...
- 【转】Android开发笔记——圆角和边框们
原文地址:http://blog.xianqu.org/2012/04/android-borders-and-radius-corners/ Android开发笔记——圆角和边框们 在做Androi ...
- Android开发笔记:打包数据库
对于数据比较多的控制一般会加入SQLite数据库进行数据存储,在打包时这些数据库是不自动打包到apk中的,如何创建数据库呢 方法1:将创建数据库的sql语句在SQLiteHelper继承类中实现,在第 ...
- Android开发笔记--hello world 和目录结构
原文:Android开发笔记--hello world 和目录结构 每接触一个新东西 都有一个hello world的例子. 1.新建项目 2.配置AVD AVD 没有要新建个,如果不能创建 运行SD ...
- Android开发笔记——以Volley图片加载、缓存、请求及展示为例理解Volley架构设计
Volley是由Google开源的.用于Android平台上的网络通信库.Volley通过优化Android的网络请求流程,形成了以Request-RequestQueue-Response为主线的网 ...
- Android开发笔记(一百三十四)协调布局CoordinatorLayout
协调布局CoordinatorLayout Android自5.0之后对UI做了较大的提升.一个重大的改进是推出了MaterialDesign库,而该库的基础即为协调布局CoordinatorLayo ...
随机推荐
- Unity3D RPC调用顺序问题
使用Unity自带的Network实现多人协同任务时,因为使用RPC传递消息.RPC即远程过程调用,对于它的使用,第一反应的问题就是如果连续两次调用RPC,RPC的函数会顺序执行吗?还是只要RPC的消 ...
- [BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】
题目链接:BZOJ - 1055 题目分析 这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多. 都是将现在 Solve 的区间分成子区间,再求解子区间. 这道题 Sol ...
- 3.2. Grid Search: Searching for estimator parameters
3.2. Grid Search: Searching for estimator parameters Parameters that are not directly learnt within ...
- Effective C++学习笔记:初始化列表中成员列出的顺序和它们在类中声明的顺序相同
类成员的默认初始化顺序是按照声明顺序进行, 如果使用初始化列表初始化成员变量, 则必须按照成员变量的声明顺序进行; 否则, 在变量之间交替赋值时, 会产生, 未初始化的变量去赋值其他变量; 同时GCC ...
- Lua开发环境配置
Lua(英语发音:/ˈluːə/)程序设计语言是一个简洁.轻量.可扩展的脚本语言,是葡萄牙语中“Luna”(月亮)的意思. Lua is a powerful, fast, lightweight, ...
- PHP SPL使用
转载文章:php遗落的宝石 Rafael Dohms 上面的篇文章 让我惊艳了下,忍不住就翻译了下来,同时补充了部分内容. SPL,PHP 标准库(Standard PHP Library) ,此从 ...
- Oracle 搜集统计信息的存储过程
DECLARE CURSOR STALE_TABLE IS SELECT OWNER, SEGMENT_NAME, CASE WHEN SIZE_GB < 0.5 THEN 30 WHEN SI ...
- 【Linux】鸟哥的Linux私房菜基础学习篇整理(十)
1. at [-mldv] TIME/at -c 工作号码:单一工作调度.参数:-m:当at的工作完成后,即使没有输出信息,以email通知用户该工作已完成:-l:相当于atq,列出目前系统上面的所有 ...
- 有两个指针pa,pb分别指向有两个数,a,b,请写一个函数交换两个指针的指向,也就是让pa指向b,让pb指向a
题目:有两个指针pa,pb分别指向有两个数,a,b,请写一个函数交换两个指针的指向,也就是让pa指向b,让pb指向a,具体实现如下: #include<stdlib.h> #include ...
- GitHub的5人骨干小组:早期初创公司该如何招到正确的人
转自:http://news.cnblogs.com/n/190924/ 前 5 年对初创公司来说至关重要,根据美国中小企业发展署的数据,大约 1/4 的初创公司在第一年内关门大吉,只有不到一半的企业 ...