package cws.AppProject;
import android.app.*;
import android.os.*;
import android.view.*;
public class MainStart extends Activity {
//Painting vw = new Painting(this);
/** A handle to the View in which the game is running. */
@Override
public void onCreate(Bundle savedInstanceState) {
//전체화면
requestWindowFeature(Window.FEATURE_NO_TITLE); //타이틀화면 제거, 상태바 제거
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
// vw = new Painting(this);
//LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//View v = (View) inflater.inflate(R.layout.myview,null);
//setContentView(v);
setContentView(R.layout.myview);
}
// 메뉴키의 메뉴 구현
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
menu.add(0,1,0,"Option");
menu.add(0,2,0,"Exit");
return super.onCreateOptionsMenu(menu);
}
// 메뉴키의 메뉴 기능 구현
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case 1:
break;
case 2:
//이전 액티비티를 종료후에 app 프로세스 완전 종료
AppProject acty= (AppProject)AppProject.activity;
acty.finish();
System.exit(1);
break;
}
return super.onOptionsItemSelected(item);
}
} public class Painting extends View {
ArrayList<Vertex> arVertex = new ArrayList<Vertex>();
Paint mPaint;
//View m = new View(R.id.background);
public Painting(Context context) {
super(context);
// Paint 객체 미리 초기화
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(3);
mPaint.setAntiAlias(true);
}
public Painting(Context context, AttributeSet attrs) {
super(context,attrs);
// arVertex = new ArrayList<Vertex>();
}
@Override
public void onDraw(Canvas canvas) {
//try{
canvas.drawColor(Color.WHITE);
// 정점을 순회하면서 선분으로 잇는다.
for (int i=0;i<arVertex.size();i++) {
if (arVertex.get(i).Draw) {
canvas.drawLine(arVertex.get(i-1).x , arVertex.get(i-1).y, arVertex.get(i).x, arVertex.get(i).y, mPaint);
}
}
//}catch(Exception e){}//페이탈에러//발생/////--------------------------------------------------------------
}
// 손가락으로 터치를 하면서 그 좌표값을 저장
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
arVertex.add(new Vertex(event.getX(), event.getY(), false));
return true;
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
arVertex.add(new Vertex(event.getX(), event.getY(), true));
invalidate();
return true;
}
return false;
}
}
public class Vertex {
Vertex(float ax, float ay, boolean ad){
x = ax;
y = ay;
Draw = ad;
}
float x;
float y;
boolean Draw;
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical">
<cws.AppProject.Painting
android:id="@+id/background"
android:layout_height="400px"
android:layout_width="480px">
</cws.AppProject.Painting>
<LinearLayout android:layout_height="50px" android:id="@+id/linearLayout1" android:layout_gravity="bottom" android:orientation="horizontal" android:layout_width="480px">
<Button android:layout_height="wrap_content" android:text="검정" android:id="@+id/black" android:layout_weight="1" android:layout_width="wrap_content"></Button>
<Button android:layout_height="wrap_content" android:text="파랑" android:id="@+id/blue" android:layout_weight="1" android:layout_width="wrap_content"></Button>
<Button android:layout_height="wrap_content" android:text="노랑" android:id="@+id/yellow" android:layout_weight="1" android:layout_width="wrap_content"></Button>
<Button android:layout_height="wrap_content" android:text="빨강" android:id="@+id/red" android:layout_weight="1" android:layout_width="wrap_content"></Button>
<Button android:layout_height="wrap_content" android:text="지우기" android:id="@+id/clear" android:layout_weight="1" android:layout_width="wrap_content"></Button>
<Button android:id="@+id/button1" android:layout_height="wrap_content" android:text="저장" android:layout_width="80px"></Button>
</LinearLayout>
<LinearLayout android:gravity="bottom"
android:id="@+id/linearLayout2"
android:layout_marginTop="5px"
android:layout_weight="0"
android:layout_height="match_parent"
android:layout_width="fill_parent"
android:orientation="vertical">
<ListView android:layout_gravity="bottom"
android:layout_width="match_parent"
android:id="@+id/listView1"
android:layout_weight="0"
android:transcriptMode="alwaysScroll"
android:layout_height="200px">
</ListView>
<RelativeLayout android:id="@+id/relativeLayout1" android:layout_gravity="bottom" android:layout_width="match_parent" android:layout_weight="0" android:layout_height="70px">
<Button android:layout_alignParentRight="false" android:text="전송" android:layout_height="wrap_content" android:layout_toRightOf="@+id/ChatInput" android:id="@+id/goBtn" android:layout_width="match_parent" ></Button>
<EditText android:text="" android:layout_alignParentRight="false" android:id="@+id/ChatInput" android:layout_height="wrap_content" android:layout_width="400px"></EditText>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
안드로이드를 공부하고 있는 학생입니다.
자바는 충분히 한다고 생각하고 있구요.-_-;;
일단 제가 책에 있는 그리기 예제로 만들었을때는 성공하였습니다.
그런데 레이아웃의 한 부분에 출력하기 위해서 소스를 위와같이 수정후
다시 실행하니 점을 찍고 시작하는순간에 널포인터익셉션이 발생합니다.
에러 로그는 아래에 첨부하겠습니다.
디버그 창으로 계속 살펴본 결과
0~2번까지 x,y좌표가 입력이 되었지만 나머지는 null로 가득찼습니다.
이런 이유를 모르겠습니다.
좌표가 입력됬다는것은 제대로 읽어들인다는건데
왜 null로 갑자기 바뀌어 익셉션을 발생시키는지 이해가 안되군요;;
안드로이드가 함수만 끌어다 쓰면 된다는말은 전부 거짓말인가 봅니다 ㄷㄷ;
음..
레이아웃 설정에서부터 잘못된건지 아니면 소스중에 어느 부분이 잘못되었는지
디버그창으로 봤을땐 잘 모르겠습니다. 널포인터익셉션은 이때끔 코딩하면서 처음본거라서요;
궁금한거 못참는데 책이나 이래저래 봐도 정말 모르겟네요;
어디서 나는 오류인지는 알아도 실제 저곳에는 값이 잘 들어오니깐 처음부터 다시 코딩해야하는지;;ㅠ
에러 로그
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): FATAL EXCEPTION: main
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): java.lang.NullPointerException
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.graphics.Canvas.drawLine(Canvas.java:809)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at cws.AppProject.Painting.onDraw(Painting.java:42) <<<<<<<<<<<<<<<<<<<<<<<<<
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.View.draw(View.java:6740)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewGroup.drawChild(ViewGroup.java:1638)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.View.draw(View.java:6743)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.widget.FrameLayout.draw(FrameLayout.java:352)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewGroup.drawChild(ViewGroup.java:1640)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.View.draw(View.java:6743)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.widget.FrameLayout.draw(FrameLayout.java:352)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1842)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewRoot.draw(ViewRoot.java:1407)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewRoot.performTraversals(ViewRoot.java:1163)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.view.ViewRoot.handleMessage(ViewRoot.java:1727)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.os.Handler.dispatchMessage(Handler.java:99)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.os.Looper.loop(Looper.java:123)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at android.app.ActivityThread.main(ActivityThread.java:4627)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at java.lang.reflect.Method.invokeNative(Native Method)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at java.lang.reflect.Method.invoke(Method.java:521)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
05-25 15:53:25.735: ERROR/AndroidRuntime(3570): at dalvik.system.NativeStart.main(Native Method)
위에 올리신 소스 상으로는 33라인에서 나는 오류네요. 암튼 해당 하는 라인에 브래이크 걸고 무슨 변수가 널인지 확인 하면 되겠습니다.
답변을 한다면, 28라인이 무사히 넘어가고 drawLine메소드 까지 진행 된 것을 보면 canvas는 널이 아니고 arVertex는 get(i).Draw에서 무사히 넘어간 것을 보면 남은건 mPaint변수와 arVertex(i - 1) 뿐입니다.
두가지 상황 중 한가지니까 슬슬 감이 잡히죠?
자바를 충분히 하신다고 자부 하시면 이제 IDE와 디버깅을 그에 못지 않게 다루시면 될듯합니다.
Variables창에서 특정 연산을 하여 반환이 있는지, 무슨 값이 반환 되는지 확인 해보시고, 특정 메소드에서 반환 된걸 두세번 쓴다면 변수에 담아서 사용하기도 해보세요. 그러면 해당 변수가 널인지, 정상 값인지 확인이 수월 할 뿐 아니라 약간이나마 효율이 더 좋습니다.
암튼 결론은 mPaint가 널일듯 싶었지만 i가 0부터 시작 하는 for문의 특성 상 arVertex.get(i - 0)에서 널이 반환 되는것으로 보입니다.
C#에서는 OutOfRangeException이 발생 할텐데 약간 의외네요.
봉느님,iruis님 답변감사합니다.
디버그할때 33번라인의 mPaint값에 null을 봤었는데 이부분을 무심코 지나쳤네요..
public Painting(Context context, AttributeSet attrs) 쪽에 mPaint를 초기화 시켜주니 잘 작동합니다^^;;
iruis님 말처럼 디버깅 실력을 쌓아야할것 같습니다 ㅠ




mPaint가 null 이네요.
layout을 통해서 View 클래스를 생성할 경우
public Painting(Context context)
이쪽이 아니라
public Painting(Context context, AttributeSet attrs)
이쪽 생성자를 타게 될 겁니다.
아래쪽 생성자에서도 mPaint 초기화를 해주세요.