0

更新 05/08/12 上午 7:23:
我尝试交换 draw/toast,即将 Draw 放在 AsyncTask 中,将 Toast 放在主 UI 线程中,但仍然没有乐趣:行为没有变化。我放弃。但是,感谢大家的建议。
-约翰

=======================================

更新 05/04/12 下午 6:30:
我认为“单任务”问题可能是问题所在,并且工作线程可能会工作,但由于根据定义,两个线程都需要访问 UI(主线程),看起来对我来说,我仍然有争议。尽管如此,根据建议,我将吐司放在 AsyncTask 的 onProgressUpdate() 中,但正如我担心的那样,问题仍然存在。(我不想将渲染放在异步任务中,因为它是一个怪物,我更愿意将简单的吐司放在其他任务中)。所以,还是不开心。关于如何做到这一点的任何其他建议?

=======================================

我创建了一个应用程序,它可以在屏幕上组合和绘制位图。因为撰写位图需要 2-3 秒,所以我想向用户显示一条 Toast 消息,例如“正在刷新,请等待...”。我的问题是,即使我在drawBitmap( )之前调用 Toast(),直到绘制完成后,toast 才会出现。

我以前在 Windows 下看到过​​这样的行为,因为消息队列在长时间计算期间得到了备份,解决方案是在长时间计算期间定期显式发送消息。但我不知道是否/如何在 Android 上执行此操作。也许是神秘的(对我来说)“循环者”???

我已经包含了一个小而琐碎的应用程序来隔离/演示问题。

任何建议都非常感谢。
-约翰

//  PixmapTestMain.java

public class PixmapTestMain extends Activity {

public static View PixmapView;                  // pixmap view
public static Context Ctx;

// Create activity
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Ctx = this;
    PixmapView = findViewById( R.id.pixmap );
}

// Handle click
public void onClick(View v) {           // button view clicked
    PixmapView.invalidate();            // new pixmap
}

}  // end class PixmapTestMain

自定义视图:

//  PixmapView - my custom view

public class PixmapView extends View {

static final int Wide=1000,High=1000,Size=(Wide*High);
static int toggle;

// Construct a view to display pixmap
public PixmapView(Context ctx,AttributeSet attrs) {
    super(ctx, attrs);
}

// Handle onDraw callback
@Override
protected void onDraw( Canvas canvas) {
    int[] pixmap;
    Bitmap bm;

    super.onDraw(canvas);

    toast( "Refreshing..." );
    pixmap = createPixmap();
    bm = Bitmap.createBitmap( pixmap, Wide, High, Bitmap.Config.ARGB_8888 );
    canvas.drawBitmap( bm, 0, 0, null );
}

// Create a pixmap
int[] createPixmap()
{
    int i,color;
    int[] pm;
    double s;
    Random rand = new Random();

    pm = new int[Size];                     // allocate pixmap

    toggle++;
    if( (toggle&1)==0 ) color = 0xff0000ff; // red
    else                color = 0xffff0000; // blue

    for( i=0; i<Size; i++ ) {
        pm[i] = color;
        rand.nextLong();        // slow me down
    }

    return( pm );
}

// Flash a toast message
public void toast( String msg)
{
    if( PixmapTestMain.Ctx == null ) return;
    Toast.makeText( PixmapTestMain.Ctx, msg, 0 ).show();
    }
}

布局:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<Button
  android:text="Refresh"
  android:id="@+id/refresh"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:onClick="onClick"/>

<com.hyperdyne.PixmapTest.PixmapView
  android:id="@+id/pixmap"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"/>

</LinearLayout>
4

4 回答 4

1

您应该将长时间运行的任务从您的 UI 线程中移开,例如:

protected void onDraw( Canvas canvas) {
    int[] pixmap;
    Bitmap bm;

    super.onDraw(canvas);

    toast( "Refreshing..." );
    pixmap = createPixmap();
    bm = Bitmap.createBitmap( pixmap, Wide, High, Bitmap.Config.ARGB_8888 );
    canvas.drawBitmap( bm, 0, 0, null );
}

应该变成:

private class DrawAsyncTask extends AsyncTask<Void,Void,Bitmap[]> {
    int[] pixmap;
    Bitmap bm;

    protected Void doInBackground(Void... v) {
        pixmap = createPixmap();
        bm = Bitmap.createBitmap( pixmap, Wide, High, Bitmap.Config.ARGB_8888 );
        return bm;
    }

    protected void onPostExecute(Bitmap[] result) {
        canvas.drawBitmap( result[0], 0, 0, null );
    }
}

protected void onDraw( Canvas canvas) {
    super.onDraw(canvas);
    toast( "Refreshing..." );
    new DrawAsyncTask().execute();
}
于 2012-05-04T23:14:38.420 回答
1

您在与 Toast 消息相同的线程上调用画布刷新。由于重绘操作会阻塞 UI 线程直到它完成,所以在 UI 线程被解除阻塞之前无法呈现 toast 消息。如果将重绘操作移到工作线程中,它应该可以解决您的问题。

于 2012-05-04T19:12:14.060 回答
0

两者都在 UI 上没有延迟,因此只有在两者结束后才能看到修改。

于 2012-05-04T16:26:34.420 回答
0

我有一个类似的问题。就我而言,我正在加载谷歌地图。第一次加载谷歌地图时,由于您的 api 密钥的验证过程以及加载初始地图图像,会出现明显的延迟。这可能需要几秒钟的时间,并且不会显示 toast。一个简单的解决方案是在 AsyncTask 或单独的 Activity 中加载地图,但不要立即启动 AsyncTask 或 Activity,而是在延迟 1 秒后。首先你显示你的吐司,然后在延迟后启动你的进程:

Toast.makeText(context, "Please wait...", Toast.LENGTH_LONG).show();
Handler handler = new Handler(); handler.postDelayed(DoSomething, 1000);

private Runnable DoSomething = new Runnable()
{
  @Override
  public void run()
  {
    try
    {
      // Launch an AsyncTask here or some other activity to handle your long process.
    }
    catch (Exception ex)
    {
    }
  }
};
于 2013-01-04T15:56:14.843 回答