实现AsyncTask的技巧

时间:2011-05-17 11:24:13

标签: android view bitmap android-asynctask

大家好我有一个应用程序,它在一个bitmapa上放置一个圆圈,并用一个滑动条改变圆圈内像素的rgb值。我想使用asynctask加速改变像素的过程。我不知道从哪里开始。我已经在活动文件的底部注释掉了一些代码,因为这是我第一次参加它:)。任何人都可以指出我如何实现这一目标的正确方向。该活动调用自定义视图(touchview),据我所知,必须在UI线程上实例化asynctask。我正在考虑在onPreExecute()中初始化滑块等,但不确定如何将所有工作人员的东西放在doInBackground()中。任何帮助将不胜感激,谢谢马特。

public class Jjilapp extends Activity {


    private Button b1;

    private static final String TAG = "*********jjil";


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "***********inside oncreate about to set contentview = ");
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.touchview);
        final TouchView touchView = (TouchView)findViewById(R.id.touchview); 
        final HorizontalSlider slider = (HorizontalSlider)findViewById(R.id.slider); 

        touchView.initSlider(slider);


        b1 = (Button)findViewById(R.id.button1);
        b1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.e(TAG, "onClickButton1");

            }
        });



    }//end of oncreate

   /* private class UpdateCirclePixels extends AsyncTask<Integer,Integer,Integer>{

        @Override
        protected void onPreExecute(){
            final TouchView touchView = (TouchView)findViewById(R.id.touchview); 
            final HorizontalSlider slider = (HorizontalSlider)findViewById(R.id.slider); 

            touchView.initSlider(slider);

        }



        @Override
        protected Integer doInBackground(Integer... arg0) {
            // TODO Auto-generated method stub

            publishProgress(progress);
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... progress){


        }


    }//end of AsyncTask     */


}//end of jjilapp

public class TouchView extends View{


    private File tempFile;
    private byte[] imageArray;
    private Bitmap bgr;
    private Bitmap bm;
    private Paint pTouch;
    private int centreX = 1;
    private int centreY = 1;
    private int radius = 50;
    private int Progress;
    private static final String TAG = "*********TouchView";




    public TouchView(Context context) {
        super(context);
       // TouchView(context, null);
    }




    public TouchView(Context context, AttributeSet attr) {
        super(context,attr);




        tempFile = new File(Environment.getExternalStorageDirectory().
                getAbsolutePath() + "/"+"image.jpg");

        imageArray = new byte[(int)tempFile.length()];


     try{

            InputStream is = new FileInputStream(tempFile);
            BufferedInputStream bis = new BufferedInputStream(is);
            DataInputStream dis = new DataInputStream(bis);


            int i = 0;

            while (dis.available() > 0) {
            imageArray[i] = dis.readByte();
            i++;
            }

            dis.close();

       } catch (Exception e) {

               e.printStackTrace();
            }



        BitmapFactory.Options bfo = new BitmapFactory.Options();
        bfo.inSampleSize = 1;

        bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length, bfo);
        bgr = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());
        bgr = bm.copy(bm.getConfig(), true);



        pTouch = new Paint(Paint.ANTI_ALIAS_FLAG);         
        pTouch.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT)); 
        pTouch.setColor(Color.TRANSPARENT);
        pTouch.setStyle(Paint.Style.STROKE);


        //pTouch.setMaskFilter(new BlurMaskFilter(15, Blur.NORMAL));



    }// end of touchView constructor


    public void findCirclePixels(){ 



        for (int i=centreX-50; i < centreX+50; ++i) {
            for (int y=centreY-50; y <centreY+50 ; ++y) {

    if( Math.sqrt( Math.pow(i - centreX, 2) + ( Math.pow(y - centreY, 2) ) ) <= radius ){

                    bgr.setPixel(i,y,Color.rgb(Progress+50,Progress,Progress+100));
                }
            }
        }

        }// end of changePixel()




    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN: {

                centreX = (int) ev.getX();
                centreY = (int) ev.getY();
                findCirclePixels();
                invalidate();

                break;
            }

            case MotionEvent.ACTION_MOVE: {

                    centreX = (int) ev.getX();
                    centreY = (int) ev.getY();
                    findCirclePixels();
                    invalidate();
                    break;

            }           

            case MotionEvent.ACTION_UP: 

                break;

        }
        return true;
    }//end of onTouchEvent





    public void initSlider(final HorizontalSlider slider)
    {
        Log.e(TAG, "******setting up slider*********** ");
        slider.setOnProgressChangeListener(changeListener);
    }



    private OnProgressChangeListener changeListener = new OnProgressChangeListener() {


        @Override
        public void onProgressChanged(View v, int progress) {
            // TODO Auto-generated method stub

            setProgress(progress);
            Log.e(TAG, "***********progress = "+Progress);

        }
    };





    @Override
    public void onDraw(Canvas canvas){
        super.onDraw(canvas);


        canvas.drawBitmap(bgr, 0, 0, null);
        canvas.drawCircle(centreX, centreY, radius,pTouch);


    }//end of onDraw




    protected void setProgress(int progress2) {
        this.Progress = progress2;
        findCirclePixels();
        invalidate();

    }


}

2 个答案:

答案 0 :(得分:8)

作为runOnUiThread的替代方案,您可以使用AsyncTask,并使用publishProgress/onProgressUpdate机制触摸视图。 Google有pretty good post使用AsyncTask,包括在任务中运行哪些方法,以及哪些方法在UI线程中运行。在doInBackground中进行计算,并在有一定数量的数据提供给要渲染的UI时调用publishProgress。然后在onProgressUpdate函数中渲染该数据。请注意,这两个函数的参数都是非常随意的,您可以根据需要定义它们。

编辑:在重新阅读你的问题时,我想知道是否可以使用单独的线程,因为在进行计算时你正在从用户那里获取输入。滑块移动和渲染之间可能存在明显的滞后,尤其是在计算线程变得饥饿的情况下。如果计算足够强大以保证单独的线程,您可能需要考虑在计算期间抛出进度条,而不是通过使渲染滞后于滑块移动太远来混淆用户。或者,如果检测到更改并且当前渲染不完整,则必须在cancel计算线程中添加一些逻辑,然后使用新参数再次激活它。有关取消AsyncTasks的详细信息,请阅读AsyncTask的{​​{3}}的简介部分。

edit2:当我实现我的AsycTask时,我定义了一个包含我需要的所有元素的Object:Views,Cursors,Exceptions等,并将其用作来回传递的参数。我暗示与TouchViewData相同的概念,因为线程无法触及View。只需用你需要的数据打包它,让线程就疯了。

public class MyAsyncTask extends AsyncTask<TouchViewData, Object, void> {

    /*
     * These run on the UI thread, and can access the Views
     */
    protected void onProgressUpdate(Object... values) {
      // Here's where the magic happens! 
      //   Update your views, open dialogs, Toast the user, whatever!
    }

    protected void onPreExecute() {
      // Prep anything you need for the thread
    }

    protected void onPostExecute() {
      // Finalize any rendering or cleanup
    }

    protected void onCancelled() {
      // Got cancelled! Time to clean up
    }

    /*
     * This runs in a separate thread, and can not change the View at all
     */
    public void doInBackground(TouchViewData... params) {
      while(stillCalculating && ! isCancelled()) {
        // Do your calculations, then...
        publishProgress(...); // pass some data to the UI thread to render
      }
      return;
    }

}

在您的活动中:

MyAppTask calculator = new MyAppTask();
calculator.execute(touchViewInstanceData, someObject);

...

// if you need to:
calculator.cancel();

答案 1 :(得分:2)

AsyncTask易于使用:只需在doInBackground(...)中执行您的操作,它就会在单独的线程中运行。

但是,请注意,您无法触及该单独帖子中的观看次数,或者您将获得CalledFromWrongThreadException。只有创建视图层次结构的原始线程才能触及其视图。

但是,如果您确实需要触摸可以使用的视图:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        //do your stuff here
    }
});