大家好我有一个应用程序,它在一个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();
}
}
答案 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
}
});