I'm having android surfaceView and in that I'm trying to add buttons to this. In the surfaceView canvas I draw something. And I have a thread class to keep drawing.
package com.androidsurfaceview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class androidsurfaceview extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonShowHide = (Button)findViewById(R.id.showhide);
final Button buttonDummy = (Button)findViewById(R.id.dummy);
buttonShowHide.setOnClickListener(
new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
if(buttonDummy.getVisibility()==View.VISIBLE){
buttonDummy.setVisibility(View.GONE);
}
else{
buttonDummy.setVisibility(View.VISIBLE);
}
}
}
);
The thread class
package com.androidsurfaceview;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MySurfaceThread extends Thread {
private SurfaceHolder myThreadSurfaceHolder;
private com.androidsurfaceview.test.MySurfaceView myThreadSurfaceView;
private boolean myThreadRun = false;
public MySurfaceThread(SurfaceHolder surfaceHolder, com.androidsurfaceview.test.MySurfaceView surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}
public void setRunning(boolean b) {
myThreadRun = b;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(myThreadRun){
Canvas c = null;
try{
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder){
myThreadSurfaceView.onDraw(c);
}
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
The surfaceView & the class for drawing
package com.androidsurfaceview;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class test extends Activity{
// ......
// I do a few things here... with this class test.
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private MySurfaceThread thread;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
int cx, cy, offx, offy;
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
getHolder().addCallback(this);
thread = new MySurfaceThread(getHolder(), this);
setFocusable(true); // make sure we get key events
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
cx = 0;
cy = 0;
offx = 10;
offy = 10;
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.setRunning(true);
thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
}
catch (InterruptedException e) {
}
}
}
////Just a simple graphic of moving circle.
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawRGB(0, 0, 0);
canvas.drawCircle(cx, cy, 3, paint);
cx += offx;
if (cx > getWidth() || (cx < 0)){
offx *= -1;
cx += offx;
}
cy += offy;
if (cy > getHeight() || (cy < 0)){
offy *= -1;
cy += offy;
}
}
}
}
Here is the main.xml
<?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:id="@+id/showhide"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Toggle The Another Button Show/Hide" />
<Button
android:id="@+id/dummy"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="a Button" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.androidsurfaceview.test.MySurfaceView
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
</LinearLayout>
PROBLEM: The above code works ONLY if I don't have the "MySurfaceView" as nested class. but with the outer class "test" I get the following error. If I remove the "class test" it works fine.
Error/Crash
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): FATAL EXCEPTION: main
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidsurfaceview/com.androidsurfaceview.androidsurfaceview}: **android.view.InflateException: Binary XML file line #20: Error inflating class com.androidsurfaceview.test.MySurfaceView**
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.os.Handler.dispatchMessage(Handler.java:99)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.os.Looper.loop(Looper.java:123)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.ActivityThread.main(ActivityThread.java:4627)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at java.lang.reflect.Method.invokeNative(Native Method)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at java.lang.reflect.Method.invoke(Method.java:521)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at dalvik.system.NativeStart.main(Native Method)
**04-29 11:43:18.977: ERROR/AndroidRuntime(21832): Caused by: android.view.InflateException: Binary XML file line #20: Error inflating class com.androidsurfaceview.test.MySurfaceView**
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:576)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.view.LayoutInflater.rInflate(LayoutInflater.java:621)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:200)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.Activity.setContentView(Activity.java:1647)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at com.androidsurfaceview.androidsurfaceview.onCreate(androidsurfaceview.java:13)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
Any help will be great ...I'm stuck with this.
First, you must declare your view as a static
type, to be able to be inflated it even when no instance of the holding class is available:
public static class MySurfaceView extends SurfaceView
implements SurfaceHolder.Callback
The line
<com.androidsurfaceview.test.MySurfaceView
in your layout xml suggests, that the MySurfaceView
class is inside the com.androidsurfaceview.test
package, and tries to inflate it from there, which is wrong.
In your layout you should follow the package.class$innerclass form of declaration.
BUT since the "$"
is illegal character, you cannot write
<com.androidsurfaceview.test$MySurfaceView
so you must specify your view in the layout xml as follows:
<view class="com.androidsurfaceview.test$MySurfaceView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
This way it will work.