【问题标题】:Android executes task sequentially or not?Android是否按顺序执行任务?
【发布时间】:2015-02-19 06:19:10
【问题描述】:

Android Studio 在我的项目中发现了一个非常有趣的行为。对不同活动的调用没有按顺序执行!

我正在构建一个项目,其中调用如下:

button.setOnClickListener()
{
    (1) call to cusom camera acivity
    (2) call to activity showing preview of latest captured image         
    (3) call to a doCrop() function
} 

但是执行时,实际的流程是:

    (1) call to the doCrop() function
    (2) call to activity showing preview of image captured
    (3) call to cusom camera acivity

自定义相机活动处理所有必要的SurfaceHolderSurfaceView 操作。

SurfaceView 布局创建和销毁需要更多时间并且android 切换到更简单的一项任务时,这种效果是否会发生?

即便如此,它也应该跳到preview activity 而不是doCrop() 调用。

这里发生了什么?请指点!

谢谢!

编辑:

命名为:

MainActivity - 主要活动

Preview - 创建相机实例

CameraPreview - 处理 SurfaceView 等

ImagePreview - 显示指定图片

Main activity代码:

photo.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                File temp = new File(//path to store image);
                imageUri=Uri.fromFile(temp);

                 Intent intent = new Intent(MainActivity.this,Preview.class);

                startActivity(intent);

               // Image Preview Activity
                Intent intent1=new Intent(MainActivity.this,ImagePreview.class);
                startActivity(intent1);

                //Crop function
                doCrop();

            }

        });

preview activity 代码:

public class Preview extends Activity {
    private static final String TAG = "CamTestActivity";
    CameraPreview preview;
    Button buttonClick;
    Camera camera;
    Activity act;
    Context ctx;
    Uri uri;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ctx = this;
        act = this;
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_preview);

        preview = new CameraPreview(this, (SurfaceView)findViewById(R.id.surfaceView));
        preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        ((FrameLayout) findViewById(R.id.layout)).addView(preview);
        preview.setKeepScreenOn(true);

        buttonClick = (Button) findViewById(R.id.btnCapture);

        buttonClick.setOnClickListener(new OnClickListener()
        {
            public void onClick(View v) {
                camera.takePicture(shutterCallback, rawCallback, pngCallback);
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        int numCams = Camera.getNumberOfCameras();
        if(numCams > 0){
            try{
                camera = Camera.open(0);
                camera.startPreview();
                preview.setCamera(camera);
            } catch (RuntimeException ex){
                Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
            }
        }
    }

    @Override
    protected void onPause() {
        if(camera != null) {
            camera.stopPreview();
            preview.setCamera(null);
            camera.release();
            camera = null;
        }
        super.onPause();
    }

    private void resetCam() {
        camera.startPreview();
        preview.setCamera(camera);
    }

    private void refreshGallery(File file) {
        Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        mediaScanIntent.setData(Uri.fromFile(file));
        sendBroadcast(mediaScanIntent);
    }

    ShutterCallback shutterCallback = new ShutterCallback() {
        public void onShutter() {

        }
    };

    PictureCallback rawCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {

        }
    };

    PictureCallback pngCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            new SaveImageTask().execute(data);
            resetCam();
            Log.d(TAG, "onPictureTaken - png");
        }
    };

    private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
        @Override
        protected Void doInBackground(byte[]... data) {
              // save the image
            }
            catch (Exception e) { e.printStackTrace();}

            return null;
        }
    }
}

CameraPreview代码:

class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
    private final String TAG = "Preview";

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Size mPreviewSize;
    List<Size> mSupportedPreviewSizes;
    Camera mCamera;

    CameraPreview(Context context, SurfaceView sv) {
        super(context);

        mSurfaceView = sv;

        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            requestLayout();

            // get Camera parameters
            Camera.Parameters params = mCamera.getParameters();

            List<String> focusModes = params.getSupportedFocusModes();
            if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
                // set the focus mode
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

                // set Camera parameters
                mCamera.setParameters(params);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                previewWidth = mPreviewSize.width;
                previewHeight = mPreviewSize.height;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight > height * previewWidth) {
                final int scaledChildWidth = previewWidth * height / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                        (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2,
                        width, (height + scaledChildHeight) / 2);
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }


    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;
        Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        if(mCamera != null) {
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            requestLayout();

            mCamera.setParameters(parameters);
            mCamera.startPreview();
        }
    }

}

【问题讨论】:

  • 尽可能在此处发布您的代码
  • @vaishnavee,请看我的回答,如果合适,请接受

标签: android android-activity call callstack


【解决方案1】:

我认为这更多是设计问题。 您真的应该同时打开多个活动吗?

当一个 Activity 启动时,它会被放在历史堆栈的顶部,这可能会让人产生它正在以相反方式发生的错觉。

但在我看到代码之前,我无法进一步评论。

更新:是的,设计问题。

这是它应该工作的方式:

  1. MainActivity 中的 Onclick 操作只能使用 startActivityForResult() 打开预览活动。
  2. 用户拍照,触发 setResult() 并关闭相机活动。
  3. 结果返回到 MainActivity,触发 onActivityResult()
  4. onActivityResult 中的代码启动 ImagePreview 活动。
  5. ImagePreview 中的 onCreate 函数触发 doCrop();

我建议您仔细阅读此处的 Android 文档: http://developer.android.com/guide/components/activities.html

Android 不如其他平台灵活(或更有帮助),因此您必须充分了解 API。

【讨论】:

  • 谢谢回复,是的,我的项目需要上面的流程。我已经用代码更新了帖子
  • 非常混乱,你应该只需要调用一次 startActivity 。你能解释一下你想要达到的目标吗?您需要运行相机活动,返回结果并显示拍摄的图像吗?
  • 我认为有人没有阅读文档 ;-) 请参阅上面的更新。
【解决方案2】:

Activity启动代码是异步的,如果同时启动多个Activity,像这样:

startActivity(intent1);
startActivity(intent2);
startActivity(intent3);

不保证它们会按顺序显示给用户,即按“启动顺序”。

这是预期的行为,您通常不应该这样做,因为它表明您的应用程序设计缺陷

【讨论】:

  • 感谢您的回复。那么我怎样才能达到所需的流量呢?
  • @micwallace 的回答很好地说明了如何实现它 - 创建一个流程,其中启动 Activity 以处理一个操作并将结果提供给另一个 Activity。一次一份工作
【解决方案3】:

所以你要做的是同时启动 3 个活动。这些都需要在onActivityResult() 中处理。但是一个用户不能同时访问 3 个活动。 所以修改你的流程。 应该是这样的

  1. 启动CameraActivity
  2. 在你的调用活动的onActivityResult() 中,你调用 do crop 并做你想做的事。

您需要重新审视您的工作流程,因为:

  1. 您没有启动 3 个活动。
  2. 您正在触发基于用户交互的事件,因此不应从您的代码中控制函数的顺序。

【讨论】:

  • 我尝试使用onResult() 启动相机活动,但它没有返回到父活动(MainActivity)。请看我的问题link
  • @vaishnavee 为什么你需要自定义相机活动?你也在那里做任何事情吗?你不能使用相机启动意图吗?
  • 我想在不同的设置下启动相机,比如不同的场景模式和亮度等。有了相机意图,我们就无法操纵这些设置,对吗?
【解决方案4】:

您的任务执行顺序错误,因为它们被异步调用。要按照您指定的顺序执行它们,请进行 同步 调用,这可以使用 startActivityForResult(intent, requestCode);

完成

【讨论】:

  • 感谢回复,请在此处查看我的问题link。我试图让相机活动返回但不能。
猜你喜欢
  • 2018-09-08
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多