советы по реализации AsyncTask - PullRequest
2 голосов
/ 17 мая 2011

Привет всем, у меня есть приложение, которое размещает круг на битмапе и с помощью ползунка изменяет значения rgb пикселей в круге. Я хотел бы использовать asynctask, чтобы ускорить процесс изменения пикселей. Я не уверен, с чего начать. Я прокомментировал некоторый код в нижней части файла активности, так как это мое первое посещение :). Может ли кто-нибудь указать мне в правильном направлении, как реализовать это. Действие вызывает пользовательское представление (touchview), так как я понимаю, что 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 ]

8 голосов
/ 17 мая 2011

В качестве альтернативы runOnUiThread вы можете использовать AsyncTask и использовать механизм publishProgress/onProgressUpdate для касания видов.У Google есть довольно хороший пост об использовании AsyncTask, включая сведения о том, какие методы запускаются в задаче, а какие - в потоке пользовательского интерфейса.Выполните вычисления в doInBackground и вызывайте publishProgress всякий раз, когда есть какие-то кванты данных, которые нужно передать в пользовательский интерфейс для рендеринга.Затем визуализируйте эти данные в функции onProgressUpdate.Обратите внимание, что параметры для обеих функций совершенно произвольны, и вы можете определить их по своему усмотрению.

edit: Перечитав ваш вопрос, я задаюсь вопросом, стоит ли использовать отдельный поток, так как выпринимаем данные от пользователя во время ваших вычислений.Вполне возможно, что между движением ползунка и рендерингом может быть значительная задержка, особенно если вычислительный поток истощается.Если вычисления достаточно интенсивные, чтобы оправдать отдельный поток, вы можете подумать о том, чтобы подбрасывать индикатор выполнения во время вычислений, а не вводить пользователя в заблуждение из-за слишком большой задержки рендеринга за его движением ползунка.Либо так, либо вам придется добавить некоторую логику в cancel поток вычислений, если изменение обнаружено и текущий рендер не завершен, а затем снова запустите его с новыми параметрами.Для получения дополнительной информации об отмене AsyncTasks прочитайте раздел (ы) введения в документации для AsyncTask.

edit2: когда я реализовал свой AsycTask, я определил объект, который содержалвсе элементы, которые мне нужны: представления, курсоры, исключения и т. д., и использовали его в качестве параметра для передачи туда и обратно.Я имею в виду ту же концепцию с TouchViewData, так как поток не может касаться представления.Просто соберите все данные, которые вам нужны, и пусть поток сходит с ума.

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();
2 голосов
/ 17 мая 2011

AsyncTask прост в использовании: просто выполните свои действия в doInBackground(...), и он будет выполняться в отдельном потоке.

Однако учтите, что вы не можете касаться представлений в этом отдельном потоке, иначе вы получите CalledFromWrongThreadException. Только оригинальный поток, создавший иерархию представлений, может касаться его представлений.

Однако, если вам действительно нужно прикоснуться к видам, которые вы можете использовать:

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