Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android多媒體開發 Pro Android Media 第一章 Android圖像編程入門 3

Android多媒體開發 Pro Android Media 第一章 Android圖像編程入門 3

編輯:關於Android編程

圖像存儲和元數據

Android提供了一個標准的方式在應用程序之間分享數據。負責此功能的那些類被稱為內容提供者(content provider。內容提供者提供了一個存儲和檢索各類數據的標准接口。

圖像的標准內容提供者(同時也是音頻和視頻的)是MediaStoreMediaStore允許將文件配置到設備上的標准位置,並提供了便利的存儲和檢索文件元數據的方法。元數據是關於數據的數據。它可以包含它所在文件本身的信息,比如文件大小和名稱。但MediaStore還可以設置各種各樣的附加信息,例如標題,描述,緯度和經度。

我們來改變我們的 SizedCameraIntent activity,使用MediaStore來存儲圖像和相關元數據,代替之前將圖像隨意存儲到SD卡上。

為圖像獲取URI

要獲得存儲圖像的標准位置,我們首先需要得到一個MediaStore的引用。為此,我們使用內容解析器(content resolver)。內容解析器是獲取,諸如MediaStore這樣內容提供者的途徑。

通過傳入一個指定的URI,內容解析器知道提供一個接口給MediaStore,作為內容提供者。

因為我們要插入一個新圖像,我們要用的方法是insertURI是定義在android.provider.MediaStore.Images.Media類的常量,名為EXTERNAL_CONTENT_URI.這表示我們想將圖像保存到設備的主外部存儲空間上,一般而言是SD卡。如果我們想保存到設備的內部存儲空間,我們可以用INTERNAL_CONTENT_URI.不過, 一般來說,媒體內容,如圖像,音頻,視頻都相當大,你更可能用EXTERNAL_CONTENT_URI.

之前所示的insert調用返回一個URI,我們可以用來寫入圖像文件的二進制數據。在我們的例子中,如同我們在CameraActivity所做的那樣,我們只是想要把它作為激活相機應用的Intent的一個extra。

Uri imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, 
    new ContentValues());  
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);  
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri); 
startActivityForResult(i, CAMERA_RESULT); 

你會發現,我們還傳遞了一個新建ContentValues對象。ContentValues對象,是記錄創建時我們想要與之關聯的元數據。在前述的例子中,我們傳遞了一個空的ContentValues對象。

預先填入關聯的元數據

如果我們想預先填寫元數據,我們可使用put方法來添加一些數據到其中。ContentValues以名稱-值對接收數據。名稱是標准的,以常量定義在android.provider.MediaStore.Images.Media類中。(某些常量實際上是存在於android.provider.MediaStore.MediaColumns接口,Media類所實現的。)

//保存圖像的名稱和描述到ContentValues的映射表。 
ContentValues contentValues = new ContentValues(3);  
contentValues.put(Media.DISPLAY_NAME, "This is a test title");  
contentValues.put(Media.DESCRIPTION, "This is a test description");  
contentValues.put(Media.MIME_TYPE, "image/jpeg");
 
//添加一個新紀錄,不帶位圖,但是設置了一些值。
//insert()返回新紀錄的URI。 
Uri imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, 
    contentValues); 

同樣,這個調用返回的是一個URI,通過Intent傳遞給相機應用,指定了圖像存儲位置。

如果你通過Log來輸出這個URI,它可能看起來是這樣:

content://media/external/images/media/16

你可能首先發現它看起來像一個普通的URL,如同你在web浏覽器所用的;只不過開頭用Content替換了httphttp是網頁傳輸協議。在Android中,如果一個URIcontent開頭,那麼它必是用於content provider(如MediaStore)。

檢索已存圖像

之前取得的用於存儲圖像的URI,也能作為訪問圖像的路徑。但我們不再傳遞文件的全路徑給BitmapFactory,而是通過內容解析器(content provider)為該圖像打開一個InputStream,傳遞給BitmapFactory。

Bitmap bmp = BitmapFactory.decodeStream(  
    getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions);

創建過後添加元數據

如果我們想在圖像采集到MediaStore之後,給它關聯更多的元數據,可以使用內容解析器(content provider)的update方法。這跟我們之前使用的insert非常類似,除了我們是通過圖像文件的URI來訪問它。

//更新記錄的標題和描述 
ContentValues contentValues = new ContentValues(3);  
contentValues.put(Media.DISPLAY_NAME, "This is a test title");  
contentValues.put(Media.DESCRIPTION, "This is a test description");  
getContentResolver().update(imageFileUri,contentValues,null,null); 

更新CameraActivity,使用MediaStore來存儲圖像和關聯元數據

下面是對之前的例子的更新,新版本將圖像存儲到MediaStore,並給我們展示了如何添加標題和描述。另外,這個版本還有幾個用戶界面元素(UI element),它們的顯示和隱藏基於用戶對程序的操作。

package com.apress.proandroidmedia.ch1.mediastorecameraintent;
  
import java.io.FileNotFoundException;  
import android.app.Activity;  
import android.content.Intent;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.net.Uri; 
import android.os.Bundle;  
import android.util.Log;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.EditText;  
import android.widget.ImageView;  
import android.widget.TextView;  
import android.widget.Toast;  
import android.provider.MediaStore.Images.Media;  
import android.content.ContentValues;  

public class MediaStoreCameraIntent extends Activity {
  
    final static int CAMERA_RESULT = 0;  

    Uri imageFileUri; 

    // 用戶界面元素,定義在/res/layout/main.xml
    ImageView returnedImageView;  
    Button takePictureButton;  
    Button saveDataButton;  
    TextView titleTextView;  
    TextView descriptionTextView;  
    EditText titleEditText;  
    EditText descriptionEditText; 

我們包含了一些用戶界面元素它們已經定義在layout/main.xml中,其對象在上述的代碼中做了聲明。

    @Override  
    public void onCreate(Bundle savedInstanceState)  {  
        super.onCreate(savedInstanceState); 

         //將Content View設置為定義在res/layout/main.xml內的視圖
         setContentView(R.layout.main); 

         //取得用戶界面元素的引用
         returnedImageView = (ImageView) findViewById(R.id.ReturnedImageView);  
         takePictureButton = (Button) findViewById(R.id.TakePictureButton);  
         saveDataButton = (Button) findViewById(R.id.SaveDataButton);  
         titleTextView = (TextView) findViewById(R.id.TitleTextView);  
         descriptionTextView = (TextView) findViewById(R.id.DescriptionTextView);  
         titleEditText = (EditText) findViewById(R.id.TitleEditText);  
         descriptionEditText = (EditText) findViewById(R.id.DescriptionEditText); 



在Activity的標准方法OnCreate裡,調用setContentView之後,我們實例化需要代碼控制的用戶界面元素。 通過findViewById取得用戶界面的引用,然後轉義為對應的類型。

        // 除了takePictureButton之外,所有界面元素初始化為不可見
        //View.GONE 表示不可見,而且不占空間。 
        returnedImageView.setVisibility(View.GONE);  
        saveDataButton.setVisibility(View.GONE);  
        titleTextView.setVisibility(View.GONE);  
        descriptionTextView.setVisibility(View.GONE);  
        titleEditText.setVisibility(View.GONE);  
        descriptionEditText.setVisibility(View.GONE); 

接著,我們將設置所有的用戶界面元素不可見,同時不在布局中占用空間。為此我們傳遞常量View.GONE給setVisibility方法。另一個常量View.INVISIBLE,可以隱藏上述元素,但是仍要在布局中占用空間。

        //當點擊拍照按鈕(Take Picture Button)時
        takePictureButton.setOnClickListener(new OnClickListener() {  
            public void onClick(View v)  {
                //添加一項不帶位圖的新記錄
                //返回新記錄的URI
                imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI,
                    new ContentValues()); 

                // 啟動相機應用                
                Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);
                startActivityForResult(i, CAMERA_RESULT);
            }  
        }); 

在takePictureButton的點擊監聽類OnClickListener裡,我們為內置相機創建了一個標准的Intent,然後調用startAcitivityForResult。放在這裡比直接放在onCreate,用戶體驗要稍微好一些。

        saveDataButton.setOnClickListener(new OnClickListener() {  
            public void onClick(View v)  { 
                //更新MediaStore記錄的標題和描述
                ContentValues contentValues = new ContentValues(3);  
                contentValues.put(Media.DISPLAY_NAME,titleEditText.getText().toString());  
                contentValues.put(Media.DESCRIPTION, 
                    descriptionEditText.getText().toString());  
                getContentResolver().update(imageFileUri,contentValues,null,null); 

                // 通知用戶
                Toast bread = Toast.makeText(MediaStoreCameraIntent.this, 
                   "Record Updated", Toast.LENGTH_SHORT);                  
                bread.show(); 

                //回到初始狀態,設置拍照按鈕可見
                //隱藏其他的用戶界面元素
                takePictureButton.setVisibility(View.VISIBLE);  
                returnedImageView.setVisibility(View.GONE);  
                saveDataButton.setVisibility(View.GONE);  
                titleTextView.setVisibility(View.GONE);  
                descriptionTextView.setVisibility(View.GONE);                  
                titleEditText.setVisibility(View.GONE);  
                descriptionEditText.setVisibility(View.GONE);  
           }
        });  
    }

一旦相機應用返回圖像,saveDataButton變得可見。其監聽類OnClickListener為圖像關聯元數據。它接收用戶輸入到各個EditText元素的值,創建一個ContentValues對象,用來更新MediaStore中該圖像的記錄。

    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

        if (resultCode == RESULT_OK)  { 
            // 相機應用返回了
            // 隱藏拍照按鈕 
            takePictureButton.setVisibility(View.GONE); 
            
            // 顯示其他用戶界面元素            
            saveDataButton.setVisibility(View.VISIBLE);  
            returnedImageView.setVisibility(View.VISIBLE);  
            titleTextView.setVisibility(View.VISIBLE);
            descriptionTextView.setVisibility(View.VISIBLE);
            titleEditText.setVisibility(View.VISIBLE); 
            descriptionEditText.setVisibility(View.VISIBLE);

            // 縮放圖像 
            int dw = 200; //使其最多200像素寬 
            int dh = 200; //使其最多200像素高 

            try  {
                // 加載圖像的尺寸,而非圖像本身
                BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
                bmpFactoryOptions.inJustDecodeBounds = true;
                Bitmap bmp = BitmapFactory.decodeStream(
                    getContentResolver().openInputStream(imageFileUri),
                    null, bmpFactoryOptions);
                int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)dh);
                int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)dw);
                Log.v("HEIGHTRATIO",""+heightRatio);
                Log.v("WIDTHRATIO",""+widthRatio);
            
                // 如果兩個比值都大於1 那麼圖像的某一邊大於屏幕 
                //(譯注:此處注釋不恰當,把dh和dw當作了屏幕尺寸)
                if (heightRatio > 1 && widthRatio > 1)  {
                    if (heightRatio > widthRatio)  { 
                        // 高度比較大,根據它進行縮放
                        bmpFactoryOptions.inSampleSize = heightRatio;  
                    }  
                    else  {
                        // 寬度比較大,根據它進行縮放
                        bmpFactoryOptions.inSampleSize = widthRatio; 
                    } 
                } 

                // 真正解碼圖像
                bmpFactoryOptions.inJustDecodeBounds = false;  
                bmp = BitmapFactory.decodeStream(
                   getContentResolver().openInputStream(imageFileUri),
                   null, bmpFactoryOptions); 

                //顯示圖像 
                returnedImageView.setImageBitmap(bmp); 
            }  
            catch (FileNotFoundException e)  {
                Log.v("ERROR",e.toString());
            }  
        }  
    }  
} 

這是布局的XML文件:main.xml.用於上面的例子。
  
  

    
      

    
      

    
      

    
      

    
      
    
      
      
 

在前面的例子裡,當相機應用返回時,onActivityResult被觸發.新創建的圖像被解碼成位圖並顯示出來。在這個版本中,對相關的用戶界面元素也進行了管理。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved