最近由于项目需要,在学习android系统。android是一个基于linux的专门针对手机平台的操作系统。当然,现在的android 3似乎也将进入平板电脑的市场。由于至今为止,大部分的智能手机采用的是ARM的硬件平台,因此android本身对ARM的平台进行了全面的支持,从源代码中可以看出,也在逐步加入对x86平台的支持,暂时没有看到第三个平台的身影。

这篇文章是我对android系统认识的一个总结,同时介绍一下我至今为止发现的获取屏幕图像数据的方法。经过一定的搜索,我发现方法有很多种,而实现效果会有所差别。其中,有通过最顶层的Android SDK进行截屏,也可以通过C直接读取framebuffer实现。由于framebuffer的方法网上虽然有很多,但是很多我认为并没有写的十分清楚,特别是在编译的方法上,没有找到很好的文章,可能是因为自己找的不够,或者android本身就在不断发展。对此,我在最后给出了一个Android Native Programming的Hello World Howto,需要先到github上mirror下来Android的源代码(2.多G),里边将会带所有的编译器和Emulator等工具。

1 android之我的粗浅理解

android的版本号很有意思,一个版本号对应一个API Level(比如android 2.3.3则对应Android API Level 10)。写这篇文章的时候,最新的android版本号为3.1,而API Level为12。

学习android,首先需要了解的是其系统框架。如下图所示:

android操作系统框架图

这个图在网上比比皆是,这里还是贴了一下,因为的确可以比较好的描述这个系统。它的最底层是linux的内核,只有这一层是工作在内核级的,其余三层都是工作在用户级的。这里,android也不是使用的标准的linux内核,而是一个经过了裁剪,并添加了一些特定功能的内核。其中一个让我记得的比较有意思的feature是,android内核中会有一个叫做Low Memory Killer的驱动,它的主要功能是在系统缺少内存的情况下,杀死进程。显然,我们平时的电脑中,往往不是很需要这个东西;而在手机中,由于资源十分有限,缺少内存的现象或许会发生的非常频繁,这个功能似乎就显得十分重要了(或许还有一个原因是手机没有虚拟内存?毕竟它是用Flash作为长期存储介质,而Flash的特性似乎并不适合作为虚拟内存来使用)。我想这是android针对手机定制进行优化的一个很好的例子。

第二层就是所谓的Native层,由C/C++实现。如果熟悉ARM的应用程序开发的话,我理解这一层就是ARM平台的应用开发层。我们仍然可以用一个类似arm-linux-gcc的交叉编译工具对C程序进行编译(这里是arm-linux-androideabi-gcc)进行编译,具体的方法一会详细介绍。而在这一层,系统给我们提供的库可是比较少的,往往就是最基本的libc等(从提供的可用C基础库来看,数量上肯定是android<ARM<x86/64)。随着android的发展,提供的库也在不断增多。详细的关于Native API的信息需要参考Android NDK Dev Guide文档中有关Stable API的部分。这一层还有一个最核心的东西,就是Dalvik虚拟机。我想,android的核心就是这个虚拟机(或者可以说:Java的核心就是虚拟机?简直是废话!而虚拟机的核心是Portable,即可移植)。

第三层由Java实现,是Android SDK的核心,是android最上层的框架。所有的Android SDK的接口我想就是在这一层实现的了。

最上面就不说了,我们基于android SDK使用Java开发出来的东西应该都在这了。

因为我之前对通用ARM平台有一定的了解,而android也是一个ARM平台,但是比较特殊。让我用我现在的理解来对android总结一下的话:Android=(ARM平台)+(针对手机平台的定制)+(Dalvik虚拟机核心 & Android SDK)。

2 开发平台搭建

在android平台下,我想有三个开发内容。第一个,就是最好入门、最常见的应用程序开发了(也就是我们所说的基于SDK的开发),我们需要搭建一个SDK的环境,还需要懂得Java语言。如何搭建我就不说了,来看看这里吧!另外两个,一个就是ative代码的开发(比如,用C写一个native库,通过JNI给Java调用,或者直接写一个native application),还一个就是牛人们才能搞定的android源代码开发了(我短期恐怕是入不了门了),这些工作都最好搞到android的source tree比较好(这里也包括了所谓的NDK,也就是Native Development Kit)。方法我也不说了,来看这里!

基本的实验方法,SDK在上面的developer网站上写的很详细,有一个HelloWorld的demo,走一遍肯定就知道了。一会我会给出一个利用NDK开发的helloworld。

3 截屏方法种种

是的,让我们开始截屏吧!这里我截屏的环境都是在Android Emulator中(这个基于qemu的模拟器在Android SDK和NDK中都有提供)

3.1 基于Android SDK的截屏方法

主要就是利用SDK提供的View.getDrawingCache()方法。网上已经有很多的实例了。首先创建一个android project,然后进行Layout,画一个按键(res/layout/main.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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截屏文件。

这种截屏有一个问题,就是只能截到一部分,比如电池指示部分就截不出来了。

3.2 基于Android ddmlib进行截屏

这种方法网上有很多相关资料。我也没有测试过,此处略过。

3.3 Android本地编程(Native Programming)读取framebuffer

这是我现在使用的方法。它的优点是整个屏幕都可以截下来,同时不需要写JNI,也不需要Java层的实现。而且如果是emulator的话,也可以直接用adb来操作,十分方便(其实,有一个库android-screenshot-lib应该实现了类似的功能,但是我尝试了一下没有截图成功,图片大小不正确,且是黑屏。就没有进一步尝试了)。

3.3.1 Android的framebuffer介绍

framebuffer是linux内核对显示的最底层驱动。在一般的linux文件系统中,通过/dev/fb0设备文件来提供给应用程序对framebuffer进行读写的访问。这里,如果有多个显示设备,就将依次出现fb1,fb2,…等文件。而在我们所说的android系统中,这个设备文件被放在了/dev/graphics/fb0,而且往往只有这一个。

3.3.2 framebuffer的读取

读取的方法很简单,就将/dev/graphics/fb0当作一般的文件读取即可。可以通过ioctl()方法获取图像的长宽,以及每一个pixel对应的数据量。在android系统中,采用的是rbg565的编码方式。这里编程的方法是C最基本的,难点主要是编译器的配置我会在第4节介绍一个Native的tutorial: hello world程序,这里会讲到编译的方法和具体配置。

3.3.3 在android emulator中利用命令直接进行截屏

这一篇文章有一个大致的流程。主要是用cat读取fb,后用ffmpeg转换编码的方法。此处略。

4 Android本地编程入门:”hello world!” again!

我简单介绍一下怎么在android上开发基本的C程序。如果做过ARM的C应用程序开发的话会发现,ARM一般情况下提供了十分完备的编译器,而android没有而已(android提供了完善的Java层开发工具,C的却不是那么完善)。

4.1 编写hello.c

这个太简单了,不是么?

#include <stdio.h>
int main(void)
{
    printf("hello world!\n");
    return 0;
}

4.2 编写Android的编译器配置文件make_android

在Android SDK中,并没有提供Android系统的C编译器。就算是在NDK中,也只是提供了ndk-build工具,用来编译native static/dynamic library。只有仔细翻阅NDK的手册(它的手册位于NDK根目录的doc/OVERVIEW.html,比较简略),才会发现有一个STANDALONE-TOOLCHAIN的页面,会提到单独编译C Level应用程序的方法。我这里提供一段简单的makefile,命名文件为make_android,用来配置CC宏:

# make_android: this is a sub makefile for android native compile
# you have to set ANDROID_VER and ANDROID_ROOT to your flavor to work
  
### these two things have to be set first!!!
ANDROID_VER=android-8
ANDROID_ROOT=/home/xzpeter/android
  
PLATFORM_DIR=${ANDROID_ROOT}/prebuilt/ndk/android-ndk-r4/platforms
SYSROOT=${PLATFORM_DIR}/${ANDROID_VER}/arch-arm
  
EABI_GCC=${ANDROID_ROOT}/prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-gcc
  
CC=${EABI_GCC} --sysroot=${SYSROOT}

这里,ANDROID_ROOT和ANDROID_VER是需要针对自己的android source目录地址和android API level修改一下的。这里的android source是我用repo sync从github上mirror下来的android源代码。

4.3 编写Makefile

利用上面的make_android,写Makefile:

# to make x86 version of code, run: "make X86=1"
ifdef X86
CC=gcc
CLFAGS=-g
else
include make_android
endif
  
default: hello
  
hello: hello.o
  
clean:
  rm hello *.o

我们提供了X86和android两种编译方式,默认是android方式。

4.4 编译

可以用make X86=1先在本地编译一下,并运行./hello试试看。如果想编译android版本,先make clean一下,然后直接make就可以了。

4.5 在模拟器中运行

利用shell命令启动emulator并将文件放到目标模拟器上去:

emulator -avd my_avd # my_avd is my config name of avd
# wait for some time to boot up
adb push ./hello /data/hello
adb shell chmod 0755 /data/hello
adb shell ./data/hello

应该可以看到返回的”hello world!”字符串了。

转载地址为:

http://xzpeter.org/?p=229

android截屏代码实现方法相关推荐

  1. android开发截屏代码,android截屏代码:C++实现

    android截屏代码:C++实现 示例代码在: frameworks\base\services\surfaceflinger\tests\screencap\screencap.cpp /* * ...

  2. Android截屏方法总结

    最近研究了一些Android的截屏方法,做一个总结. 图片剪裁方法 使用View.getDrawingCache()得到Bitmap.非常简单但是只能截图本应用的图片,并且没办法控制截图的范围. 对B ...

  3. android 截屏函数_android截屏功能实现代码

    这篇文章主要为大家详细介绍了android截屏功能的实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 android开发中通过View的getDrawingCache方法可以达到截屏的目的, ...

  4. android获取activity截图,Android Activity 不能被截屏的解决方法

    Android Activity 不能被截屏的解决方法 在Activity 添加即可 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECU ...

  5. Android截屏截图的几种方法总结

    Android截屏 Android截屏的原理:获取具体需要截屏的区域的Bitmap,然后绘制在画布上,保存为图片后进行分享或者其它用途 一.Activity截屏 1.截Activity界面(包含空白的 ...

  6. android盒子截图,Android截屏截图的几种方法总结

    Android截屏 Android截屏的原理:获取具体需要截屏的区域的Bitmap,然后绘制在画布上,保存为图片后进行分享或者其它用途 一.Activity截屏 1.截Activity界面(包含空白的 ...

  7. Android截屏截图方法汇总(Activity、View、ScrollView、ListView、RecycleView、WebView截屏截图)

    Android截屏 Android截屏的原理:获取具体需要截屏的区域的Bitmap,然后绘制在画布上,保存为图片后进行分享或者其它用途 一.Activity截屏 1.截Activity界面(包含空白的 ...

  8. 三星 android截屏快捷键,三星手机截图快捷键以及截图方法【图文】

    三星手机的出货量仍然占据着全球绝大多数的分量,而三星手机之所以会深受国内外消费者喜欢,主要是因为它拥有非常强大的性能以及非常好的使用体验.而三星手机为了不断增加消费者的使用体验,因此三星为人们开发出了 ...

  9. 三星android截屏快捷键是什么,三星手机怎么快速截屏快捷键(必知这3种截屏方法)...

    对于大部分的用户们来说,相信大家对于智能手机的截屏功能一定不会陌生,在使用手机的过程中也会经常遇到.但是对于一些新手们来说,大家可能还不清楚三星S7怎么截屏,因此今天本文就来和大家分享下三星S7的三种 ...

最新文章

  1. boos里的AHCI RAID_安徒恩Raid删除,安徒恩讨伐战上线,详细攻略快速看,成为新的摸金圣地...
  2. Android—RecyclerView相关内容
  3. HTML5 上传图片预览
  4. C++ 获取函数耗时
  5. 《Python编程从入门到实践》记录之Python函数返回值
  6. 请允许我像亲人一样去爱你
  7. C++ STL 源码剖析之 Traits 编程技法
  8. 大革命修改后无法连接服务器,刺客信条大革命常见问题解决方法 中文设置教学...
  9. zigbee学习之JN5169 串口UARTs
  10. 千锋web前端教学知识点记录及个人理解2
  11. 自适应Simpson法P4525 【模板】自适应辛普森法1
  12. DirectX11 交换链是什么
  13. php小于neq qe,ThinkPHP eq neq if 标签
  14. SAP Scripting Tracker基本使用技巧
  15. FxFactory 7 for Mac(视觉特效软件包)
  16. IT类实习/工作习惯心得
  17. 【IoT】14.Identify Customer Need 拿捏住客户的想法
  18. px4+ros+gazebo+ORB_SLAM2室内视觉无人机导航
  19. vmm_xactor
  20. 以太网物理层协议整理(1)-百兆/千兆以太网

热门文章

  1. 振荡器在电路中的作用是什么
  2. xp无法识别u盘exFAT。插入提示格式化
  3. Python 于 webgame 的应用(下)
  4. 如何用WGDI进行共线性分析(一)
  5. Excel公式注意事项
  6. 机关工勤计算机考试成绩查询,河南省机关事业单位工勤技能岗位考试成绩查询...
  7. 网络:交换机工作原理
  8. 基于CNN和FNN的进化神经元模型的快速响应尖峰神经网络(Matlab代码实现)
  9. 超级容易的WiFi设置方法在这里
  10. mysql dba盲注_MSSQL手工注入 报错注入方法