Androidカメラ起動加速詳細

4784 ワード

Androidで簡単に使えるカメラを実現するのは簡単です.グーグルが勝手に検索すると使えるSampleがたくさんあります.もちろんグーグルが検索できる他のコードのように、これらのSampleは使えますが、使いやすいのはまだ遠いです.
この文章は、ユーザーが起動ボタンをクリックしてから、ユーザーがリアルタイムのプレビューを見ることができるまでの間、私たちが行った最適化についてだけ話しています.
Androidの携帯電話にはハードウェアがバラバラで、カメラの起動時間が短く、予想しにくい.ユーザーがappを使用する過程で、長すぎる待機は焦りを生む.私たちがしなければならないのは、ユーザーがカメラの起動にかかる時間をできるだけ感じないようにすることです.
ネットで検索できる一般的なカメラSampleによると、カメラの起動からリアルタイムプレビューまで、3つのことをする必要があります.GlSurfaceViewを構築し、そのSurfaceHolderを取得します.2.Camera deviceを取得し、起動します.3.Camera deviceのプレビューを私たちが用意したSurfaceHolderに設定します.
GlSurfaceViewをxmlに次のように書きます.



このGlSurfaceViewはCameraActivityのonCreateで入手できます.しかしGlSurfaceViewがSurfaceHolderを作成すれば準備ができているわけではありません.生成されるSurfaceHolderを待つためにHolderListenerを設定する必要があります.

  private class SurfaceObserver implements
      SupportCamSurfaceView.SurfaceHolderLisener {
 
    public void onSurfaceHolderCreated(SurfaceHolder holder) {
      mSurfaceHolder = holder;
    }
  }
  vCameraPreview.setHolderListener(new SurfaceObserver());

それから私たちはCameraを開きます.

  //        Camera  ,  CameraId    CameraPreviewSize   。          。
  mCamera = Camera.open(mCameraId);

最後にSurfaceHolderをCameraに設定するとプレビューが開きます.

  mCamera.setPreviewTexture(mSurfaceHolder);
  mCamera.startPreview();

一般的にネット上で検索されたSample Codeは、この3つのステップをActivityのonCreateに順番に実行します.つまり、SurfaceHolderListenerがSurfaceHolderを取得してCameraを再起動します.Cameraの起動が完了したら、2つを関連付けてプレビューを起動します.また小米1のこの流れにかかる時間を見てみましょう.
SurfaceHolderListener 0.3秒の取得
Camera 1秒起動
Activityが作成した時間と他のコードが実行された時間を無視すると、1.3秒かかります.ユーザは1秒以上の待ち時間にうんざりしている.ましてや、ある携帯電話ではカメラの起動時間が反人類の1.5秒以上に達することは言うまでもない.
容易に考えられる最適化案の1つは,SurfaceHolderの取得とCameraの起動を2つのスレッドで非同期で行うことである.これで小米1にかかる時間を1秒程度に短縮でき、無理に納得できるはずです.
Surface Holderの取得自体が非同期です.ActivityのonCreateでCameraを起動するために非同期スレッドを再起動するだけです.この2つの非同期スレッドの実行が完了した後、別のスレッドが完了したかどうかをそれぞれ検出します.簡略化されたコードは以下の通りです.

  public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    vCameraPreview.setHolderListener(new SurfaceObserver());
    new Handler().post(new Runnable(){
      public void run(){
        mCamera = Camera.open(mCameraId);
        checkCamera();
      }    
    }); 
  }
 
  private class SurfaceObserver implements
      SupportCamSurfaceView.SurfaceHolderLisener {
 
    public void onSurfaceHolderCreated(SurfaceHolder holder) {
      mSurfaceHolder = holder;
      checkCamera();
    }
  }
 
  private void checkCamera(){
    if(mSurfaceHolder != null && mCamera != null{
      mCamera.setPreviewTexture(mSurfaceHolder);
      mCamera.startPreview();
    }
  }

これで最適化は終わりますか?りんごはどうやって作ったのか考えてみましょう.アップルは、バックグラウンドのロード時間を隠すために移行アニメーションを使うのが好きです.結局、カメラが起動するこの1秒の時間はハードウェアによって制限されているので、appレベルでは短縮できないので、アニメーションを追加して、アニメーションの過程でカメラを事前に起動して、アップル式の小さなtrickを持ってきたほうがいいです.私はカメラのActivityに入るボタンに0.5秒のフィードバックアニメーションをプラスして、またカメラのActivityに0.3秒のPendingアニメーションをプラスして、2つのアニメーションが完成した後に、更に0.2秒の時間小米1のカメラが完成して起動して、これはユーザーにとってすでに完全に受け入れることができます.
上の論理を実現するには2つの問題がある.一つはCameraActivityのインスタンスを取得する前にカメラの起動を開始することであり、もう一つはCameraの起動が完了した後にActivityインスタンスを呼び出すことができないcheckCameraメソッドである.したがって,CameraとActivityのインスタンスをそれぞれ1つのstatic変数に格納するしかない.複雑ではありませんが、変数の回収に注意する必要があります.ActivityのonDestroyではまずCamera releaseをnullに設定し,Activityインスタンスの参照をnullに直接設定すればよい.

  static Camera mCamera; 
  static CameraActivity instance; 
 
  public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    instance = this;
    vCameraPreview.setHolderListener(new SurfaceObserver());
  }
 
  public static void openCamera{
    new Handler().post(new Runnable(){
      public void run(){
        mCamera = Camera.open(mCameraId);
        if(instance != null){
          instance.checkCamera();
        }
      }    
    }); 
  }
 
  private class SurfaceObserver implements
      SupportCamSurfaceView.SurfaceHolderLisener {
 
    public void onSurfaceHolderCreated(SurfaceHolder holder) {
      mSurfaceHolder = holder;
      checkCamera();
    }
  }
 
  private void checkCamera(){
    if(mSurfaceHolder != null && mCamera != null{
      mCamera.setPreviewTexture(mSurfaceHolder);
      mCamera.startPreview();
    }
  }