Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 1

本章我们将来学习图像采集和存储的基本知识。我们首先探索android提供的内置功能,然后在后续章节中学习如何定制化软件。内置的图像采集和存储功能是学习Android多媒体功能非常好的入门指南,同时也为后续音频和视频的学习铺路。

我们从如何使用内置相机应用(Camera)开始,之后转到MediaStore使用技巧。 MediaStore是Android内置的多媒体和元数据(metadata)存储机制。在此过程中,我们将研究如何减少内存使用和利用EXIF -- 消费电子和图像处理软件界共享元数据的标准。

使用内置相机应用采集图像

随着移动电话快速地向移动电脑转化,它们在许多方面替代了各种消费电子产品。摄像头是最早加入的与通话无关硬件之一。目前,不带相机功能的手机很难为人们所接受。当然,安卓手机也会不例外;从一开始,Android SDK就支持访问手机中内置的摄像头来采集图像。

在Android中,完成很多事情最简单,最直接的方法就是利用设备的已有软件模块,通过Intent来激活。Intent是Android核心组件,在官方文档中是这样描述它的:一个执行动作的描述。在实践中,Intent用于触发其它应用程序做某件事,或者在一个单一的应用程序的各个Activity之间进行切换。

所有出货的带有相应硬件(摄像头)的Android设备都附带了相机应用。相机应用包含了一个Intent过滤器(Intent filter),它允许开发者提供此应用的图像采集功能给用户,而不需开发自己的定制采集例程。

应用开发者利用Intent过滤器来列举其应用提供的特定功能。通过在应用程序的AndroidManifest.xml中写入一个Intent过滤器,Android系统就知道该应用程序,具体来说,包含该Intent过滤器的Activity,能够应要求完成其指定任务。

相机应用在清单文件(manifest file)包含了下列Intent过滤器。显示在这里的Intent过滤器包含在名为Camera的Activity的标签之中。

<intent-filter>  
	<action android:name="android.media.action.IMAGE_CAPTURE" />  
	<category android:name="android.intent.category.DEFAULT" />  
</intent-filter>

为了使用相机应用,我们只需建立一个能被上述Intent过滤器捕捉到的Intent。

Intent i = new Intent("android.media.action.IMAGE_CAPTURE"); 

在实践中,我们可能不希望直接通过动作字符串(action string)来创建Intent。在本例中,MediaStore类指定了一个常量,ACTION_IMAGE_CAPTURE.我们应该使用常量,而不是字符串本身的原因是:如果字符串改变了,定义的常量很可能也随之变化,从而以前的调用仍然能够正常工作。

Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);  
startActivity(i);

在一个简单的安卓activity中使用这个Intent,该Intent将导致相机应用以静态图片模式启动,如图1-1.

Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 1

图 1-1. 内置相机应用,通过Intent调用运行在模拟器

从相机应用返回数据

当然,单单使用内置相机应用采集一幅图像,而不返回所得数据给调用Activity,并没有多大实际用处。这个可以通过在我们的Activity中,使startActivityForResult方法替换startActivity方法来实现。使用这个方法我们可以获得相机应用返回的数据,这个数据以位图(Bitmap)的形式存在,内容为用户所捕获的图像。

这里是一个简单的例子:

package com.apress.proandroidmedia.ch1.cameraintent;  
import android.app.Activity;  
import android.content.Intent;  
import android.graphics.Bitmap;  
import android.os.Bundle;  
import android.widget.ImageView; 

public class CameraIntent extends Activity {  
    final static int 

    CAMERA_RESULT = 0;  
    ImageView imv;  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);  
        startActivityForResult(i, CAMERA_RESULT);  
    }  
    
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {  
        super.onActivityResult(requestCode, resultCode, intent);  
        if (resultCode == RESULT_OK)  { 

            Bundle extras = intent.getExtras();
            Bitmap bmp = (Bitmap) extras.get("data");  
            imv = (ImageView) findViewById(R.id.ReturnedImageView);
            imv.setImageBitmap(bmp);  
        }  
    }
}  
项目的 layout/mail.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">
 
    <ImageView android:id="@+id/ReturnedImageView" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content">
    </ImageView>  
</LinearLayout>
为了完成上述例子,这里是AndroidManifest.xml的内容:
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    android:versionCode="1"  
    android:versionName="1.0" 
    package="com.apress.proandroidmedia.ch1.cameraintent">  
    <application android:icon="@drawable/icon" 
        android:label="@string/app_name">  
        <activity android:name=".CameraIntent"  
            android:label="@string/app_name">
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
    </application>  
    <uses-sdk android:minSdkVersion="4" />  
</manifest>
在这个例子中,返回的图像包含在相机应用发给调用Activity的Intent的一个extra中。在调用应用的OnActivityResult中可以取得该Intent。该extra的名字为:data,它包含了一个位图对象,使用的时候,需要从通用对象转换到位图对象。 
// Get Extras from the intent  
Bundle extras = intent.getExtras();  
// Get the returned image from that 
extra  Bitmap bmp = (Bitmap) extras.get("data"); 
在我们的布局XML(layout/main.xml)文件中,包含有一个ImageView视图。ImageView为通用视图的扩展,支持图像显示。现在我们有一个id为ReturnImageView的ImageView视图,在Activity中,我们需要取得该视图的一个引用,然后通过setImageBitmap方法,将它显示的位图设置为相机返回的图像,从而用户能够查看捕获到的图像。
为取得ImageView对象的引用,我们使用Activity类的标准方法findViewById。此方法允许我们传入元素的Id,以编程方式引用布局XML文件中指定的元素。布局文件通过调用setContentView来设定。在上述例子中,ImageView对象在XML文件的定义如下:

<ImageView android:id="@+id/ReturnedImageView" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content">
</ImageView>
为引用ImageView,并告知其显示来自相机的位图,我们使用下面的代码:
imv = (ImageView) findViewById(R.id.ReturnedImageView);
imv.setImageBitmap(bmp); 
当你运行这个例子,你可能发现,得到的图像很小。(在我的手机上,它宽121像素,高162像素。其他设备有其他的缺省尺寸。)这并不是一个错误,相反,它是特意设计成这样的。相机应用,当由Intent激活时,并不返回全尺寸图像给调用Activity。在一般情况下,如此做需要相当多的内存,而移动设备在这方面通常有限制。因而相机应用代之以一个很小的缩略图,放在返回的Intent中,如图1-2所示。
Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 1
图1-2 取得的121x162像素图像,显示在我们的ImageView



Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 1

上一篇:Android adb shell启动应用程序的方法


下一篇:UI篇--Android中TableLayout中的布局