Reputation: 1232
I've been doing a little learning from youtube about android custom views and all. In my attempt to do a Surface View (rather simple as described in this video).
I've done things pretty much in sync with what was shown in the video.
How ever I am receiving a null pointer exception in the surfaceHolder.getSurface() .
Here is my entire code :
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainActivity extends AppCompatActivity {
Ui ui;
Bitmap ball;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
ui = new Ui(this);
ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball);
setContentView(ui);
}
@Override
protected void onResume() {
super.onResume();
ui.resume();
}
@Override
protected void onPause() {
super.onPause();
ui.pause();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public class Ui extends SurfaceView implements Runnable {
private Thread thread;
private SurfaceHolder surfaceHolder;
boolean ok = false;
public Ui(Context context) {
super(context);
thread = null;
surfaceHolder = getHolder();
}
@Override
public void run() {
while (ok) {
if (!surfaceHolder.getSurface().isValid()) {
continue;
}
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawARGB(200, 150, 130, 120);
canvas.drawBitmap(ball, 0, 0, null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
ok = false;
while (true) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
thread = null;
}
public void resume() {
ok = true;
thread = new Thread(this);
thread.run();
}
}
}
This part of the code :
Some pointer to what I am doing wrong will be helpful!.
@Override
public void run() {
while (ok) {
if (!surfaceHolder.getSurface().isValid()) {
continue;
}
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawARGB(200, 150, 130, 120);
canvas.drawBitmap(ball, 0, 0, null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
The problem appears in this line :
if (!surfaceHolder.getSurface().isValid())
always returns false and the later part of the code is never executed.
Logcat :
06-25 15:23:46.211 2012-2012/com.pchakraverti.canvasapp D/AndroidRuntime﹕ Shutting down VM
06-25 15:23:46.211 2012-2012/com.pchakraverti.canvasapp W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xa62f8288)
06-25 15:23:46.211 2012-2012/com.pchakraverti.canvasapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to resume activity {com.pchakraverti.canvasapp/com.pchakraverti.canvasapp.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.pchakraverti.canvasapp.Ui.run(Ui.java:44)
at java.lang.Thread.run(Thread.java:856)
at com.pchakraverti.canvasapp.Ui.resume(Ui.java:66)
at com.pchakraverti.canvasapp.MainActivity.onPostResume(MainActivity.java:24)
at android.app.Activity.performResume(Activity.java:5095)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
06-25 15:23:46.227 2012-2015/com.pchakraverti.canvasapp D/dalvikvm﹕ GC_CONCURRENT freed 208K, 3% free 10919K/11207K, paused 12ms+0ms, total 15ms
06-25 15:25:15.043 2067-2067/com.pchakraverti.canvasapp D/dalvikvm﹕ Late-enabling CheckJNI
06-25 15:25:15.091 2067-2070/com.pchakraverti.canvasapp D/dalvikvm﹕ GC_CONCURRENT freed 98K, 3% free 11074K/11335K, paused 11ms+0ms, total 23ms
06-25 15:25:15.095 2067-2067/com.pchakraverti.canvasapp D/dalvikvm﹕ GC_FOR_ALLOC freed <1K, 3% free 11073K/11335K, paused 4ms, total 4ms
06-25 15:25:15.131 2067-2067/com.pchakraverti.canvasapp I/dalvikvm-heap﹕ Grow heap (frag case) to 11.887MB for 1048588-byte allocation
06-25 15:25:15.155 2067-2070/com.pchakraverti.canvasapp D/dalvikvm﹕ GC_CONCURRENT freed 0K, 3% free 12097K/12423K, paused 15ms+0ms, total 22ms
06-25 15:25:15.155 2067-2067/com.pchakraverti.canvasapp D/dalvikvm﹕ WAIT_FOR_CONCURRENT_GC blocked 0ms
06-25 15:25:15.163 2067-2067/com.pchakraverti.canvasapp I/dalvikvm﹕ Could not find method android.view.ViewGroup.onRtlPropertiesChanged, referenced from method android.support.v7.widget.Toolbar.onRtlPropertiesChanged
06-25 15:25:15.163 2067-2067/com.pchakraverti.canvasapp W/dalvikvm﹕ VFY: unable to resolve virtual method 13337: Landroid/view/ViewGroup;.onRtlPropertiesChanged (I)V
06-25 15:25:15.163 2067-2067/com.pchakraverti.canvasapp D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0007
06-25 15:25:15.163 2067-2067/com.pchakraverti.canvasapp I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.internal.widget.TintTypedArray.getChangingConfigurations
06-25 15:25:15.163 2067-2067/com.pchakraverti.canvasapp W/dalvikvm﹕ VFY: unable to resolve virtual method 408: Landroid/content/res/TypedArray;.getChangingConfigurations ()I
06-25 15:25:15.163 2067-2067/com.pchakraverti.canvasapp D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002
06-25 15:25:15.167 2067-2067/com.pchakraverti.canvasapp I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.internal.widget.TintTypedArray.getType
06-25 15:25:15.167 2067-2067/com.pchakraverti.canvasapp W/dalvikvm﹕ VFY: unable to resolve virtual method 430: Landroid/content/res/TypedArray;.getType (I)I
06-25 15:25:15.167 2067-2067/com.pchakraverti.canvasapp D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002
06-25 15:25:15.171 2067-2067/com.pchakraverti.canvasapp D/AndroidRuntime﹕ Shutting down VM
06-25 15:25:15.171 2067-2067/com.pchakraverti.canvasapp W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xa62f8288)
06-25 15:25:15.171 2067-2067/com.pchakraverti.canvasapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to resume activity {com.pchakraverti.canvasapp/com.pchakraverti.canvasapp.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.pchakraverti.canvasapp.Ui.run(Ui.java:45)
at java.lang.Thread.run(Thread.java:856)
at com.pchakraverti.canvasapp.Ui.resume(Ui.java:66)
at com.pchakraverti.canvasapp.MainActivity.onPostResume(MainActivity.java:24)
at android.app.Activity.performResume(Activity.java:5095)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2089)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
06-25 15:26:56.039 2120-2125/com.pchakraverti.canvasapp I/dalvikvm﹕ threadid=3: reacting to signal 3
Upvotes: 1
Views: 2920
Reputation: 52303
The SurfaceView has two parts, the Surface and the View. The Surface is created asynchronously, by the Window Manager, and you can't do anything with it until it's ready. You have to handle the SurfaceHolder.Callback methods to know when the Surface has been created and destroyed.
The SurfaceView lifecycle is not in lock step with the Activity life cycle, so you have to be a bit careful about allocating resources (like Camera) and starting / stopping threads. A discussion of the topic can be found in this appendix of the graphics architecture document. Various examples can be found in Grafika.
Please make sure that a SurfaceView is what you actually want. If you want a custom View, you should be working with View, not SurfaceView.
Upvotes: 1
Reputation: 331
please also look at this problem issued by myself, actually, it is very similar:
View.SurfaceView, why its member, mSurfaceHolder, returns null from getSurface()?
i also read the source code of SurfaceView.java in android sdk 22, but I noticed that member SurfaceView.mSurfaceHolder.getSurface() always returns null. That frastrates me!
Upvotes: 1