我正在编写一个应用程序并且我有一个自定义 View 。在这个自定义 View 中,我必须计算不确定数量的点的位置。点数取决于我从数据库中读取的内容(因此每个用户都不同)。 所以,我的问题是,我怎样才能很好地解决这个问题?该应用程序的步骤如下:
- Activity 开始
- 数据库查询
- 绘图
问题是当我打开 Activity 时调用了 onDraw()
方法,但我无法绘制任何东西,因为我必须等待数据库查询和计算点。在计算完成之前,我如何使用线程或者进度条之类的东西?我可以阻止应用程序在 Activity 开始时立即运行 onDraw()
方法吗?
感谢您的帮助。
edit1:所以这是代码(注意:我现在不想计算任何东西,出现错误是因为我尝试将 ProgressBar 的可见性设置为 true,没有这行它就可以工作):
public class MyView extends View {
private ProgressBar progressBar;
private boolean calculationsDone;
public MyView(Context context, AttributeSet attrs) {
super(context);
// TODO Auto-generated constructor stub
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
calculationsDone=false;
}
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
if(calculationsDone == true){
//draw stuff
progressBar.setVisibility(INVISIBLE);
}else{
Log.d("calcNotDone", "CALCULATION NOT DONE YET!");
progressBar.setVisibility(VISIBLE);
}
}
}
这里是错误:
03-31 20:45:44.131: E/AndroidRuntime(27445): FATAL EXCEPTION: main 03-31 20:45:44.131: E/AndroidRuntime(27445): java.lang.NullPointerException 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.example.test.MyView.onDraw(MyView.java:50) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14853) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13744) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14856) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13744) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13739) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13739) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14563) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.drawChild(ViewGroup.java:3316) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3153) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.draw(View.java:14856) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.widget.FrameLayout.draw(FrameLayout.java:467) 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2621) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13744) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.View.getDisplayList(View.java:13786) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1411) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1359) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.draw(ViewRootImpl.java:2672) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2538) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2154) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1249) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6364) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer.doCallbacks(Choreographer.java:591) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer.doFrame(Choreographer.java:561) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.os.Handler.handleCallback(Handler.java:730) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.os.Handler.dispatchMessage(Handler.java:92) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.os.Looper.loop(Looper.java:176) 03-31 20:45:44.131: E/AndroidRuntime(27445): at android.app.ActivityThread.main(ActivityThread.java:5419) 03-31 20:45:44.131: E/AndroidRuntime(27445): at java.lang.reflect.Method.invokeNative(Native Method) 03-31 20:45:44.131: E/AndroidRuntime(27445): at java.lang.reflect.Method.invoke(Method.java:525) 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) 03-31 20:45:44.131: E/AndroidRuntime(27445): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) 03-31 20:45:44.131: E/AndroidRuntime(27445): at dalvik.system.NativeStart.main(Native Method)
最佳答案
你应该研究一下 onDraw()
生命周期。
onDraw
在开始时被调用,然后每次有“something”要绘制时都会被调用。您如何告诉 View 它有“东西” 可以绘制?通过调用“invalidate
”。
所以在您的 onDraw
上,如果点未加载,一开始您什么都不做。
当您完成计算后,只需调用 invalidate()
,onDraw
稍后将被调用,异步。这时候,在您的 OnDraw
中,您会检测到您的计算已经准备就绪,所以然后就是您绘制这些东西的时候了。
种类:
boolean myCalculationsAreReady=false;
Paint mPaint=new Paint(); // to draw text "loading" ... (new edit). You have to call mPaint.setColor(Color.WHITE) or any color you want, the default would be Black.
public void onDraw(Canvas canvas) {
if (myCalculationsAreReady) {
drawMyStuff (canvas);
} else {
// You don't have your calculations yet , just ignore, or paint a message ...
drawDataNotReady(canvas);
}
}
private void drawMyStuff (Canvas c) {
// here you have your calculations available
// time to draw !
}
// to make this view totally independent, you can create yourself a progress indicator here.
// you can also put a standard progressbar at the parent level and notify the parent when
// to show / hide it. I like this approach, because it's more efficient (you save one view)
// but obviously you can use any fancy view you like over this one.
private void drawDataNotReady (Canvas c) {
c.drawText (0, c.getHeight() / 2, "Please wait while data is loading ...", mPaint);
}
private void do_my_heavy_calculations () {
// do all your calculations.
.
.
.
// when you are done:
myCalculationsAreReady=true;
invalidate(); // this will call onDraw
}
当您了解其工作原理后,如果您的计算量很大,您肯定希望将它们从 UI 线程中取出。您可以按照您的要求使用普通线程,但是调用“invalidate”的方式不同:
view.postInvalidate();
这用于使来自主 UI 线程(即您的线程)外部的 View 无效。
另请查看 AsyncTask
作为帮助编写异步线程的类。
关于android - 在 onDraw() 中使用线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22765947/