Android - 每分钟用相机拍照

时间:2015-08-24 08:05:22

标签: android-camera handler

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

  

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: android.os.BinderProxy@3d659231 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

2 个答案:

答案 0 :(得分:1)

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

第二个也是更大的问题与&#39; onPictureTaken&#39;方法。此方法会在拍摄照片后处理您的照片。呼叫。这是第一个答案(上图)绊倒我的地方。 似乎无论我使用什么循环方法,或者在代码中的哪个地方调用“拍摄图片”。找到了,所有的&#39; onPictureTaken&#39;方法排队等候,一旦接下来的话,就会一个接一个地调用方法。来电者结束了。

尽管onPictureTaken处理的图片数据处于适当的时间顺序,但我可以看到存储了数百张照片并等待处理可能会导致问题,并且需要找到一种方法,在处理和存储照片之前拍下一张照片。

沿着这些方向,我偶然发现了AlarmManager并将其与BroadcastReceiver和Future类耦合以解决问题。

我所做的是将alarmManger设置为在设定的时间或时间频率下关闭。 BroadcaseReceiver捕获此呼叫&amp;反过来调用一个创建的方法 一个线索,其中一个未来&#39;对象打电话拍照。

&#39;未来&#39;对象很好,因为它会等待物理相机拍摄照片(takePicture)然后处理它(onPictureTaken)。这一切都发生在一个线程中,然后终止。因此,不需要对要处理的图片进行排队,并且每个图片序列都是单独处理的。

代码包含在下面。请注意,某些默认&#39;覆盖&#39;被遗漏以节省空间。此外,可见屏幕基本上是一个捕获点击事件的按钮......非常基本。 MainActivity.java:     包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;
}

}

答案 1 :(得分:0)

大卫,你想要1小费吗?我正在解决类似的问题,这可能会让你在未来的路上走得更远...到我目前所处的位置。

我可以使用以下内容拍摄无需预览的照片。

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

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

课程是: public class 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) {            }
    }

我遇到的问题是我在“拍摄照片”之后输入的任何代码。并没有导致'onPictureTaken&#39;被召唤。

然而,这至少可以让你到一个没有预览就可以拍照的地方。也许你可以弄清楚如何进行多次调用以拍摄照片