我有一个问题要解决 - 我正在尝试一切,没有任何工作。 我正在编写一个应该每分钟拍照的应用程序(图片之间的时间段可能会更长,但这并不重要)并将其上传到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
答案 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)
我可以使用以下内容拍摄无需预览的照片。
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;被召唤。
然而,这至少可以让你到一个没有预览就可以拍照的地方。也许你可以弄清楚如何进行多次调用以拍摄照片