2011-06-10 74 views
0

我有一个应用程序在位图上放置一个效果。当用户滑动滑杆时,效应的失真水平增加/减少,然后重新绘制位图。我的自定义视图类称为TouchView,并且此类获取位图并调用处理图像的Filters类的方法。我有帮助实施asyncTask来加速处理,但无济于事。 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]

嗨,好,我改变了我的代码,你amendements并改变了我几行这样的观点是通过增加TouchView.this.invalidate()等关于更新我设置horizo​​ntalSlider在设置进度时仅检查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; 
    } 
} 
+0

看看这个:http://stackoverflow.com/questions/5765904/touch-release-在Android中的方法 - 你需要保存每个触摸的“进度”,但不要调用'listener.onProgressChanged(this,progress)'直到你看到ACTION_UP' – 2011-06-12 21:26:55

+0

@tanner感谢您的更新,更新了代码。它现在只发射一个异步,但仍然运行缓慢(可能是由于过滤器类) – turtleboy 2011-06-13 11:16:00

+0

@turtuleboy这是非常可能的。希望它至少比以前跑得快。我的DroidX上的图像处理速度相对较慢,而且它是那里更强大的手机之一。所以你可能会碰到一个硬件限制。我不能说可以对过滤进行的任何优化,但听起来您至少在​​正确的轨道上。 – 2011-06-13 12:47:49

回答

1

看起来,对于滑块中的每个值更改,都会创建MyTask并运行它。相反,可能执行得更好的一件事情是,只有在滑块已释放(停止移动)时才更新侦听器。它看起来像HorizontalSlider是一个自定义类,所以我不能说出那里正在发生的事情。

如果滑块从左向右移动,它可能在该移动过程中触发100次更新事件。那将是100个后台任务!

UPDATE

一种可能性是cancel()您的积极MyTask你产生另外一个之前。如果您采用该路线,则需要拨打onPostExecute中的isCancelled(),并且仅在任务为而非取消的情况下使视图无效。但是,如果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); 
    } 
} 
+0

嗨,这很有道理。如何取消onProgressChanged()中的AsyncTask,然后在setProgress中执行AsyncTask。这样,当滑动条移动时,只会有一个Asynctask运行? – turtleboy 2011-06-10 18:07:15

+0

@turtleboy查看我的更新 – 2011-06-10 18:20:37

+0

刚刚更新后。你会如何正确编码?谢谢 – turtleboy 2011-06-11 17:35:41