안녕하세요. 급하게 안드로이드 개발을 일주일내에 해야할일이 생겨서 이틀째 밤새 구글과 관련서적으로 맨땅에 헤딩하고 있습니다.

 

현재 상황은 이렇습니다.

 

1. 메인 액티비티에서 버튼을 눌러, 서브액티비티 호출

2. 서브액티비티에서는 시간계산을 하는 쓰레드가, 메인쓰레드에게 시간을 전달.

    메인쓰레드는 가속도 센서를 통해, 폰을 얼마나 흔들었는지 횟수를 계산.

3. 에뮬레이터든 단말기든, 뒤로가기 버튼을 누르면 앱이 터짐. (예외발생)

 

아무리 찾아봐도, 도무지 뭐가 틀린지도 모르겠고, 구글링 2시간을 넘게 하고있는데 마땅한 대안이 나오지 않아... 여기까지 방문하게 되었습니다.

 

초심자이고, 급한 마음에 벼락치기를 하여 기초가 매우 부실하니, 이 점 개발자 선배님들께서는 가엽게 여기셔서 조언 한마디 해주셨으면 합니다...

 

 

일단 로그캣이 띄워주신 오류는 이러합니다.

 

 

03-12 18:03:50.506: D/dalvikvm(834): GC_EXTERNAL_ALLOC freed 49K, 53% free 2548K/5379K, external 716K/1038K, paused 55ms
03-12 18:03:51.875: D/dalvikvm(834): GC_EXTERNAL_ALLOC freed 36K, 52% free 2621K/5379K, external 870K/1480K, paused 54ms
03-12 18:03:57.305: W/KeyCharacterMap(834): No keyboard for id 0
03-12 18:03:57.305: W/KeyCharacterMap(834): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
03-12 18:03:57.765: D/AndroidRuntime(834): Shutting down VM
03-12 18:03:57.765: W/dalvikvm(834): threadid=1: thread exiting with uncaught exception (group=0x40015560)
03-12 18:03:57.785: E/AndroidRuntime(834): FATAL EXCEPTION: main
03-12 18:03:57.785: E/AndroidRuntime(834): java.lang.RuntimeException: Unable to stop activity {project.shake/project.shake.GameStart}: java.lang.NullPointerException
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:2624)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:2690)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.ActivityThread.access$2100(ActivityThread.java:117)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:964)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.os.Handler.dispatchMessage(Handler.java:99)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.os.Looper.loop(Looper.java:123)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.ActivityThread.main(ActivityThread.java:3683)
03-12 18:03:57.785: E/AndroidRuntime(834):  at java.lang.reflect.Method.invokeNative(Native Method)
03-12 18:03:57.785: E/AndroidRuntime(834):  at java.lang.reflect.Method.invoke(Method.java:507)
03-12 18:03:57.785: E/AndroidRuntime(834):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
03-12 18:03:57.785: E/AndroidRuntime(834):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
03-12 18:03:57.785: E/AndroidRuntime(834):  at dalvik.system.NativeStart.main(Native Method)
03-12 18:03:57.785: E/AndroidRuntime(834): Caused by: java.lang.NullPointerException
03-12 18:03:57.785: E/AndroidRuntime(834):  at project.shake.GameStart.onStop(GameStart.java:87)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1170)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.Activity.performStop(Activity.java:3873)
03-12 18:03:57.785: E/AndroidRuntime(834):  at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:2619)
03-12 18:03:57.785: E/AndroidRuntime(834):  ... 11 more

 

다음은 메인 액티비티의 자바코드입니다.

 

  1. package project.shake;
  2.  
  3. import project.shake.*;
  4. import android.app.Activity;    // 게임 메인임...
  5. import android.os.Bundle;
  6. import android.app.*;
  7. import android.content.*;
  8. import android.os.*;
  9. import android.view.*;
  10. import android.widget.*;
  11.  
  12. public class GameMain extends Activity {
  13.     /** Called when the activity is first created. */
  14.     Toast tempToast = null;
  15.     @Override
  16.     public void onCreate(Bundle savedInstanceState) {
  17.         super.onCreate(savedInstanceState);
  18.         setContentView(R.layout.gamemain);
  19.     }
  20.    
  21.     public void mOnClick(View v)
  22.     {
  23.         Intent intent = new Intent(this, GameStart.class);
  24.         tempToast = Toast.makeText(this, "게임 시작", Toast.LENGTH_SHORT);
  25.         tempToast.show();
  26.         startActivity(intent);
  27.     }
  28. }

 

다음은 서브 액티비티의 자바코드입니다.

 

  1. package project.shake;
  2.  
  3. import project.shake.*;
  4. import android.app.Activity;   
  5. import android.os.*;
  6. import android.app.*;
  7. import android.content.*;
  8. import android.os.*;
  9. import android.view.*;
  10. import android.widget.*;
  11. import android.hardware.*;
  12.  
  13. public class GameStart extends Activity implements SensorEventListener
  14. {
  15.     float forceAccel = 0;   // 가속도의 벡터합(x + y + z)을 스칼라로 표현하는 변수.
  16.     float forceSumForScore = 0; // forceAccel 의 누적합을 구함. forceSumForScore += forceAccel;
  17.     long lastTime;
  18.    
  19.     // 가속도 변화율 구하는 변수
  20.     float lastX = 0;
  21.     float lastY = 0;
  22.     float lastZ = 0;
  23.     float x, y, z;
  24.    
  25.     // 게임의 논리를 구성하는 변수들
  26.     static boolean viveOnOff = true;        // 디폴트 바이브레이션 : on
  27.     static final int SHAKE_THRESHOLD = 800;
  28.     static int shakeCount = 0;              // 흔든 횟수. 타 클래스에서도 인스턴스 없이 참조하도록 static
  29.    
  30.     // 가속도 센서를 가져오는 센서매니저, 센서 인스턴스, 바이브레이터 인스턴스
  31.     SensorManager sm = null;
  32.     Sensor accel = null;
  33.     Vibrator mVib;
  34.    
  35.     // 디버깅용 토스트, 스트링, 기타 등등 ...
  36.     Toast tempToast = null;
  37.     String temp;
  38.     TimeThread timeThread;  // 시간재는 스레딩
  39.     TextView mBackText;     // 디버깅 텍스트뷰
  40.    
  41.     //Intent intent = new Intent(this, GameMain.class);
  42.  
  43.     /** Called when the activity is first created. */
  44.    
  45.     public void onAccuracyChanged(Sensor arg0, int arg1) {  }
  46.    
  47.     // 실험용 쓰레드가 초단위로 메세지를 보냄. ^ㅅ^
  48.     Handler mHandler = new Handler() {
  49.         public void handleMessage(Message msg)
  50.         {
  51.             mBackText.setText("경과시간 : " + msg.arg1);    // 텍스트뷰 쳐묵쳐묵
  52.         }
  53.     };
  54.    
  55.     @Override
  56.     public void onCreate(Bundle savedInstanceState)
  57.     {
  58.         super.onCreate(savedInstanceState);
  59.         sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
  60.         accel = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  61.         setContentView(R.layout.gamestart);
  62.         mVib = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);    // 바이브레이터 인스턴스 끌어씀
  63.        
  64.         mBackText = (TextView)findViewById(R.string.count);
  65.        
  66.         timeThread = new TimeThread(mHandler);
  67.         timeThread.setDaemon(true);
  68.         timeThread.start();
  69.     }
  70.    
  71.     public void onDestroy()
  72.     {
  73.         super.onDestroy();
  74.     }
  75.    
  76.     public void onStart()
  77.     {
  78.         super.onStart();
  79.        
  80.         if (accel != null)
  81.             sm.registerListener(this, accel, SensorManager.SENSOR_DELAY_GAME);
  82.     }
  83.  
  84.     public void onStop()
  85.     {
  86.         super.onStop();
  87.         tempToast.cancel();
  88.         if (sm != null)
  89.             sm.unregisterListener(this);
  90.     }
  91.  
  92.     // 가속도센서 감지 코드
  93.     // 가속도의 변화율에 따라, 점수와 흔들이 횟수를 올린다.
  94.     public void onSensorChanged(SensorEvent event)
  95.     {
  96.         if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
  97.         {
  98.             long currentTime = System.currentTimeMillis();
  99.             long gabOfTime = currentTime - lastTime;
  100.             x = event.values[0];
  101.             y = event.values[1];
  102.             z = event.values[2];
  103.            
  104.             if (gabOfTime > 100) // 0.1초동안 흔들면.
  105.             {
  106.                 lastTime = currentTime;  
  107.                
  108.                 forceAccel = Math.abs(x+y+z - lastX - lastY - lastZ)/gabOfTime * 10000;
  109.                 if(forceAccel > 5000)
  110.                 {
  111.                     mVib.vibrate(500);  // 0.5초 진동이 울린다! 임시
  112.                     ++shakeCount;   // 흔든횟수도 증가.
  113.                     temp = String.valueOf(timeThread.currentGameTime);
  114.                     tempToast = Toast.makeText(this, temp, Toast.LENGTH_SHORT); // 임시용
  115.                     tempToast.show();   // 임시용 토스트 호출  
  116.                 }
  117.                
  118.                 lastX = x;
  119.                 lastY = y;
  120.                 lastZ = z;
  121.             }
  122.         }
  123.     }
  124.    
  125.     class TimeThread extends Thread
  126.     {
  127.         int limitTime = 10;                         // 게임의 제한시간.
  128.         int currentGameTime = 0;                    // 실제 카운팅되는 상대시간. 초단위로 계산되며,
  129.                                                 // if(currentGameTime == limitTime) 게임끗();
  130.         Handler mHandler;
  131.        
  132.         TimeThread(Handler handler)
  133.         {
  134.             mHandler = handler;
  135.         }
  136.        
  137.         public void run()
  138.         {
  139.             while(true)
  140.             {
  141.                 currentGameTime++;
  142.  
  143.                 Message msg = Message.obtain(mHandler, 0, currentGameTime, 0);
  144.                 mHandler.sendMessage(msg);
  145.  
  146.                 try
  147.                 {
  148.                     Thread.sleep(1000);
  149.                 }
  150.                
  151.                 catch(InterruptedException e)
  152.                 {
  153.                     e.printStackTrace();
  154.                 }
  155.             }
  156.         }
  157.     }
  158. }

 

요건 메인액티비티의 xml입니다.

 

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.    android:layout_width="fill_parent"
  4.    android:layout_height="fill_parent"
  5.    android:orientation="vertical"
  6.    android:background="@drawable/appmain" >
  7.  
  8.     <LinearLayout
  9.        android:layout_width="fill_parent"
  10.         android:layout_height="fill_parent"
  11.         android:orientation="vertical"
  12.         android:background="@drawable/appmain" >
  13.        
  14.         <Button
  15.             android:layout_width="wrap_content"
  16.             android:layout_height="wrap_content"
  17.             android:onClick="mOnClick"
  18.             android:text="게임시작"
  19.             />  
  20.                
  21.         </LinearLayout>
  22. </LinearLayout>

 

요건 서브액티비티의 xml입니다.

 

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.    android:layout_width="fill_parent"
  4.    android:layout_height="fill_parent"
  5.    android:orientation="vertical"
  6.    android:background="@drawable/appmain" >
  7.  
  8.     <LinearLayout
  9.        android:layout_width="fill_parent"
  10.         android:layout_height="fill_parent"
  11.         android:orientation="vertical"
  12.         android:background="@drawable/appgamecontinue" >
  13.        
  14.         <TextView  
  15.         android:id="@+string/count"
  16.         android:layout_width="wrap_content"
  17.         android:layout_height="wrap_content"
  18.         android:textSize="30sp"
  19.         android:text="경과시간 : "
  20.         android:textColor="#ff0000"
  21.         />
  22.                
  23.         </LinearLayout>
  24.    
  25.    
  26. </LinearLayout>

 

 

오동작을 하는 원인이라도 간단하게 귀띔해주시면 백방 찾아 고치려 노력하겠습니다.

 

선배님들의 지적/조언을 바라며 ... 다시 구글링 하러 가겠습니다.