吐司推迟到绘图完成后。为什么?

时间:2012-05-04 16:23:48

标签: android android-layout

UPDATE 05/08/12 7:23 AM:
我尝试交换绘制/吐司,即将Draw放入主UI线程中的AsyncTask和Toast中,但仍然没有乐趣:行为没有变化。我放弃。但是,感谢大家的建议 -John

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

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

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

我创建了一个应用程序,它将位图组合并绘制到屏幕上。因为组合位图需要2-3秒,我想向用户显示Toast消息,如“刷新,请待机......”。我的问题是,即使我在 drawBitmap()之前调用Toast(),只要之后油漆完成,吐司才会显示。

我之前在Windows下看到过这样的行为,因为消息队列在长时间计算期间得到了备份,解决方案是定期在长时间计算期间明确地调度消息。但我无法弄清楚是否/如何在Android上执行此操作。也许是神秘的(对我来说)“Looper”???

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

任何建议非常赞赏 -John

//  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 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分: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();
}

答案 2 :(得分:0)

两者都在UI上播放,它们之间没有延迟,所以只有在两个结束后才能看到修改。

答案 3 :(得分:0)

我有类似的问题。就我而言,我正在加载谷歌地图。第一次加载Google地图时,由于api密钥的验证过程以及加载初始地图图像,会出现明显的延迟。这可能需要几秒钟的时间,并且不会显示吐司。一个简单的解决方案是将地图加载到AsyncTask或单独的Activity中,但 NOT 立即加载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)
    {
    }
  }
};