I am trying to open a camera preview but I get an
FATAL EXCEPTION: AsyncTask #1 java.lang.RuntimeException: An error
occured while executing doInBackground()
Below is my code:
public class ScanActivity extends Activity implements SurfaceHolder.Callback, OnClickListener {
private SurfaceHolder surface_holder;
protected Camera camera;
protected boolean scanning;
private Animation laser_effect;
private Animation flash_effect;
public static final class id {
public static final int quit = 0;
public static final int found = 1;
public static final int nothing = 2;
public static final int error = 3;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan);
findViewById(R.id.capture_button).setOnClickListener(this);![enter image description here][1]
}
#Override
protected void onResume() {
super.onResume();
/* open camera if any, returns error otherwise */
camera = Camera.open();
if (camera == null) {
Intent error = new Intent();
error.putExtra("reason", "Camera Error");
setResult(id.error, error);
finish();
}
restartView();
surface_holder = ((SurfaceView) findViewById(R.id.surface_view)).getHolder();
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surface_holder.addCallback(this);
}
#Override
protected void onPause() {
this.scanning=false;
/* release camera */
camera.cancelAutoFocus();
camera.stopPreview();
camera.release();
super.onPause();
}
private void restartView() {
findViewById(R.id.freeze).setVisibility(View.GONE);
findViewById(R.id.loading).setVisibility(View.GONE);
findViewById(R.id.capture_button).setVisibility(View.VISIBLE);
findViewById(R.id.surface_view).setVisibility(View.VISIBLE);
findViewById(R.id.camera_loading).setVisibility(View.GONE);
}
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.capture_button:
scanning = true;
break;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// void implementation
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
findViewById(R.id.camera_loading).setVisibility(View.VISIBLE);
//we use an AsyncTask to avoid ugly lag when camera is loading...
new InitCamera().execute(holder);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// void implementation
}
private class InitCamera extends AsyncTask<SurfaceHolder, Void, Boolean> {
#Override
protected Boolean doInBackground(SurfaceHolder... holder) {
/* initialize camera parameters and start Preview */
Rect dim = holder[0].getSurfaceFrame();
int w = dim.width();
int h = dim.height();
Camera.Parameters params = camera.getParameters();
params.setPreviewSize(w, h);
camera.setParameters(params);
try {
camera.setPreviewDisplay(surface_holder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
return true;
}
#Override
protected void onPostExecute(Boolean a) {
findViewById(R.id.camera_loading).setVisibility(View.GONE);
}
}
}
Most likely, the problem comes from trying to manipulate the UI from a non-UI thread. Examining your stack trace would help confirm this theory. AFAIK, the work that you are doing in doInBackground() should be performed on the main application thread.
Related
I`m trying to create bar code reader for my app, and it works fine, but the problem is when I keep focusing on QR-Code, it continues to read and never stops!!!
How can I make this happen only once?
In this code, it continues to "Toast" until I close the app, and when I use Intent for for closing the current activity and open another activity, the activity opens several times!!!
Here is the code:
public class BarcodeCaptureActivity extends AppCompatActivity {
private SurfaceView camera_preview;
TextView text;
BarcodeDetector barcodeDetector;
CameraSource cameraSource;
final int requestCameraPermissionID = 1001;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_barcode_capture);
camera_preview = (SurfaceView) findViewById(R.id.camera_preview);
text = (TextView) findViewById(R.id.text);
barcodeDetector = new BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.QR_CODE).build();
cameraSource = new CameraSource.Builder(this, barcodeDetector).setRequestedPreviewSize(640, 480).build();
camera_preview.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(BarcodeCaptureActivity.this, new String[]{Manifest.permission.CAMERA},requestCameraPermissionID);
return;
}
try {
cameraSource.start(camera_preview.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> qrcode = detections.getDetectedItems();
if (qrcode.size() != 0){
text.post(new Runnable() {
#Override
public void run() {
Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);
text.setText(qrcode.valueAt(0).displayValue);
String title = text.getText().toString();
Toast.makeText(BarcodeCaptureActivity.this, "" + title, Toast.LENGTH_SHORT).show();
finish();
}
});
}
}
});
}
Thank for any help...
UPDATE
Problem solved with adding onDestroy and onPause methods...
#Override
protected void onPause() {
super.onPause();
cameraSource.stop();
}
#Override
protected void onDestroy() {
super.onDestroy();
cameraSource.stop();
}
How can Take picture from front camera in service without showing camera on screen.
I have service class
public class PhotoTakingService extends Service {
//Camera variables
//a surface holder
private SurfaceHolder sHolder;
//a variable to control the camera
private Camera mCamera;
//the camera parameters
private Parameters parameters;
boolean mPreviewRunning = false;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent,int startId) {
// TODO Auto-generated method stub
super.onStart(intent,startId);
mCamera = Camera.open();
SurfaceView sv = new SurfaceView(getBaseContext());
try {
Camera.Parameters p = mCamera.getParameters();
mCamera.setParameters(p);
mCamera.startPreview();
mCamera.takePicture(null,null,mPictureCallback);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Get a surface
sHolder = sv.getHolder();
//tells Android that this surface will have its data constantly replaced
sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData,Camera c) {
Log.e("Callback TAG","Here in jpeg Callback");
if (imageData != null) {
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream("/sdcard/car_final/Image.jpg");
outputStream.write(imageData);
// Removed the finish call you had here
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) try {
outputStream.close();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
}
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
and main activity. I want to call from main activity.
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = MainActivity.class.getSimpleName();
public static SurfaceView mSurfaceView;
public static SurfaceHolder mSurfaceHolder;
public static Camera mCamera;
public static boolean mPreviewRunning;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Button btnStart = (Button) findViewById(R.id.button1);
btnStart.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent(MainActivity.this, PhotoTakingService.class);
//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startService(intent);
}
});
/* Button btnStop = (Button) findViewById(R.id.StopService);
btnStop.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
stopService(new Intent(CameraRecorder.this, RecorderService.class));
}
});*/
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
When you are in background thread such as service use SurfaceTexture instead of SurfaceHolder. If you are looking for implementation here is a opensource app where I have implemented background video stream and UI video stream both.
I used this tutorial to create a SurfaceView for a game. The tutorial fixed the problems I had with handling the thread but now whenever I open the fragment it takes anywhere between 3 and 15 seconds for the screen to turn yellow.
I thought it might have something to with the code in the container activity but the only thing I changed is this fragment alone. The speed before the change was fine.
public class VirtualMapFragment extends Fragment {
private MapSurfaceView mapSurfaceView;
#Override
public void onResume() {
if (mapSurfaceView != null){
mapSurfaceView.surfaceRestart();
}
super.onResume();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(mapSurfaceView == null)
mapSurfaceView = new MapSurfaceView(getActivity());
return mapSurfaceView;
}
#Override
public void onPause() {
if (mapSurfaceView != null){
mapSurfaceView.surfaceDestroyed(mapSurfaceView.getHolder());
}
super.onPause();
}
private class MapSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceThread surfaceThread;
public MapSurfaceView(Context context) {
super(context);
setFocusable(true);
surfaceThread = new SurfaceThread(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
surfaceThread.restartSurface();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceThread.terminateSurface();
}
public void surfaceRestart(){
if (surfaceThread != null){
surfaceThread.restartSurface();
}
}
public void doDraw(Canvas canvas){
canvas.drawColor(Color.YELLOW);
}
#Override
public boolean onTouchEvent(MotionEvent event){
return false;
}
}
private class SurfaceThread implements Runnable {
private SurfaceHolder mSurfaceHolder;
private MapSurfaceView mMapSurfaceView;
private Canvas mCanvas;
volatile Thread thread;
public SurfaceThread(MapSurfaceView mapSurfaceView){
mSurfaceHolder = mapSurfaceView.getHolder();
mMapSurfaceView = mapSurfaceView;
mCanvas = new Canvas();
thread = new Thread(this);
thread.start();
}
public void terminateSurface(){
this.thread.interrupt();
}
public void restartSurface() {
if (thread.getState() == Thread.State.TERMINATED){
thread = new Thread(this);
thread.start(); // Start a new thread
}
}
public SurfaceHolder getSurfaceHolder() {
return mSurfaceHolder;
}
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
mCanvas = mSurfaceHolder.lockCanvas(null);
if (mCanvas == null){
mSurfaceHolder = mMapSurfaceView.getHolder();
} else {
synchronized (mSurfaceHolder) {
mapSurfaceView.doDraw(mCanvas);
}
}
} finally {
if (mCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
}
}
I have got a problem
When hitting the home button, my game thread class gets paused. But when re-entering the app and the onResume() method gets called, it should resume the game thread... everythin i get is a force close.
Here is my MainActivity:
public class MainActivity extends Activity {
private RelativeLayout relativeLayout;
private GameView gameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameView = new GameView(this, this);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout)findViewById(R.id.mainView);
relativeLayout.addView(gameView);
}
#Override
protected void onPause() {
super.onPause();
gameView.pause();
}
#Override
protected void onResume() {
super.onResume();
if(gameView.getGameThread() != null) {
if(gameView.getGameThread().isRunning == false) {
gameView.resume();
}
}
}
}
gameView is following class, a surfaceView getting rendered by GameThread:
public class GameView extends SurfaceView{
private GameThread gameThread;
public GameView(Context context, Activity activity) {
super(context);
gameThread = new GameThread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameThread.setRunning(true);
gameThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
});
}
public GameThread getGameThread() {
return gameThread;
}
public void update() {
}
public void pause() {
gameThread.pause();
}
public void resume() {
gameThread.resumeThread();
}
}
This is the GameThread class:
public class GameThread extends Thread{
private GameView view;
public boolean isRunning = false;
public GameThread(GameView view) {
this.view = view;
}
public void setRunning(boolean setRunning) {
isRunning = setRunning;
}
public void stopThread() {
isRunning = false;
}
public void run() {
while(isRunning) {
Canvas c = null;
view.update();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.draw(c);
}
}finally {
if(c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
}
}
public void startThread() {
isRunning = true;
}
public void pause() {
isRunning = false;
}
public void resumeThread() {
isRunning = true;
}
}
I removed the irrelevant parts of the code.
When re-entering the app the android.view.Choreographer class opens
Any ideas?
Actually you're not pausing your thread (to be strict, there's no such thing as pausing a thread). You're ending your thread.
When you call pause() you set the isRunning flag to false, that makes the thread exit the loop and the thread ends. When you set your 'isRunning' to true again, the thread won't restart.
Actually you can't reuse threads in java, you have to create a new one, because once the thread loop ends, it's dead.
I have a small application in which i implement a surface view.Now depending on some condition(time) i would like to change the screen to a different layout.How do i do this in the following code.
Sketch of what i am doing.
public class df extends Activity
{
public void onCreate(Bundle savedInstanceState) {
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
public Panel(Context context){
super(context);
}
public void onDraw(Canvas canvas) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}