Приложение AsyncTask все еще работает медленно - PullRequest
0 голосов
/ 10 июня 2011

У меня есть приложение, которое накладывает эффект на растровое изображение. Когда пользователь перемещает ползунок, уровень искажения эффекта увеличивается / уменьшается, а затем растровое изображение перерисовывается. Мой пользовательский класс представления называется TouchView, и этот класс получает растровое изображение и вызывает метод из класса Filters, который обрабатывает изображение. Мне помогли реализовать asyncTask для ускорения обработки, но безрезультатно. Является ли AsyncTask реализован правильно. Спасибо Мэтт.

public class TouchView extends View{


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



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




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



     //.....code that gets the bitmap from camera and sdcard

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


      // instantiate the image processing class
      f = new Filters();





    }// end of touchView constructor


    public void findCirclePixels(){ 



        //set level of distortion
        float prog = (float)Progress/150000;

        // call processing method on bitmap
        bgr2 = f.barrel(bgr,prog);


        }// end of changePixel()





    }//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);

        }
    };

    private class MyTask extends AsyncTask<Void, Void, Void> {
          protected void onPreExecute() {

            }

            @Override
            protected Void doInBackground(Void... params) {
              TouchView.this.findCirclePixels();
              return null;

            }

            protected void onPostExecute(Void result) {                               
              TouchView.this.invalidate();
            }
        }




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


        canvas.drawBitmap(bgr2, 0, 0, null);




    }//end of onDraw




    protected void setProgress(int progress2) {
        this.Progress = progress2;
        new MyTask().execute();


    }




}

.

[обновление] Это то, что у меня есть сейчас. Приложение работает медленнее, к сожалению, сейчас. У вас есть еще идеи, которые я мог бы попробовать?

public class TouchView extends View{


    private File tempFile;
    private byte[] imageArray;
    private Bitmap bgr;
    private Bitmap bm;
    private Bitmap bgr2 = null;;
    private Paint pTouch;
    private int centreX = 1;
    private int centreY = 1;
    private int radius = 50;
    private int Progress = 1;
    private static final String TAG = "*********TouchView";
    private Filters f = null;
    private boolean AsyncRunning = false;
    private MyTask mt = null;



    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);
        bgr2 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());



      f = new Filters();




    }// end of touchView constructor


    public void findCirclePixels(){ 




        float prog = (float)Progress/150000;
        bgr2 = f.barrel(bgr,prog);


        }// end of changePixel()









    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);

        }
    };

    private class MyTask extends AsyncTask<Void, Void, Void> {
          protected void onPreExecute() {

            }

            @Override
            protected Void doInBackground(Void... params) {
              TouchView.this.findCirclePixels();

              return null;

            }

            protected void onPostExecute(Void result) { 

                while(!isCancelled()){
              TouchView.this.invalidate();
                }
                     mt.cancel(true);
            }
        }




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


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



    }//end of onDraw




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


        mt = new MyTask();
        mt.execute();
        AsyncRunning = true;


    }




}

.

[обновление 2]

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ProgressBar;

public class HorizontalSlider extends ProgressBar {



    private OnProgressChangeListener listener;

    private static int padding = 2;

    public interface OnProgressChangeListener {
        void onProgressChanged(View v, int progress);
    }

    /*
    public HorizontalSlider(Context context, AttributeSet attrs,

                            Map inflateParams, int defStyle) {

                    super(context, attrs, inflateParams, defStyle);

            }



            public HorizontalSlider(Context context, AttributeSet attrs,

                            Map inflateParams) {

                    super(context, attrs, inflateParams, android.R.attr.progressBarStyleHorizontal);
}*/
    public HorizontalSlider(Context context) {
        super(context);

    }
    public HorizontalSlider(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }


    public void setOnProgressChangeListener(OnProgressChangeListener l) {
        listener = l;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();

        if (action == MotionEvent.ACTION_DOWN
                || action == MotionEvent.ACTION_MOVE) {
            float x_mouse = event.getX() - padding;
            float width = getWidth() - 2*padding;
            int progress = Math.round((float) getMax() * (x_mouse / width));

            if (progress < 0)
                progress = 0;

            this.setProgress(progress);

            if (listener != null)
                listener.onProgressChanged(this, progress);

        }

        return true;
    }
}

.

[обновление 3]

Привет, хорошо, я изменил свой код на ваши изменения и изменил пару строк, чтобы обновить представление, добавив TouchView.this.invalidate () и т. Д. Что касается горизонтального слайдера, я установил его для проверки только ACTION_UP при настройке прогресса. Таким образом, пользователь может перемещать ползунок, но представление становится недействительным только тогда, когда пользователь отпускает ползунок. Я надеялся, что растровое изображение будет обновляться в режиме реального времени при перемещении панели, но класс обработки изображений «Фильтры» занимает около 20 секунд, чтобы обработать растровое изображение, что не годится. я думаю, что мне нужно работать над последним, так как я уверен, что вы сможете обрабатывать растровые изображения быстрее, чем это! :). Если это так быстро, как может работать AsyncTask, тогда мне может понадобиться сначала нарисовать растровое изображение камеры без искажений, а затем создать другое наложение растрового изображения, в котором присутствует только эффект окружности. таким образом, код фильтра может иметь только 1/3 пикселей для цикла? Я опубликую код, чтобы убедиться, что вы предлагаете его.

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import com.tecmark.HorizontalSlider.OnProgressChangeListener;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.PorterDuff.Mode;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class TouchView extends View{


    private File tempFile;
    private byte[] imageArray;
    private Bitmap bgr;
    private Bitmap bm;
    private Bitmap bgr2 = null;;
    private Paint pTouch;
    private int centreX = 1;
    private int centreY = 1;
    private int radius = 50;
    private int Progress = 1;
    private static final String TAG = "*********TouchView";
    private Filters f = null;
    private boolean AsyncRunning = false;
    private MyTask mt = null;



    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);
        bgr2 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());



       f = new Filters();


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


    }// end of touchView constructor


    public void findCirclePixels(){ 




        float prog = (float)Progress/150000;
        bgr2 = f.barrel(bgr,prog);


        }// end of changePixel()







    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);

            //TouchView.this.Progress = progress;

              if (mt != null) {
                mt.cancel(true);
              }

              mt = new MyTask();
              mt.execute();


        }
    };

    private class MyTask extends AsyncTask<Void, Void, Void> {
          protected void onPreExecute() {
            //  Log.e(TAG, "***********in PREEXECUTE");
            }

            @Override
            protected Void doInBackground(Void... params) {
            //  Log.e(TAG, "***********in DOINBACKGROUND");
                if(!mt.isCancelled()){
            //  Log.e(TAG, "***********in doInBackgroud about to call fcp()");
            //  Log.e(TAG, "***********in doinbackground asyncStatus = "+mt.getStatus());
              TouchView.this.findCirclePixels();
              Log.e(TAG, "***********in doinbackground fcp() called!!!!");
                }

              return null;

            }

            protected void onPostExecute(Void result) { 
            //  Log.e(TAG, "***********in POSTEXECUTE");
                if(!isCancelled()){
           // Log.e(TAG, "***********in postExecute task not canclled and about to invalidate");
          //  Log.e(TAG, "***********in postexecute asyncStatus = "+mt.getStatus());
              TouchView.this.invalidate();
          //    Log.e(TAG, "***********in postexecute  invalidate() called!!!!");
           //   Log.e(TAG, "***********in postexecute asyncStatus = "+mt.getStatus());
                }


            }



        }// end of mytask




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


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



    }//end of onDraw




    protected void setProgress(int progress2) {
        //Log.e(TAG, "***********in SETPROGRESS");
        this.Progress = progress2;

        //Log.e(TAG, "***********in setprogress progress = "+Progress);

        //Log.e(TAG, "***********in setProgress about to create mytask ");
        mt = new MyTask();
        //Log.e(TAG, "***********in setprogress about to execute mytask");
        //Log.e(TAG, "***********in setprogress asyncStatus = "+mt.getStatus());
        mt.execute();
    //  Log.e(TAG, "***********in setprogress asyncStatus = "+mt.getStatus());
    //  Log.e(TAG, "***********in setprogress mytask executed!!!!! ");



    }




}

.

@Override
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();

        if (action == MotionEvent.ACTION_UP
                /*|| action == MotionEvent.ACTION_MOVE*/) {
            float x_mouse = event.getX() - padding;
            float width = getWidth() - 2*padding;

             int progress = Math.round((float) getMax() * (x_mouse / width));

            if (progress < 0)
                progress = 0;

            this.setProgress(progress);

            if (listener != null)
                listener.onProgressChanged(this, progress);
        }


        return true;
    }
}

1 Ответ

1 голос
/ 10 июня 2011

Похоже, что для каждого изменения значения в вашем ползунке вы создаете MyTask и запускаете его. Вместо этого, одна вещь, которая может работать лучше, - это обновлять слушателя только тогда, когда ползунок был отпущен (перестал двигаться). Похоже, HorizontalSlider - это пользовательский класс, поэтому я не могу говорить о том, что там происходит.

Если ползунок перемещается слева направо, он может вызвать события обновления 100 раз во время этого перемещения. Это было бы 100 фоновых задач!

UPDATE

Одной из возможностей будет cancel() ваш активный MyTask, прежде чем вы создадите другую. Если вы выберете этот маршрут, вам нужно позвонить по номеру isCancelled() в onPostExecute и аннулировать ваш просмотр только в том случае, если задача не отменена. Однако, если код в findCirclePixels() является узким местом, это не будет работать. Я предполагаю, что отмена активной задачи перед созданием новой НЕ решит вашу проблему.

Правильное кодирование (только создание MyTask при необходимости) все еще будет лучшим маршрутом. Учтите, что для каждого AsyncTask ОС должна создавать новый фоновый поток, который имеет свои собственные издержки. Не обманывайтесь небольшим количеством кода, который вы вставили в doInBackground().

ОБНОВЛЕНИЕ СНОВА

Я очистил ваш код и добавил комментарии для предложения:

public class TouchView extends View{

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

  public TouchView(Context context) {
    super(context);
  }

  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);
    bgr2 = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());
    f = new Filters();
  }

  public void findCirclePixels(){ 
    float prog = (float) Progress / 150000;
    bgr2 = f.barrel(bgr, prog);
  }

  public void initSlider(final HorizontalSlider slider) {
    slider.setOnProgressChangeListener(changeListener);
  }

  private OnProgressChangeListener changeListener = new OnProgressChangeListener() {
    @Override
    public void onProgressChanged(View v, int progress) {
      /*
      TODO: If there is a way to see if the slider is still being changed (control
      has not been released), then you should return and not continue with the
      creation of another task
      */

      this.Progress = progress2;

      if (mt != null) {
        mt.cancel();
      }

      mt = new MyTask();
      mt.execute();
    }
  };

  private class MyTask extends AsyncTask<Void, Void, Void> {
      protected void onPreExecute() {
      }

      @Override
      protected Void doInBackground(Void... params) {
        // This check is not necessary if coded properly
        if (!isCancelled()) {
          TouchView.this.findCirclePixels();
        }
        return null;
      }

      protected void onPostExecute(Void result) { 
        // This check is not necessary if coded properly
        if (!isCancelled()) {
          TouchView.this.invalidate();
        }
      }
  }




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

    canvas.drawBitmap(bgr2, 0, 0, null);
    canvas.drawCircle(centreX, centreY, radius, pTouch);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...