android之手机截屏小程序

Android 手机截屏程序

一:程序运行的大致思路

1、运行程序,显示一个Activity界面,点击按钮,显示一个浮窗。这里用到一个显示浮窗的小技术。

2、在显示浮窗的同时,会启动一个server服务,这个服务很重要,因为在这里会建立java端和android底层(即c语言端)的通信机制。这个地方比较抽象。以后再来解释,你就记住它是一个通信机制,相当于客户端和服务器端的关系

3、点击一下浮窗,就会向android底层发送消息,开始截屏,这里的向android底层发送消息,采用了android源代码里面的通信机制,我直接就把android源码拿来用了。

4、开始截屏,这里的截屏程序也是用的android自带的截屏程序,也是android源码,但是我在这里做了很多的工作。因为截屏出来的图片,我需要保存为png格式。

5、在保存png格式的图片的时候,我又使用了第三方的一个png库。

6、最后的运行效果相当于点击浮窗,开始截屏,再点击浮窗,停止截屏,图片会自动保存到/sdcard/DCIM/这个目录下面。

二:改程序在做的过程中使用到的一些技术

1、要用到android的应用程序开发的基本知识,这里就不多说了

2、用到了ndk开发技术

3、既然使用ndk开发,那C/C++的技术就不得不用了

4、因为做ndk开发,我觉的就相当于在Linux系统下面做c语言的开发,那Linux开发中使用的一些东西也就需要了。

5、最后一点,你的手机需要root。因为截屏的基本思路就读取屏幕像素在内存中的映射,所有需要直接读取内存中的内容,root是必须的。

 

三:程序开发的具体过程

1、从现在起,我会一步一步的把这个程序再重新做一遍,目的就是希望能把之前学习到的东西再回顾一遍,温故而知新。

2、先建立一个截屏项目工程,名字随便吧,我的叫screenshot如图

3、在Activity_main.xml文件中添加一个Button控件,如图

 

MainActivity.java这个类里面做一些简单的初始化,为Button按钮添加点击响应事件,显示浮窗。因为显示浮窗,程序会直接跳到手机的桌面,所以这里有一个小技术,从应用程序直接跳到手机桌面,代码如下。

 

/**

     * 返回到主桌面 类似按下Home按钮

     * 

     * @param context

     */

    public static void backToHomePage(Context context) {

Intent i = new Intent(Intent.ACTION_MAIN);

i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

i.addCategory(Intent.CATEGORY_HOME);

context.startActivity(i);

   }

 

4、要新建一个ScreenCaptureServer,这个类就非常重要了,它主要有这几个作用,首先要创建一个浮窗,其次就是要建立与android底层的连接,然后要维护与android底层的通信。最后也是最重要的,建立截屏程序的独立线程。首先做一个浮窗,很简单,这里就不多说了,具体可以看我的另一篇博客-----android之浮窗篇。

 

5、实现androidjava端与底层的c端通信。因为这里是调用的系统的通信代码,好多我也没有搞清楚。不过现在到是能用,在该程序里面,java端充当的是服务器端,它随service的启动开始运行,不停的监听来自客户端(c端的连接)。下面是服务器线程的具体代码。

 

/**

     * 服务器端的线程

     * 

     * @author jeck

     * 

     */

    private class ServerSocketThread extends Thread {

 

/**

 * 线程运行的标示

 */

private boolean keeprunning = true;

 

/**

 * 本地服务socket

 */

private LocalServerSocket localServerSocket;

 

@Override

public void run() {

    try {

 

// 创建一个本地socket

localServerSocket = new LocalServerSocket("screen_shot_socket");

 

    } catch (Exception e) {

e.printStackTrace();

keeprunning = false;

    }

 

    // 通过while循环, 轮训从客户端发过来的连接请求

    while (keeprunning) {

 

Log.d(TAG"Waitting for client to connect !! ");

 

try {

 

    // 监听客户端的连接

    LocalSocket interactClientSocket = localServerSocket

    .accept();

 

    // 因为有可能在等待客户端连接的时候,accept阻塞了。Activity被finish掉,所以有必要在检测一次

    if (keeprunning) {

Log.d(TAG"now client coming !!!");

 

// 开始为客户端服务

new InteractClientSocketThread(interactClientSocket)

.start();

    }

catch (Exception e) {

    e.printStackTrace();

    keeprunning = false;

}

    }

 

    // 如果断开连接,那就关闭服务

    if (localServerSocket != null) {

 

try {

 

    localServerSocket.close();

catch (Exception e) {

    e.printStackTrace();

}

    }

}

 

// /**

// * 停止线程

// */

// public void stopRunning() {

//

// keeprunning = false;

// }

    }

 

 

6、接下来的是service里面的第三个功能,就是维护与客户端(c端)的通信了。这里无非就是监听连接,连接到了就发送消息。因为要配合我的主要功能,截屏,所有我这里的逻辑是启动service,开启服务器监听,如果有客户端连接,会向客户端发送一个数字2,如果客户端收到2,会向服务器端发送2222表示连接成功,然后如果你点击了我们的小浮窗,会向客户端发送数字1,表示开始截屏,客户端收到消息会想服务器端发送1111表示我客户端已经收到消息了。然后你再点击一次小浮窗,服务器端会发送0,表示停止截屏,那客户端收到0会停止截屏,并向服务器端反馈0000.这就是我的通信机制。下面我把代码粘出来。

/**

     * 服务器与客户端直接的通信线程

     * 

     * @author jeck

     * 

     */

    private class InteractClientSocketThread extends Thread {

 

/**

 * 本地socket

 */

private LocalSocket interactClientSocket;

 

/**

 * 输入流

 */

private InputStream inputStream = null;

 

/**

 * 输出流

 */

private OutputStream outputStream = null;

 

/**

 * 从客户端发来的消息

 */

private StringBuilder receiveFromClientString = new StringBuilder();

 

/**

 * 输入缓存区

 */

private char[] readBuffer = new char[4096];

 

/**

 * 输入字节数

 */

private int readBytes = -1;

 

/**

 * 构造函数

 */

public InteractClientSocketThread(LocalSocket interactClientSocket) {

    this.interactClientSocket = interactClientSocket;

 

}

 

/**

 * 从客户端读取数据

 * 

 * @return

 */

private boolean readDataFromClient() {

 

    boolean readResult = false;

 

    // 从本地连接中获取输入流

    try {

inputStream = interactClientSocket.getInputStream();

 

// 读数据

InputStreamReader inputStreamReader = new InputStreamReader(

inputStream);

 

// 从输入流中读取数据

while ((readBytes = inputStreamReader.read(readBuffer)) != -1) {

 

    String tmpStr = new String(readBuffer, 0, readBytes);

 

    receiveFromClientString.append(tmpStr).append("\n");

}

 

if (receiveFromClientString.toString() != null) {

 

    if (receiveFromClientString.toString().startsWith("0000")

    || receiveFromClientString.toString().startsWith(

    "1111")) {

 

captureState = 2;

    }

 

    // 显示client发送的消息

    Log.d(TAGreceiveFromClientString.toString());

 

    // 读取时间成功

    readResult = true;

}

 

    } catch (IOException e) {

e.printStackTrace();

    }

 

    return readResult;

}

 

/**

 * 向客户端写数据

 * 

 * @return

 */

private boolean writeDataToClient(String writeContent) {

 

    boolean writeResult = false;

 

    try {

outputStream = interactClientSocket.getOutputStream();

 

// 如果点击了开始录屏,则发送消息

if (writeContent != null && !"".equals(writeContent)) {

 

    outputStream.write(writeContent.getBytes());

}

 

writeResult = true;

 

    } catch (IOException e) {

e.printStackTrace();

writeResult = false;

    }

 

    return writeResult;

}

 

@Override

public void run() {

 

    try {

 

switch (captureState) {

 

case 0:

    // 停止截屏

    writeDataToClient(STOP_CAPTURE_SCREEN);

    break;

case 1:

    // 开始录屏

    writeDataToClient(START_CAPTURE_SCREEN);

    break;

case 2:

    // 等待连接

    writeDataToClient(KEEP_CONNECTION);

    break;

}

 

readDataFromClient();

 

    } catch (Exception e) {

e.printStackTrace();

 

Log.d(TAG"receive data failed !!");

    } finally {

 

if (outputStream != null) {

    try {

 

outputStream.close();

    } catch (Exception e) {

e.printStackTrace();

    }

}

if (inputStream != null) {

    try {

inputStream.close();

    } catch (Exception e) {

e.printStackTrace();

    }

}

    }

}

}

 

7、接下来是最关键的部分,呵呵,其实那个地方都很关键,缺少了任何一个地方,这个程序也跑不起来。废话不多说了,现在简绍截屏进程了。这进程的工作原理是这样的。1需要手机root权限,在获取手机root权限之后,通过ndk的混合编译器,编译一个exe文件,在root权限下面,通过代码执行这个exe程序。换句话说就是相当于在java端,执行exe文件。因为android系统是基于Linux操作系统的,所以你的exe想要直接执行,必须获取一点的权限,就算你在Linux系统下面直接写代码,那你执行./xxxx 程序的时候,也是需要权限的。2就是要创建一个进程了(process)。你执行了exe程序,就相当于你创建了一个进程,所以要把这个进程获取出来,以便操作。最后这些东西都是在一个单独的线程中运行的,来代码。

 /**

     * 响应点击截屏按钮

     */

    private boolean screenCapture() {

 

boolean result = false;

try {

 

    // 创建log对象

    screenLog = new StringBuilder();

 

    // 创建一个进程

    logcatProcess = RuntimeHelper.getLogcatProcess(this);

 

    // 创建一个缓冲

    bufferedReader = new BufferedReader(new InputStreamReader(

    logcatProcess.getInputStream()), 8192);

 

    String line;

 

    while ((line = bufferedReader.readLine()) != null) {

 

Log.d(TAG, line);

 

screenLog.append(line).append("\n");

 

if (line.startsWith("Success")) {

 

    result = true;

 

}

    }

 

catch (Exception e) {

    e.printStackTrace();

 

    result = false;

}

 

return result;

    }

 

    /**

     * 使用异步线程执行截屏操作

     * 

     * @author jeck

     * 

     */

    private class ScreenCaptureTask extends AsyncTask {

 

@Override

protected Boolean doInBackground(Void... params) {

 

    return screenCapture();

}

 

@Override

protected void onPostExecute(Boolean result) {

 

    if (result) {

 

// 将日志保存在SD卡上

// try {

// // Utils.saveCaptureLog(screenLog.toString());

// } catch (Exception e) {

// e.printStackTrace();

// }

 

Toast.makeText(getApplicationContext(), "截屏成功",

Toast.LENGTH_LONG).show();

    }

}

}

 

8以上就是我们这个截屏程序的java端的所有代码了,这只是一个好的开始。

java端的功能就是显示一个浮窗,然后点击浮窗,会开始和C端进行交互。

C端涉及的东西就都是C语言的了,这里面都是ndk的知识了,这里首先要编写一个.cpp文件,就是我们的通信程序,因为这里用的是android源代码,所以这个程序目前只适合android4.1系统的。其他版本暂时没有测试。下面这是我的exe程序的主要代码。

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include "screen_capture_image.h"

 

#define TAG "--screen_capture-->"

 

int socketID;

/*

 *获取当前的系统版本

 */

int getCurrentSDKVersion() {

 

int sdk;

char c[PROP_VALUE_MAX];

if (__system_property_get("ro.build.version.sdk", c) > 0) {

 

sscanf(c, "%d", &sdk);

else {

 

sdk = 8;

}

 

return sdk;

}

 

/*

 * Class:     com_rdtd_jni_SendMessageFromClientJNI

 * Method:    startHeartBead

 * Signature: ()I

 */

 

int connection_to_server() {

 

char path[] = "screen_shot_socket";

 

socketID = socket_local_client(path, ANDROID_SOCKET_NAMESPACE_ABSTRACT,

SOCK_STREAM);

 

//如果连接失败

if (socketID < 0) {

 

return socketID;

else {

return 1;

}

 

}

 

void close_connection() {

 

if (socketID) {

close(socketID);

}

}

int read_data_from_server() {

 

//0表示停止录屏,1 表示开始录屏, 2 表示连接中, -1 表示读取数据出错

int result;

 

//读取的字数

int read_result;

char readBuffer[2];

 

memset(readBuffer, 0, 2);

 

read_result = read(socketID, readBuffer, 2);

 

if (read_result) {

 

result = atoi(readBuffer);

//printf("---->read data success :%d\n", result);

 

else {

 

result = -1;

}

 

return result;

}

 

int write_data_to_server(const char *str) {

 

int write_result;

 

write_result = write(socketID, str, strlen(str));

 

if (write_result) {

 

close_connection();

return 1;

else {

 

printf("write data failed !\n");

close_connection();

return 0;

}

 

}

 

void* begin_capture(void*) {

 

long result = 1;

 

//设置截屏开始的标示

set_capture_flag_png(1);

 

//截屏并保存成png图片,现在在联想的机器上是不行的。一直报的是找不到libpng。so文件

screen_capture_png();

 

return (void*) result;

}

 

/*

 *截屏程序的入口,截屏参数都放在这里面。

 *argv[1]表示宽度, argv[2]表示高度

 *默认帧率15帧每秒,宽度和高度是手机屏幕的宽高

 */

int main(int argc, char *argv[]) {

 

int count = 0;

pthread_t thread_id;

void *thread_result;

 

//循环读写数据

while (connection_to_server()) {

 

//先读取数据

int read_result = read_data_from_server();

printf("---->receive message = %d\n", read_result);

__android_log_print(ANDROID_LOG_DEBUG, TAG, "receive message = %d",

read_result);

 

switch (read_result) {

 

case 0:

//停止录制

write_data_to_server("0000---------->");

set_capture_flag_png(0);

 

if (pthread_join(thread_id, &thread_result) == -1) {

printf("waiting thread failed !\n");

else {

 

if ((long) thread_result == 0) {

 

printf("screen_cap return failed \n");

else {

printf("Success------------------>\n");

//这个地方必须返回,否则保存的图片都是黑屏图片,不知道是为什么,呵呵,应该是没有关闭文件,只有函数返回了,系统自动关闭文件

exit(0);

}

 

}

break;

 

case 1:

 

//开始录制

write_data_to_server("1111---------->");

 

if (pthread_create(&thread_id, NULL, begin_capture, NULL) == -1) {

printf("create thread failed !\n");

}

 

break;

 

case 2:

//连接中

write_data_to_server("2222---------->");

break;

 

case -1:

//读取数据出错

printf("---->read data failed !\n");

goto exit;

}

 

sleep(3);

}

 

exit: close_connection();

return 0;

}

 

这个cpp文件就会被ndk编译成我们在上面提到的exe文件,就是Linux系统下面的可执行文件。只有这个文件,我们能做的就是和java端发个信息而已,还是不能截屏的,需要截屏的程序在下面,也是用的android源代码,不过基本让我改的没有源代码的味道了。

在这里,我使用了第三方的png库,我把它编译成静态库,然后链接到我的cpp文件中,最后把cpp文件编译成exe文件,再在代码中执行exe文件。下面是截屏的主要代码。

/*

 * Copyright (C) 2010 The Android Open Source Project

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

 

#include 

#include 

#include 

#include 

#include "screen_capture_image.h"

 

#include 

 

//#ifdef ANDROID_KK //4.4

//#include 

//#include 

//#else

#include 

//#endif

 

using namespace android;

 

#define TAG "--screen_capture-->"

 

//截屏标识

static int capture_flag = 0;

 

//录音标识

static int record_flag = 0;

 

int PushTime = 0;

 

//获取当前时间(microsecond)

int64_t getCurrentTime() {

struct timeval tv;

gettimeofday(&tv, NULL);

return (1000000LL * tv.tv_sec) + tv.tv_usec;

}

 

//#ifdef ANDROID_KK

//static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;

//#endif

 

//显示错误信息

void error(const char* msg) {

fprintf(stderr, "%s: %s:\n", msg, strerror(errno));

exit(1);

}

typedef struct param {

 

void *fb_in;

FILE * fb_out;

int width;

int height;

int64_t usedTime;

size_t buffer_size;

param * next;

 

image_info;

 

// 获取当前日期, 以秒为单位,现在我一秒之内可以截取3张图片,他的名字当然一样了

char* getLocalTime() {

 

char currentTime[128];

 

memset(currentTime, 0, 128);

 

int64_t time = getCurrentTime();

 

sprintf(currentTime, "%lld", time);

 

return currentTime;

}

 

//创建视频路径

void create_video_path(char* path) {

 

memset(path, 0, 256);

 

strcpy(path, "/sdcard/DCIM/Record_");

 

strcat(path, getLocalTime());

 

strcat(path, ".mp4");

 

printf("---->path = %s\n", path);

 

}

 

//创建视频路径

void create_image_path(char* path) {

 

memset(path, 0, 256);

 

strcpy(path, "/sdcard/DCIM/capture_");

 

strcat(path, getLocalTime());

 

strcat(path, ".png");

 

printf("---->path = %s\n", path);

 

}

 

//创建截屏图片信息的节点

image_info* create_image_info_node(const void * in, FILE* out, int w, int h,

size_t size, int64_t ut) {

 

image_info *newInfo = (image_info*) malloc(sizeof(image_info));

 

//分配内存

newInfo->fb_in = malloc(size);

 

//拷贝内存

memcpy(newInfo->fb_in, in, size);

 

newInfo->fb_out = out;

newInfo->buffer_size = size;

newInfo->width = w;

newInfo->height = h;

newInfo->usedTime = ut;

newInfo->next = NULL;

 

printf("---->create a new image node \n");

return newInfo;

}

 

//释放内存

void release_image_node(image_info* node) {

 

if (node != NULL) {

 

free(node->fb_in);

node->fb_in = NULL;

free(node);

node = NULL;

printf("---->success to release a image node \n");

}

}

 

/*

 * fb_base 屏幕左上角的第一个像素的内存地址

 * fb_out 生成的png保存的地址

 * w 屏幕的宽度

 * h 屏幕的高度

 * f png的文件格式

 */

//void take_screenshot(char *fb_base, FILE* fb_out, int w, int h, int f) {

int take_screenshot(image_info *argu) {

 

long result = 0;

 

//printf("take_screenshot is running! \n");

//image_info *argu = (image_info*) param;

 

//png结构

png_structp png;

 

//png info

png_infop info;

 

struct fb_var_screeninfo vinfo;

 

// 因为是一行一行的扫描屏幕,r是行数

unsigned int r;

 

//每一行的长度,是右屏幕的宽度(像素) * 每一个像素的大小(32位 4个字节)

unsigned int rowlen;

 

//每一个像素所占的大小,4个字节

unsigned int bytespp = 4;

 

//创建一个png结构

png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

//printf("1---> png_create_write_struct is runed \n");

 

if (png == NULL) {

ALOGE("failed png_create_write_struct\n");

}

 

png_init_io(png, argu->fb_out);

//printf("2---> png_init_io is runed \n");

 

info = png_create_info_struct(png);

//printf("3---> png_create_info_struct is runed \n");

 

if (info == NULL) {

ALOGE("failed png_create_info_struct\n");

png_destroy_write_struct(&png, NULL);

}

if (setjmp(png_jmpbuf(png))) {

ALOGE("failed png setjmp\n");

png_destroy_write_struct(&png, NULL);

}

 

//设置png的各种信息

png_set_IHDR(png, info, argu->width, argu->height, 8,

PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,

PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

//printf("4---> png_set_IHDR is runed \n");

 

png_write_info(png, info);

//printf("5---> png_write_info is runed \n");

 

//计算每一行的长度

rowlen = argu->width * bytespp;

 

//新建一个临时变量,保存图片的内存块地址

png_bytep temp = (png_bytep) argu->fb_in;

 

//循环扫描屏幕,一行一行的读取数据

for (r = 0; r < argu->height; r++) {

 

//将第r行写到png结构中

png_write_row(png, temp);

 

//计算下一行的起始位置

temp += rowlen;

}

 

//写png的信息

png_write_end(png, info);

//printf("6---> png_write_end is runed \n");

 

png_destroy_write_struct(&png, NULL);

//printf("7---> png_destroy_write_struct is runed \n");

 

//保存完图片,就把文件关闭掉

if (fclose(argu->fb_out) == -1) {

error("close file failed !");

else {

 

//printf("---->success to save a image \n");

temp = NULL;

result = 1;

}

 

return result;

}

 

//保存图片,返回保存成功的图片数量,如果不等于24, 则说明保存失败, 成功返回1, 失败,返回0

void* save_image(void *start) {

 

long result = 0;

image_info * p = (image_info*) start;

image_info * next = NULL;

 

while (p != NULL) {

 

//先将下一个节点的指针保存在next里面

next = p->next;

 

//直接保存,如果成功,则释放该节点所占的内存

if (take_screenshot(p) == 1) {

release_image_node(p);

else {

error("save image failed");

}

 

//最后再将next节点复制给p,继续操作

p = next;

}

 

result = 1;

return (void*) result;

}

 

/*截屏程序*/

image_info* screen_shot() {

 

static int64_t base_time = getCurrentTime();

//截屏的开始时间和结束时间

int64_t beginTime = 0, usedTime = 0;

const void* base;

size_t size;

uint32_t width, height;

 

FILE *fb_out = NULL;

 

//#ifdef ANDROID_KK

//ProcessState::self()->startThreadPool();

//#endif

//

//#ifdef ANDROID_KK

//int32_t displayId = DEFAULT_DISPLAY_ID;

//#endif

 

ScreenshotClient screenshot;

 

beginTime = getCurrentTime();

 

//#ifdef ANDROID_KK

//sp display = SurfaceComposerClient::getBuiltInDisplay(displayId);

//if (display != NULL && screenshot.update(display) == NO_ERROR) {

//#else

if (screenshot.update() == NO_ERROR) {

//#endif

 

base = screenshot.getPixels();

size = screenshot.getSize();

width = screenshot.getWidth();

height = screenshot.getHeight();

 

//计算截图时间

usedTime = getCurrentTime() - beginTime;

 

printf("---->Image: width = %d, height = %d, used time = % lld\n",

screenshot.getWidth(), screenshot.getHeight(), usedTime);

 

char image_path[256];

create_image_path(image_path);

 

fb_out = fopen(image_path, "w");

 

return create_image_info_node(base, fb_out, width, height, size,

usedTime);

}

return NULL;

}

 

//截屏并生成视频链表

void* capture_and_link(void *) {

 

image_info* start = NULL;

image_info* newNode = NULL;

image_info* tail = NULL;

 

//开始截屏并生成截屏链表

while (capture_flag) {

 

//保存视频流

newNode = screen_shot();

if (newNode != NULL) {

 

if (start == NULL) {

start = newNode;

}

 

if (tail != NULL) {

 

tail->next = newNode;

}

 

tail = newNode;

else {

 

printf("---->screen_shot return NULL !\n");

return NULL;

}

 

//睡3秒,不然录制的太快

sleep(3);

}

 

return (void*) start;

}

 

#ifdef __cplusplus

extern "C" {

#endif

 

//设置截屏标志

void set_capture_flag_png(int flag) {

capture_flag = flag;

record_flag = flag;

}

 

//截屏并保存为图片

void screen_capture_png() {

 

//截屏线程,只负责截屏

pthread_t capture_thread;

if (pthread_create(&capture_thread, NULL, capture_and_link, NULL) == -1) {

error("create capture_thread  failed !");

}

 

//截屏之后返回的结果,是一个包含截屏图片信息的链表,这个链表保存的东西关系到整个截屏程序的成败

void* capture_result;

if (pthread_join(capture_thread, &capture_result) == -1) {

 

error("waiting capture_thread failed !");

}

 

//截屏完了,开始保存图片

pthread_t save_thread;

if (pthread_create(&save_thread, NULL, save_image, capture_result) == -1) {

error("create save_thread failed !");

}

 

//等待保存图片的线程

void* save_result;

if (pthread_join(save_thread, &save_result) == -1) {

error("waiting save_thread failed !");

}

 

if ((long) save_result == 1) {

 

printf("---->success to save image !\n");

}

}

#ifdef __cplusplus

}

#endif

到此为止,这个截屏程序的主要代码是都将完了,虽然说将的很简单,但是做起来一点都不简单,里面涉及的东西还是很多的。这需要你对ndk编程很熟悉才可能把这个程序顺利的运行起来

 

你可能感兴趣的:(android之手机截屏小程序)