2015-08-24 93 views
0

我有一个问题要解决 - 我正在尝试一切,没有任何工作。 我正在写一个应用程序,它应该每分钟拍摄一张照片(图片之间的时间段可能会更长,但这并不重要),并将其上传到ftp服务器。我正在尝试在拍照之前打开相机,然后拍照并释放它并停止预览。但这并不奏效 - 甚至没有拍过一张照片。打开相机等正在处理。如果我只用处理程序takePicture方法 - 应用程序工作正常(并打开相机一次,并保持打开onCreate方法),但我想释放相机并打开它之前拍照以节省电池。 我附上我的源代码和logcat。Android - 每分钟用相机拍照

MainActivity.java

public class MainActivity extends ActionBarActivity { 

private Camera mCamera; 
private CameraPreview mPreview; 
private File pictureFile; 
private File mediaStorageDir; 
private Context context; 
private Handler handler; 

public Camera.PictureCallback mPicture = new Camera.PictureCallback() { 

    @Override 
    public void onPictureTaken(byte[] data, Camera camera) { 
     pictureFile = getOutputMediaFile(); 
     if (pictureFile == null) { 
      Log.d("TAG", "Error creating media file, check storage permissions: "); 
      return; 
     } 
     try { 
      FileOutputStream fos = new FileOutputStream(pictureFile); 
      fos.write(data); 
      fos.close(); 
     } catch (FileNotFoundException e) { 
      Log.d("TAG", "File not found: " + e.getMessage()); 
     } catch (IOException e) { 
      Log.d("TAG", "Error accessing file: " + e.getMessage()); 
     } 
     Log.d("ftp", "photo taken: " + pictureFile); 
     mCamera.release(); 
     startFTP(); 
    } 
}; 

private Runnable runnable = new Runnable() { 
    @Override 
    public void run() { 
     try { 
      mCamera = Camera.open(); 
     } catch (Exception e) { 
     } 
     Camera.Parameters params = mCamera.getParameters(); 
     params.setPictureSize(1920, 1080); 
     if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { 
      params.set("orientation", "portrait"); 
      params.set("rotation", 90); 
     } 
     if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { 
      params.set("orientation", "landscape"); 
     } 
     mCamera.setParameters(params); 
     mPreview = new CameraPreview(context, mCamera); 
     FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); 
     preview.addView(mPreview); 
     mCamera.startPreview(); 
     mCamera.takePicture(null, null, mPicture); 
     try { 
      this.wait(5000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     handler.postDelayed(this, 60000); 
    } 
}; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    context = getApplicationContext(); 
    handler = new Handler(); 
    Button captureButton = (Button) findViewById(R.id.button_capture); 
    captureButton.setOnClickListener(
      new View.OnClickListener() { 
       @Override 
       public void onClick(View v) { 
        handler.post(runnable); 
       } 
      } 
    ); 
} 

public void startFTP() { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       Log.d("ftp", "photo uploading started: " + pictureFile); 
       String sendingPictureName = pictureFile.getName(); 
       String serverAddress = "1111111"; 
       String userId = "111111"; 
       String password = "111111"; 
       FTPClient ftp = new FTPClient(); 
       try { 
        ftp.connect(serverAddress); 
        ftp.login(userId, password); 
        int reply = ftp.getReplyCode(); 
        if (!FTPReply.isPositiveCompletion(reply)) { 
         ftp.disconnect(); 
        } 
        ftp.setFileType(FTP.BINARY_FILE_TYPE); 
        ftp.enterLocalPassiveMode(); 
        ftp.changeWorkingDirectory("/111111"); 
        InputStream input; 
        input = new FileInputStream(pictureFile); 
        if (ftp.storeFile(pictureFile.getName(), input)) { 
         File fileToDelete = new File(mediaStorageDir.getPath() +"/"+ sendingPictureName); 
         //Log.d("ftp", "sciezka do usuwanego pliku: " + fileToDelete.getAbsolutePath()); 
         fileToDelete.delete(); 
        } 
        input.close(); 
        Log.d("ftp", "photo uploading ended: " + sendingPictureName); 
        ftp.logout(); 
        ftp.disconnect(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     }).start(); 

} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.menu_main, menu); 
    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    // Handle action bar item clicks here. The action bar will 
    // automatically handle clicks on the Home/Up button, so long 
    // as you specify a parent activity in AndroidManifest.xml. 
    int id = item.getItemId(); 
    //noinspection SimplifiableIfStatement 
    if (id == R.id.action_settings) { 
     return true; 
    } 
    return super.onOptionsItemSelected(item); 
} 

private File getOutputMediaFile() { 
    mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
      Environment.DIRECTORY_PICTURES), "MyCameraApp"); 
    if (!mediaStorageDir.exists()) { 
     if (!mediaStorageDir.mkdirs()) { 
      Log.d("MyCameraApp", "failed to create directory"); 
      return null; 
     } 
    } 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    File mediaFile; 
    mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); 
    return mediaFile; 
} 


public void cancelTimer(View view) { 
    handler.removeCallbacks(runnable); 
} 
} 

CameraPreview.java

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 
private SurfaceHolder mHolder; 
private Camera mCamera; 

public CameraPreview(Context context, Camera camera) { 
    super(context); 
    mCamera = camera; 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
} 

public void surfaceCreated(SurfaceHolder holder) { 
    try { 
     mCamera.setPreviewDisplay(holder); 
     mCamera.setDisplayOrientation(90); 
     mCamera.startPreview(); 
    } catch (IOException e) { 
     Log.d("TAG", "Error setting camera preview: " + e.getMessage()); 
    } 
} 

public void surfaceDestroyed(SurfaceHolder holder) { 
} 

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    if (mHolder.getSurface() == null){ 
     // preview surface does not exist 
     return; 
    } 
    try { 
     mCamera.stopPreview(); 
    } catch (Exception e){ 
    } 
    try { 
     mCamera.setPreviewDisplay(mHolder); 
     mCamera.startPreview(); 
    } catch (Exception e){ 
     Log.d("TAG", "Error starting camera preview: " + e.getMessage()); 
    } 
} 
} 

activity_main.xml中 - 这是仅用于测试布局,它并不完美

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="horizontal" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
> 
<FrameLayout 
    android:id="@+id/camera_preview" 
    android:layout_width="500px" 
    android:layout_height="500px" 
    android:layout_weight="0.1" 
    android:layout_above="@+id/button_capture" /> 

<Button 
    android:id="@+id/button_capture" 
    android:text="start timer" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center" 
    android:layout_weight="1" 
    android:layout_alignParentEnd="false" 
    android:layout_alignParentStart="false" 
    android:layout_centerVertical="true" /> 

<Button 
    android:id="@+id/timer_button" 
    android:text="stop timer" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center" 
    android:layout_weight="1" 
    android:layout_below="@+id/button_capture" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentStart="false" 
    android:onClick="cancelTimer" /> 

的logcat:

08-24 09:42:42.828 8935-8935/? E/Zygote﹕ MountEmulatedStorage() 
08-24 09:42:42.828 8935-8935/? I/libpersona﹕ KNOX_SDCARD checking this for 10185 
08-24 09:42:42.828 8935-8935/? E/Zygote﹕ v2 
08-24 09:42:42.828 8935-8935/? I/libpersona﹕ KNOX_SDCARD not a persona 
08-24 09:42:42.828 8935-8935/? I/SELinux﹕ Function: selinux_compare_spd_ram , priority [2] , priority version is VE=SEPF_SM-A500FU_5.0.2_0023 
08-24 09:42:42.838 8935-8935/? E/SELinux﹕ [DEBUG] get_category: variable seinfo: default sensitivity: NULL, cateogry: NULL 
08-24 09:42:42.838 8935-8935/? I/art﹕ Late-enabling -Xcheck:jni 
08-24 09:42:42.878 8935-8935/? D/TimaKeyStoreProvider﹕ TimaSignature is unavailable 
08-24 09:42:42.878 8935-8935/? D/ActivityThread﹕ Added TimaKeyStore provider 
08-24 09:42:42.988 8935-8935/com.example.dawid.camerabezpodgladu D/PhoneWindow﹕ *FMB* installDecor mIsFloating : false 
08-24 09:42:42.988 8935-8935/com.example.dawid.camerabezpodgladu D/PhoneWindow﹕ *FMB* installDecor flags : -2139029248 
08-24 09:42:43.108 8935-8951/com.example.dawid.camerabezpodgladu D/OpenGLRenderer﹕ Render dirty regions requested: true 
08-24 09:42:43.118 8935-8935/com.example.dawid.camerabezpodgladu D/PhoneWindow﹕ *FMB* isFloatingMenuEnabled mFloatingMenuBtn : null 
08-24 09:42:43.118 8935-8935/com.example.dawid.camerabezpodgladu D/PhoneWindow﹕ *FMB* isFloatingMenuEnabled return false 
08-24 09:42:43.138 8935-8935/com.example.dawid.camerabezpodgladu D/SRIB_DCS﹕ log_dcs ThreadedRenderer::initialize entered! 
08-24 09:42:43.138 8935-8951/com.example.dawid.camerabezpodgladu I/Adreno-EGL﹕ <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: SKARAJGA_AU_LINUX_ANDROID_LA.BR.1.1.2_RB1.05.00.02.031.018+PATCH[ES]_msm8916_32_refs/tags/AU_LINUX_ANDROID_LA.BR.1.1.2_RB1.05.00.02.031.018__release_ENGG (I856e09677e) 
OpenGL ES Shader Compiler Version: E031.25.03.02 
Build Date: 04/06/15 Mon 
Local Branch: 
Remote Branch: refs/tags/AU_LINUX_ANDROID_LA.BR.1.1.2_RB1.05.00.02.031.018 
Local Patches: 112c106f3772623daa7b4181c6cf23491044ead1 Revert "Disable ASTC on A405" 
58a118cb818fdc906095a49a90977c15f9d3b223 Remove ASTC 
08-24 09:42:43.138 8935-8951/com.example.dawid.camerabezpodgladu I/OpenGLRenderer﹕ Initialized EGL, version 1.4 
08-24 09:42:43.158 8935-8951/com.example.dawid.camerabezpodgladu D/OpenGLRenderer﹕ Get maximum texture size. GL_MAX_TEXTURE_SIZE is 4096 
08-24 09:42:43.158 8935-8951/com.example.dawid.camerabezpodgladu D/OpenGLRenderer﹕ Enabling debug mode 0 
08-24 09:42:43.258 8935-8935/com.example.dawid.camerabezpodgladu I/Timeline﹕ Timeline: Activity_idle id: [email protected] time:4110726 
08-24 09:42:44.648 8935-8935/com.example.dawid.camerabezpodgladu D/ViewRootImpl﹕ ViewPostImeInputStage ACTION_DOWN 
08-24 09:42:45.678 8935-8935/com.example.dawid.camerabezpodgladu I/Choreographer﹕ Skipped 34 frames! The application may be doing too much work on its main thread. 
08-24 09:43:45.138 8935-8935/com.example.dawid.camerabezpodgladu W/CameraBase﹕ An error occurred while connecting to camera: 0 
08-24 09:43:45.498 8935-8935/com.example.dawid.camerabezpodgladu D/AndroidRuntime﹕ Shutting down VM 
08-24 09:43:45.498 8935-8935/com.example.dawid.camerabezpodgladu E/AndroidRuntime﹕ FATAL EXCEPTION: main 
Process: com.example.dawid.camerabezpodgladu, PID: 8935 
java.lang.RuntimeException: startPreview failed 
     at android.hardware.Camera.startPreview(Native Method) 
     at com.example.dawid.camerabezpodgladu.CameraPreview.surfaceCreated(CameraPreview.java:31) 
     at android.view.SurfaceView.updateWindow(SurfaceView.java:682) 
     at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:200) 
     at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:921) 
     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2226) 
     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1239) 
     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6752) 
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:777) 
     at android.view.Choreographer.doCallbacks(Choreographer.java:590) 
     at android.view.Choreographer.doFrame(Choreographer.java:560) 
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:763) 
     at android.os.Handler.handleCallback(Handler.java:739) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:145) 
     at android.app.ActivityThread.main(ActivityThread.java:6145) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:372) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194) 
08-24 09:43:48.818 8935-8935/com.example.dawid.camerabezpodgladu I/Process﹕ Sending signal. PID: 8935 SIG: 9 

甚至有一次法takePicture不叫。错误是从糟糕的摄像头获取并在一分钟后重新打开(下一个处理程序操作)。

我将是一个连尖 的Dawid

回答

0

那么大卫非常感谢,你要1个秘诀?我正在研究一个类似的问题,这可能会让你走得更远一些......我目前被卡住的地方。

我可以在不使用预览的情况下拍摄照片,如下所示。

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    cameraHandler = new CameraHandler(); 
    tryThis(); 
} 

private void tryThis(){ 
    cameraHandler.takeAPic(); 
} 

和类是: 公共类CameraHandler实现Camera.PictureCallback { 民营相机mCamera;

public CameraHandler(){ } 

    public void takeAPic(){ 
    try{ 
     if (mCamera == null){ 
      mCamera = Camera.open(); 
      mCamera.enableShutterSound(false); 

      try { 
       mCamera.setPreviewTexture(new SurfaceTexture(10)); 
      } 
      catch (IOException e1) {    } 
     } 
     mCamera.startPreview(); 
     mCamera.takePicture(null, null, this); 
    } 
    catch (Exception ex){  } 
} 

    @Override 
    public void onPictureTaken(byte[] data, Camera camera) { 
     File pictureFile = getOutputMediaFile(); 
     if (pictureFile == null) { 
      return; 
     } 
     try { 
      FileOutputStream fos = new FileOutputStream(pictureFile); 
      fos.write(data); 
      fos.close(); 
     } 
     catch (FileNotFoundException e) {   } 
     catch (IOException e) {   } 
    } 

我运行到现在的问题是,我将在下面的“takePicture”任何代码不会导致“onPictureTaken”被调用。

但是,这至少可以让你到一个可以在没有预览的情况下拍照的地方。也许你可以弄清楚如何进行多次调用拍摄图片

+0

忽略此示例与上述一个解决了上述问题 – jdosser

1

终于想出了如何设置手机拍摄定时图片而不显示任何屏幕。 我遇到过两个主要问题。首先,我想把照片不显示在屏幕上。沿着这些线条,我找到了一个他们用过的例子: mCamera.setPreviewTexture(new SurfaceTexture(10));使用此预览方法时屏幕上不显示任何内容。看起来需要某种预览。另一种方法是将预览设置为1个像素。这种方法有网上的例子似乎工作,但我没有尝试它。

第二个也是更大的问题与'onPictureTaken'方法有关。这个方法在'takePicture'调用之后处理你的图片。这是第一个答案(上图)让我沮丧的地方。 似乎无论我使用什么循环方法,或者在代码中调用'takePicture'的位置,所有'onPictureTaken'方法都会排队,然后一次又一次地调用'takePicture'调用方的父级结束。

尽管由onPictureTaken处理的图片数据的时间序列是正确的,但我可以看到有数百张图片存储并正在等待处理可能会导致问题,并且需要在图片上处理并存储之前下一张照片被拍摄。

沿着这些路线,我偶然发现了AlarmManager,并将它与BroadcastReceiver和Future类结合起来解决了这个问题。

我所做的是设置alarmManger以设定的时间或时间频率关闭。 BroadcaseReceiver捕获此呼叫&依次调用一个方法,该方法创建一个线程,在该线程中,“Future”对象使呼叫进行拍照。

'未来'的对象很好,因为它会等待物理相机拍摄照片(takePicture)然后处理它(onPictureTaken)。这一切都发生在一个线程中,然后终止。所以不需要对图片进行处理和每个图片序列的排队处理。

代码包含在下面。请注意,一些默认的“覆盖”已省略以节省空间。此外,可见屏幕基本上是一个捕获点击事件的按钮...非常基本。主动式: 包myTest.com.test;

import android.app.Activity; 
import android.app.AlarmManager; 
import android.app.PendingIntent; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.os.SystemClock; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.view.View; 
import android.widget.TextView; 
import android.widget.Toast; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 

public class MainActivity extends Activity { 
CameraHandler cameraHandler; 
public BroadcastReceiver br; 
public PendingIntent pi; 
public AlarmManager am; 

final static private long LOOPTIME = 20000; 
private static final ExecutorService threadpool = Executors.newFixedThreadPool(3); 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    setup(); 
} 

private void setup() { 
    try{ 
     cameraHandler = new CameraHandler(); 
     br = new BroadcastReceiver() { 
      @Override 
      public void onReceive(Context c, Intent i) { 
       //Toast.makeText(c, "Taking a pic!", Toast.LENGTH_LONG).show(); 
       TryAThread(); 
      } 
     }; 
     registerReceiver(br, new IntentFilter("com.timedActivity.activity")); 
     pi = PendingIntent.getBroadcast(this, 0, new Intent("com.timedActivity.activity"), 0); 
     am = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE)); 
    } 
    catch (Exception e){  } 
} 

private void TryAThread() { 
    try{ 
     CameraCaller cameraCaller = new CameraCaller(cameraHandler); 
     Future future = threadpool.submit(cameraCaller); 

     while (!future.isDone()) { 
      try { 
       Thread.sleep(5000); 
      } catch (Exception ex) { } 
     } 
    } 
    catch (Exception e){  } 
} 

@Override 
protected void onDestroy() { 
    am.cancel(pi); 
    unregisterReceiver(br); 
    super.onDestroy(); 
} 

public void onClickListener(View view){ 
    try{ 
     am.setRepeating(am.ELAPSED_REALTIME,SystemClock.elapsedRealtime(), LOOPTIME, pi); 
    } 
    catch (Exception e){  } 
} 

}

CameraCaller.java :.

package myTest.com.test; 
import java.util.concurrent.Callable; 

public class CameraCaller implements Callable { 
private CameraHandler cameraHandler; 
public CameraCaller(CameraHandler ch){ 
    cameraHandler = ch; 
} 

@Override 
public Object call() throws Exception { 
    cameraHandler.takeAPic(); 
    return true; 
} 

}

CameraHandler.java :.

package myTest.com.test; 

import android.graphics.SurfaceTexture; 
import android.hardware.Camera; 
import android.os.Environment; 
import android.util.Log; 
import junit.runner.Version; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

public class CameraHandler implements Camera.PictureCallback{ 
private Camera mCamera; 
public CameraHandler(){ 
} 

    public Boolean takeAPic(){ 
    try{ 
     if (mCamera == null){ 
      mCamera = Camera.open(); 
      mCamera.enableShutterSound(false); 

      try { 
       mCamera.setPreviewTexture(new SurfaceTexture(10)); 
      } 
      catch (IOException e1) {Log.e(Version.id(), e1.getMessage()); 
      } 
     } 
     mCamera.startPreview(); 
     mCamera.takePicture(null, null, this); 
    } 
    catch (Exception ex){  } 
     return true; 
} 

    @Override 
    public void onPictureTaken(byte[] data, Camera camera) { 
     File pictureFile = getOutputMediaFile(); 
     if (pictureFile == null) { 
      return; 
     } 
     try { 
      FileOutputStream fos = new FileOutputStream(pictureFile); 
      fos.write(data); 
      fos.close(); 
     } catch (FileNotFoundException e) { 

     } catch (IOException e) {   } 
     try { 
      Thread.sleep(2000); 
     }catch (Exception ex){} 
    } 

public static File getOutputMediaFile() { 
    File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); 
    File mediaStorageDir = new File(file, "MyCameraApp"); 
    if (!mediaStorageDir.exists()) { 
     if (!mediaStorageDir.mkdirs()) { 
      Log.d("MyCameraApp", "failed to create directory"); 
      return null; 
     } 
    } 
    // Create a media file name 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    File mediaFile; 
    mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); 
    return mediaFile; 
} 

}