인텐트를 다루는 두 번째 시간이 돌아왔습니다. (와우!)
이번 강좌는 저도 인텐트를 쪼~까 공부하느라 뭔가 깔끔하지 못할 지도 모르겠네요(...)
그래도 최대한 자세하게 다뤄보도록 할테니! 걱정은 마시고!! 따라오시면 될겁니다. (아마도요...펑...)

지난 시간에는 다른 액티비티를 단순히 "호출"하는 것만 배웠습니다. 그런데, 실제 어플리케이션을 개발하다보면 액티비티를 호출하는 것은 어찌보면 당연한 것이고, 액티비티간에 데이터를 주고받아야 할 일이 생깁니다. 그럴 땐 어떻게 해야 할까요? => 바로, 이 때도 인텐트를 사용하면 됩니다(...)

인텐트는, 액티비티를 호출하는 수단 뿐 아니라 인텐트 자체에 액티비티간 주고받아야 할 정보들을 실어줄 수 있습니다. 예를 들자면 심부름꾼(???) 이라고 할까나요??

A라는 사람이 B에게 물건을 가져오라고 심부름꾼에게 시키면, 심부름꾼은 B에게 가서 물건을 받아 A에게 전달해주게 됩니다. 마찬가지로, 액티비티 A가 B로부터 어떠한 정보를 받고 싶다면, 인텐트를 사용하여 B를 호출한 다음, 인텐트에 원하는 정보를 실어서 그 정보를 다시 돌려받으면 됩니다.

일단, 호출하는 액티비티 (InformationInput)호출당하는 액티비티(InformationProc)의 코드를 보도록 하겠습니다.


(주의)
액티비티를 추가하는 방법을 모르신다면, 2009/03/01 - [안드로이드/안드로이드 입문] - [강좌] [수정] 이클립스에서 안드로이드 액티비티 추가하기 를 읽고 액티비티 추가 방법에 대해 숙지하신 후 이 강좌를 읽어주세요.


[InformationInput.java]

01.package com.androidhuman.IntentTest;
02.import android.app.Activity;
03.import android.content.Intent;
04.import android.os.Bundle;
05.import android.view.View;
06.import android.widget.Button;
07.import android.widget.TextView;
08.
09.public class InformationInput extends Activity {
10. /** Called when the activity is first created. */
11. @Override public void onCreate(Bundle savedInstanceState) {
12. super.onCreate(savedInstanceState);
13. setContentView(R.layout.main);
14. final Button requestInfo = (Button)findViewById(R.id.requestInfo);
15. requestInfo.setOnClickListener(new Button.OnClickListener(){ // 버튼을 클릭할 경우
16. public void onClick(View v){
17. Intent intent = new Intent(InformationInput.this,InformationProc.class);
18. startActivityForResult(intent, 1); // Sub_Activity 호출
19. }
20. });
21. }
22.
23. @Override
24. protected void onActivityResult(int requestCode, int resultCode, Intent data){
25. super.onActivityResult(requestCode, resultCode, data);
26. TextView name_view = (TextView)findViewById(R.id.name_view);
27. TextView digit_view = (TextView)findViewById(R.id.digit_view);
28. if(resultCode==RESULT_OK) // 액티비티가 정상적으로 종료되었을 경우
29. {
30. if(requestCode==1) // InformationInput에서 호출한 경우에만 처리합니다.
31. { // 받아온 이름과 전화번호를 InformationInput 액티비티에 표시합니다.
32. name_view.setText(data.getStringExtra("data_name"));
33. digit_view.setText(data.getStringExtra("data_digit"));
34. }
35. }
36. }
37. }


[main.xml]
01.<?xml version="1.0" encoding="utf-8"?>
02.<LinearLayout
03.android:layout_height="fill_parent"
04.android:layout_width="fill_parent"
05.android:orientation="vertical"
07.<TextView android:layout_height="wrap_content"
08.android:layout_width="fill_parent"
09.android:text="@string/name" />
10.<TextView android:layout_height="wrap_content"
11. android:layout_width="fill_parent"
12. android:text="-이름이 입력되지 않음-"
13. android:id="@+id/name_view"/>
14.
15.<TextView android:layout_height="wrap_content"
16. android:layout_width="fill_parent"
17. android:text="@string/digit"/>
18.
19.<TextView android:layout_height="wrap_content"
20. android:layout_width="fill_parent"
21. android:text="-전화번호가 입력되지 않음-"
22. android:id="@+id/digit_view"/>
23.
24.<Button android:layout_height="wrap_content"
25. android:layout_width="wrap_content"
26. android:text="@string/button_launch"
27. android:id="@+id/requestInfo"
28. android:layout_gravity="center_horizontal"/>
29.</LinearLayout>



[InformationProc.java]

01.package com.androidhuman.IntentTest;
02.import android.app.Activity;
03.import android.content.Intent;
04.import android.os.Bundle;
05.import android.view.View;
06.import android.view.View.OnClickListener;
07.import android.widget.Button;
08.import android.widget.EditText;
09.public class InformationProc extends Activity {
10. /** Called when the activity is first created. */
11. @Override public void onCreate(Bundle savedInstanceState) {
12. super.onCreate(savedInstanceState);
13. setContentView(R.layout.informationproc);
14. Button input_info = (Button)findViewById(R.id.inputinfo);
15. input_info.setOnClickListener(new OnClickListener(){
16.
17. public void onClick(View v) { //버튼을 클릭하면
18. Intent intent = getIntent(); // 이 액티비티를 시작하게 한 인텐트를 호출
19. EditText name_input = (EditText)findViewById(R.id.name_input);
20. EditText digit_input = (EditText)findViewById(R.id.digit_input);
21. intent.putExtra("data_name",name_input.getText().toString());
22. intent.putExtra("data_digit", digit_input.getText().toString());
23. setResult(RESULT_OK,intent); // 추가 정보를 넣은 후 다시 인텐트를 반환합니다.
24. finish(); // 액티비티 종료
25. }
26. });
27. }



[informationproc.xml]




01.<?xml version="1.0" encoding="UTF-8"?>
02.<LinearLayout
03. android:layout_height="wrap_content"
04. android:layout_width="fill_parent"
05. android:orientation="vertical"
07. android:id="@+id/overview_layout">
08.
09.<TextView android:layout_height="wrap_content"
10. android:layout_width="wrap_content"
11. android:text="@string/text_information"/>
12.
13.<LinearLayout android:layout_height="wrap_content"
14. android:layout_width="fill_parent"
15. android:orientation="horizontal"
16. android:id="@+id/name_layout">
17.
18.<TextView android:layout_height="wrap_content"
19. android:layout_width="wrap_content"
20. android:text="@string/name"/>
21.
22.<EditText android:layout_height="wrap_content"
23. android:layout_width="fill_parent"
24. android:id="@+id/name_input"
25. android:hint="ex)안드로이드"/>
26.</LinearLayout>
27.
28.<LinearLayout android:layout_height="wrap_content"
29. android:layout_width="fill_parent"
30. android:orientation="horizontal"
31. android:id="@+id/digit_layout">
32.
33.<TextView android:layout_height="wrap_content"
34. android:layout_width="wrap_content"
35. android:text="@string/digit"/>
36.
37.<EditText android:layout_height="wrap_content"
38. android:layout_width="fill_parent"
39. android:id="@+id/digit_input"
40. android:hint="ex)011-123-4567"/>
41.
42.</LinearLayout>
43.
44.<Button android:layout_height="wrap_content"
45. android:layout_width="wrap_content"
46. android:text="@string/input"
47. android:id="@+id/inputinfo"
48. android:layout_gravity="center_horizontal"/>
49.</LinearLayout>


단순히 액티비티를 호출할 때에는 startActivity(Intent)를 사용했었지만, 액티비티를 호출한 후 결과값을 받기 위해서는 다른 메소드를 사용해야 합니다. 바로 startActivityForResult(Intent intent, int requestCode)입니다.


public void startActivityForResult(Intent intent, int requestCode)
호출당하는 액티비티로부터 데이터를 넘겨받기 위해 사용합니다.
intent - 인텐트
requestCode - 이 액티비티를 호출하는 액티비티가 여러 개가 있을 경우, 어떤 액티비티가 호출했는지를 알기 위해 사용


requestCode는 별로 특이한 것은 아니고, 한 액티비티를 여러 액티비티가 호출해야 할 경우, 호출이 어디에서 일어났는지를 알려주는 인자값입니다.
일단, InformationInput 액티비티를 봅시다. 버튼을 클릭하면 InformationInput 액티비티가 InformationProc 액티비티를 호출해야 하므로, 일단 intent를 생성하고, startActivityForResult()를 통해 InformationProc 액티비티를 실행시킵니다.



InformationProc 액티비티가 실행되면, 사용자로부터 이름과 전화번호를 입력받게 됩니다.
입력이 끝나고, 입력 버튼을 누르면, 입력받은 데이터를 인텐트에 집어넣게 됩니다.
1.Intent intent = getIntent(); // 이 액티비티를 시작하게 한 인텐트를 호출
2. EditText name_input = (EditText)findViewById(R.id.name_input);
3. EditText digit_input = (EditText)findViewById(R.id.digit_input);
4. intent.putExtra("data_name",name_input.getText().toString());
5. intent.putExtra("data_digit", digit_input.getText().toString());
6. setResult(RESULT_OK,intent); // 추가 정보를 넣은 후 다시 인텐트를 반환합니다.
7.finish(); // 액티비티 종료

차근차근 하나씩 보도록 하겠습니다.
일단, 첫번째, 인텐트를 생성하는 것을 볼 수 있습니다. 보통, 인텐트를 생성할 때 new 생성자를 써서 인텐트를 생성했던 것에 반해, 여기에서는 getIntent()를 사용하여 인텐트를 불러오고 있습니다. getIntent()메소드는 현재 자신을 호출했던 인텐트를 반환해줍니다.

여기서, 자신을 호출한 인텐트를 받아오는 것은, 아까 예로 들었던 심부를꾼을 생각해보면 쉽게 이해할 수 있습니다. A라는 심부름꾼에게서 물건을 받았는데, B라는 심부름꾼에게 물건을 주면 안되겠죠? 인텐트도 마찬가지입니다. :)

이렇게 해서 인텐트를 생성하면, 이제 EditText로부터 입력한 값들을 받아와야 합니다. findViewById()를 이용하여 레이아웃 객체와 코드상의 객체를 연결한 후, putExtra()메소드를 이용해 정보를 실어줍니다.

intent.putExtra(String name, _value)
name이라는 이름을 가지는 데이터를 인텐트에 첨가합니다.

인텐트에 들어가는 데이터는 "키"의 역할을 하는 name과 그에 해당하는 값인 _value가 짝을 이루어 저장됩니다.
이렇게 저장이 되었다면, 호출된 액티비티가 정상적으로 끝났는지, 비정상적으로 끝났는지 (물건을 제데로 받았는지, 심부름꾼이 왔는지 등등...으로 비유할 수 있겠습니다) 자신을 호출한 액티비티에게 알려주기도 해야 하고, 요청한 데이터도 같이 주어야 합니다.

일단, 호출당한 액티비티가 정상적으로 끝났음을 알리기 위해, setResult(RESULT_OK, intent) 메소드를 사용합니다. RESULT_OK로 액티비티가 정상적으로 끝났음을 전달하게 됩니다. RESULT_OK를 반환하지 않고 중간에 비정상적으로 종료되었다면 저 코드를 반환받지 못하므로 뭔가 문제가 있구나 알게 되겠죠? 제데로 종료가 된다면, 아까 우리가 추가로 입력한 데이터를 담은 인텐트도 함께 반환하게 됩니다.

이렇게.. 여기까지 정상적으로 돌아간 후, 호출당한 액티비티(InformationProc)가 finish()메소드에 의해 종료되게 되면, OnActivityResult() 메소드가 호출되게 됩니다. 결과를 기다리고 액티비티를 호출했으니, 액티비티가 종료되었으니 그 결과를 확인해야겠죠??


void onActivityResult(int requestCode, int resultCode, Intent data)
startActivityForResult로 호출한 액티비티가 종료되었을 때 호출됩니다.



01.protected void onActivityResult(int requestCode, int resultCode, Intent data)
02.{ super.onActivityResult(requestCode, resultCode, data);
03. TextView name_view = (TextView)findViewById(R.id.name_view);
04. TextView digit_view = (TextView)findViewById(R.id.digit_view);
05. if(resultCode==RESULT_OK) // 액티비티가 정상적으로 종료되었을 경우
06. {
07. if(requestCode==1) // InformationInput에서 호출한 경우에만 처리합니다.
08. {
09. // 받아온 이름과 전화번호를 InformationInput 액티비티에 표시합니다.
10. name_view.setText(data.getStringExtra("data_name"));
11. digit_view.setText(data.getStringExtra("data_digit"));
12. }
13. }
14. }


위의 onActivityResult에서, requestCode가 아까 setResult()에서 액티비티가 정상 종료되었는지를 판단하는 인자값, RESULT_OK를 받게 됩니다. 그래서, 이걸 가지고 적절히 예외 처리를 해 줄 수 있는 거죠.
requestCode는 아까 startActivityForResult()를 호출할 때, InformationInput이 호출한 것임을 표시하기 위해 '1'으로 설정하였으므로, 여기에서 또한 그 코드를 맞춰주어야 제데로 결과값을 받을 수 있습니다.

즉, 정상적으로 액티비티가 종료되었다면 requestCode의 값은 RESULT_OK, resultCode는 1이 됩니다.

이렇게 해서, 모두 정상이라면 인텐트에서 받아온 데이터를 꺼내 화면에 표시합니다.

putExtra() 메소드가 어떤 타입이든 상관없었던 것에 비해, 불러올 때에는 getStringExtra()메소드를 사용하여 문자열 값을 불러오면 됩니다. getStringExtra()뿐 아니라 getIntExtra(), getBooleanExtra() 등 여러 가지가 있으므로 상황에 맞추어 사용하면 됩니다.

이렇게 해서, 화면에 표시되는 TextView의 텍스트 값들이 아까 호출한 액티비티의 값들로 바뀌게 됩니다. :)


이렇게 해서, 인텐트를 통해 액티비티간에 데이터를 주고받는 것에 대해서 알아보았습니다. 이번 강좌는 다른 강좌들과는 다르게 세세한 부분에 대한 설명은 대부분 생략하였습니다. 이 강좌쯤을 보시는 분들은 어느 정도 기초가 되어 있으리라 믿기에, 일부러 안 적었습니다. 게다가 그걸 다 적으면 강좌가 한도끝도 없이 길어지기만 하죠 -_-

현재, 이 코드는 모든 문자열 값을 strings.xml에 넣어서 그 쪽에 있는 값들을 참조하는 형식으로 구성되어있습니다. 이 부분에 대해 궁금하신 분은 제가 2009/03/14 - [안드로이드/안드로이드 입문] - [강좌] 외부 리소스 사용하기 (문자열) 에 정리해놓았으니, 이걸 보시면 되겠습니다. :)

 

 

출처:http://androidhuman.tistory.com/125

Posted by 90002

가끔씩 마주치게 되는 "OutOfMemoryError : bitmap size exceeds VM budget" 에러는 메모리 누수가 주요 원인입니다. 이와 관련된 링크를 모아봤습니다.


* 액티비티가 멈출 때 비트맵을 재활용(즉 GC)되게 하라

- bitmap 이미지인 경우 recycle() 호출
- onPause에서 수행하는게 좋음
- ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();

* 이미지를 미리 줄여서 읽어들여라

- BitmapFactory.Options.inSampleSize 활용

* Activity Context에 대한 참조(reference)를 오랫동안 유지하지 말아라

- Drawable.setCallback(null) 사용
- WeakReference를 가진 static 내부 클래스
- 이미지를 static 변수로 처리하지 마라

* 외부(outer) 클래스의 상태에 의존하지 않는 내부(inner) 클래스는 static으로 선언하라
- 내부클래스는 외부 클래스 인스턴스를 크게 만들며 또한 외부클래스 객체가 필요이상으로 오래 살아있게 되어 메모리를 더 차지할 수 있음
- 외부클래스의 상태 필드에 접근하지 않는(즉 외부 객체의 상태에 의존하지 않는) 내부클래스는 static으로 선언

* Attacking memory problems on Android
Posted by 90002

안드로이드 Paint


Paint 상속 계층도

java.lang.Object

└─ android.graphics.Paint


Paint의 하위 클래스들

TextPaint


Paint 은 머야?

그리기(Draw)하기위해 쓰여지는 도구 라고 생각하시면 됩니다.

쉽게 말해 Canvas가 도화지라면 Paint는 붓이라고 생각하시면 좋을듯 합니다.

도화지에 그림을 그릴때 우리들은 여러가지 붓을 사용하여 효과를 줍니다.

붓을 굵기, 색상, 모양등을 선택해서 원하는 형태로 그릴수 있는 것이죠.


Paint 에서 사용되는 메소드

  1. set(Paint src)

    - 매개변수로 받은 Paint로 설정합니다.


    setARGB(int a, int r, int g, int b)

    - Paint의 투명도 및 색상을 설정 합니다.


    setAlpha(int a)

    - Paint의 투명도 설정을 합니다.


    setAntiAlias(boolean aa)

    - Paint의 경계면을 부드럽게 처리할지 설정합니다.


    setColor(int color)

    - Paint의 색상 설정 합니다.


    setStrokeCap(Paint.Cap cap) - 선의 끝나는 지점의 장식을 설정합니다.

    BUTT : 그 정해진 위치에서 끝납니다.

    ROUND : 둥근 모양으로 끝이 장식됩니다.

    SQUARE : 사각형 모양이며, 해당 좌표보다 조금더 길게 그려 집니다.

    setStrokeJoin(Paint.Join join) - 선의 끝 모양을 설정합니다.

    MITER : 모서리를 각진 모양으로 만듭니다.

    BEVEL : 모서리가 둥글게 살짝 깍인 모양으로 만듭니다.

    ROUND : 모서리를 둥근 모양으로 만듭니다.

    setStrokeMiter(float miter)

    - 0 이상의 값을 설정, 뽀족한 정도를 설정(각도단위)


    setStrokeWidth(float width)

    - Paint의 굵기를 설정 합니다.


    setStyle(Paint.Style style) - Paint 스타일을 설정 합니다.

    FILL : 색상이 채워지고 테두리는 그려지지 않습니다.

    FILL_AND_STROKE : 채우기와 테두리가 모두 그려집니다

    STROKE : 채우기 없이 테두리만 그려집니다.


    setTextAlign(Paint.Align align)

    - 해당 Paint의 글자 정렬을 설정 합니다.


    setTextScaleX(float scaleX)

    - 텍스트페인트의 수평scale factor 를 설정합니다.


    setTextSize(float textSize)

    - Paint의 글자 크기를 설정합니다.


    setTextSkewX(float skewX)

    - Paint의 수평으로 기울어진 정도를 설정합니다.


    setTypeface(Typeface typeface)

    - Paint의 글꼴을 설정 합니다.


    setUnderlineText(boolean underlineText)

    - Paint의 글자에 밑줄 설정을 합니다.


    setColorFilter(ColorFilter filter)

    - RGB를 이용하여 paint에 변화를 줍니다. 이것은 Alpha를 무시 합니다.

    setMaskFilter(MaskFilter maskfilter)

    - 모서리에 알파채널을 이용하여 효과를 설정합니다.


    setPathEffect(PathEffect effect)

    - 그리는 방법을 제어 합니다.(도형의 모서리, 윤곽선등)


    setShader(Shader shader)

    - 솔리드에 색상을 설정해 줍니다. 그라디언트등


    setXfermode(Xfermode xfermode)

    - 이미 그려진 곳에 새로 그리는 기법입니다.

 

 

출처:http://jwandroid.tistory.com/182#recentTrackback 


Posted by 90002

[안드로이드]이미지 드래그해서 이동, 핀치투줌으로 확대축소하는 법(멀티터치)

멀티 터치 관련 글들을 많이 찾아봤으나, 

아무리 찾아봐도 제대로 구현해놓은 것이 없어서 직접 구현해보았습니다.

드래그를 이용한 이미지 이동, 핀치투줌을 이용해서 이미지를 확대, 축소 합니다. 

이후로는 회전도 가능하도록 할 예정입니다. 회전은 Matrix를 이용해야겠지요.


  1.MovingUnit.class

실제 움직일 unit을 컨트롤한다.

package beginners.ruler;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class MovingUnit{
	//이미지
	private Bitmap Image;
	
	private float X;
	private float Y;

	private float Width;
	private float Height;
	
	//처음 이미지를 선택했을 때, 이미지의 X,Y 값과 클릭 지점 간의 거리
	private float offsetX;
	private float offsetY;
	
	// 드래그시 좌표 저장

	int posX1=0, posX2=0, posY1=0, posY2=0;	    

	// 핀치시 두좌표간의 거리 저장

	float oldDist = 1f;
	float newDist = 1f;
	
	// 드래그 모드인지 핀치줌 모드인지 구분
	static final int NONE = 0;
	static final int DRAG = 1;
	static final int ZOOM = 2;

	int mode = NONE;	
	


	//Image를 인자로 받는다.
	public MovingUnit(Bitmap Image) {
		// TODO Auto-generated constructor stub
		this.Image=Image;
		
		setSize(Image.getHeight(),Image.getWidth());
		setXY(0,0);
		
	}

	public void TouchProcess(MotionEvent event) { 
	    int act = event.getAction();
	     switch(act & MotionEvent.ACTION_MASK) {
	        case MotionEvent.ACTION_DOWN:    //첫번째 손가락 터치
	        	if(InObject(event.getX(), event.getY())){//손가락 터치 위치가 이미지 안에 있으면 DragMode가 시작된다.
		        	posX1 = (int) event.getX();
		            posY1 = (int) event.getY();
		            offsetX=posX1-X;
					offsetY=posY1-Y;
					
		            Log.d("zoom", "mode=DRAG" );
	
		            mode = DRAG;		            
	        	}
	            break;

	        case MotionEvent.ACTION_MOVE: 
	            if(mode == DRAG) {   // 드래그 중이면, 이미지의 X,Y값을 변환시키면서 위치 이동.
	            	X=posX2-offsetX;
		    		Y=posY2-offsetY;
	            	posX2 = (int) event.getX();
	                posY2 = (int) event.getY();
	                if(Math.abs(posX2-posX1)>20 || Math.abs(posY2-posY1)>20) {
	                    posX1 = posX2;
	                    posY1 = posY2;
	                    Log.d("drag","mode=DRAG");
	                }

	            } else if (mode == ZOOM) {    // 핀치줌 중이면, 이미지의 거리를 계산해서 확대를 한다.
	                newDist = spacing(event);
	               
	                if (newDist - oldDist > 20) {  // zoom in
	                	 float scale=FloatMath.sqrt(((newDist-oldDist)*(newDist-oldDist))/(Height*Height + Width * Width));
		                 Y=Y-(Height*scale/2);
		                 X=X-(Width*scale/2);
		                		 
		                 Height=Height*(1+scale);
		                 Width=Width*(1+scale);
		                
	                	 oldDist = newDist;
	                    
	                 } else if(oldDist - newDist > 20) {  // zoom out
	                	 float scale=FloatMath.sqrt(((newDist-oldDist)*(newDist-oldDist))/(Height*Height + Width * Width));
		                 scale=0-scale;
		                 Y=Y-(Height*scale/2);
		                 X=X-(Width*scale/2);
		                		 
		                 Height=Height*(1+scale);
		                 Width=Width*(1+scale);
		                
	                	 oldDist = newDist;
	                }
	            }
	            break;

	        case MotionEvent.ACTION_UP:    // 첫번째 손가락을 떼었을 경우
	        case MotionEvent.ACTION_POINTER_UP:  // 두번째 손가락을 떼었을 경우
	            mode = NONE;
	            break;
	        case MotionEvent.ACTION_POINTER_DOWN:  
	        //두번째 손가락 터치(손가락 2개를 인식하였기 때문에 핀치 줌으로 판별)
        		mode = ZOOM;
	            newDist = spacing(event);
	            oldDist = spacing(event);
	            Log.d("zoom", "newDist=" + newDist);
	            Log.d("zoom", "oldDist=" + oldDist);
	            Log.d("zoom", "mode=ZOOM");
        	
	            break;
	        case MotionEvent.ACTION_CANCEL:
	        default : 
	            break;
	    }

	}
	//Rect 형태로 넘겨준다.
	public Rect getRect(){
		Rect rect=new Rect();
		rect.set((int)X,(int)Y, (int)(X+Width), (int)(Y+Height));
		return rect;
	}

	 private float spacing(MotionEvent event) {
	    float x = event.getX(0) - event.getX(1);
	    float y = event.getY(0) - event.getY(1);
	    return FloatMath.sqrt(x * x + y * y);

	}
	 public boolean InObject(float eventX,float eventY){
		if(eventX<(X+Width+30) &&  eventX>X-30 && eventYY-30){
			return true;
		}
		return false;
	}	
	 public void setSize(float Height,float Width){
			this.Height=Height;
			this.Width=Width;
			
		}
	public void setXY(float X, float Y){
		this.X=X;
		this.Y=Y;
	}
	public Bitmap getImage(){
		return Image;
	}
}
2.MovingObject.class 
 실질적으로 main함수 역할을 한다.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.shapes.Shape;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class MoveObject extends View{
	int X,Y,Height,Width;
	private MovingUnit MU;
	
	public MoveObject(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	public void setSelectedImage(String ImagePath){
		Bitmap Image=BitmapFactory.decodeFile(ImagePath);
		MU=new MovingUnit(Image);
		invalidate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		MU.TouchProcess(event);
		invalidate();
		return (true);
	}
	
	@Override
	
	public void draw(Canvas canvas) {
		// TODO Auto-generated method stub
		canvas.drawBitmap(MU.getImage(), null,  MU.getRect(), null);
		
		
		super.draw(canvas);
	}
}

결과 화면


모르는 것 있으시면 댓글로 남겨주세요:)




 

안드로이드 Matrix 함수 확대 축소 회전 비틀기 이동 뒤집기

Matrix.postScale(float x, float y) // 확대, 축소

Matrix.postRotate(float degrees) // 이미지 회전

Matrix.postSkew(float sx, float sy) // 이미지 비틀기

Matrix.postTranslate(floatdx, float dy) // 이미지 이동

Matrix.postScale()을 이용하면 이미지의 확대/축소 뿐만 아니라 이미지를 수직이나 수평으로 뒤집기.

Matrix.postScale(-1, 1) // 수평으로 뒤집기

Matrix.postScale(1, -1) // 수직으로 뒤집기

Matrix.postScale(-1, -1) // 수평, 수직 뒤집기 Matrix.postRotate(180)과 같은 결과

Matrix matrix = new Matrix(); // 새로운 Matrix를 만들고

matrix.postScale(-1, 1); // 수평으로 뒤집기

bitmap2 = Bitmap.createBitmap(bitmap1, 0, 0, w, h, matrix, false); // 새로운 비트맵 생성

Posted by 90002

Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE
Please check logcat output for more details.
Launch canceled!

안드로이드 컴파일을 시키면 위와 같은 에러 메시지 때문에 실행이 안되는 경우가 종종 있다.

이는 내장 메모리 공간이 부족하다는 메세지이다.

프로그래밍을 하다보면 Log가 쌓이는데, 그 작은 로그들이 쌓여서 내장 메모리의 공간을 많이 사용하게 된다.

그래서 log 데이터를 삭제해야한다.

 

-에뮬레이터에서 문제가 생길 시에는

1. log 데이터를 삭제(http://devbible.tistory.com/22 참조)

/>adb shell

# cd data
cd data
# cd log
cd log
# rm *
rm *


2. 에뮬레이터의 용량 크게 설정(http://kheru.tistory.com/53 참조)

- 콘솔을 사용하여 설정하기
emulator -partition-size 256 @AVD명

- 이클립스의 Run 실행에서 설정하기
Run > Run configuration > 해당 프로젝트 > Target >
Additional Emulator Command Line Options 에 아래 코드를 입력;
-partition-size 256

[출처]http://futureworker.tistory.com/9

 하면 되지만,

 

- 에뮬레이터가 아닌, 휴대폰에서 위와 같은 문제가 발생할 수 있다.

그럴 때는 adb shell을 통해서 해도 되지만 그렇게 하기 위해서는 permission을 accept 해야하는 번거로움이 있다.

다른 방법은 History Eraser라는 어플을 사용하는 방법이다.

History Eraser는 휴대폰 사용 기록을 없애주는 어플인데,

아래와 같이 [Clear All Apps Cache]를 삭제하면 로그기록까지 삭제해서 내장 메모리 공간을 확보할 수 있다.

Posted by 90002
//파일명 불러와서 저장할 파일명 정하기
     File files = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/ruler");
     int max=0;

     if(files.listFiles().length>0){  // 안에 있는 파일의 갯수가 0보다 클때  
      for(File list : files.listFiles()){
        String text=list.getName().substring(3,7);
        if(isNaN(text)){
         int num=Integer.parseInt(text);
         if(num>max){
          max=num;
         }
        }
        Log.e("1","name: "+ list.getName());  // 로그에 불러온 파일의 이름
       }
     }
     
     
     Bitmap bm = (Bitmap) data.getExtras().get("data");
     String filename = "CAM"+String.format("%5d", max)+".jpg";
     Log.e("2","file name: "+ filename);
     
           File f = new File(Environment.getExternalStorageDirectory()+"/ruler", filename);
           
           try {

            f.createNewFile();

            OutputStream outStream = new FileOutputStream(f);
            bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            
            uri=Uri.fromFile(f);
            outStream.close();

        } catch (IOException e) {

            e.printStackTrace();

           }

Posted by 90002

<script type="text/javascript"><!--
google_ad_client = "ca-pub-1261983873465389";
/* 글 제일 위에 */
google_ad_slot = "2059623354";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

이번에 안드로이드 스터디를 진행하면서, 과제가 주어졌다. " 모든 작업은 JAVA로만 구현해오세요. "
어차피 대부분 기능은 자바로 구현되니 쉽게 찾아보면서 할수있겠지.... 했는데, 아무리 서적을 뒤져봐도 JAVA 만을 이용한 안드로이드 코드방식에 대해 설명한 책은 없었다.
일부 책에서 약간의 언급을 해줬지만, 순수 JAVA 코드로만 짜는 것은 아주 간단한 프로그램만들때만 쓸 뿐, 큰 프로젝트를 진행하게 되면, 비효율적인 부분들이 많아서 쓰지 않는다. 라고 마무리 짓고 더이상의 설명은 찾아볼수가 없었다.
혹시나 저처럼 자료를 찾아다니는 분들이 있을까하여, 혼자서 구글링을 하며 배운 내용을 짧게나마 포스팅 남겨둡니다.


[ 안드로이드 최초 생성시 Activity_main.xml 의 구성 ]

[위의 Activity_main.xml 코드를 Java로 바꿨을 때 ]

처음보면 왜 서적에서 쓰지말라고하는지, 이해가 갈수도...

그런데 막상 알고보면 별거 없습니다. 천천히 살펴보죠.

RelativeLayout rlRelativeLayout = new RelativeLayout(ctCtex);
xml에서 최초 <RelativeLayout... 으로 설정하고 코드 작성을 시작합니다.
마찬가지로 java 코드에서도 RelativeLayout 을 할당해서 컨텍스트(Context)를 연결해줍니다.



RelativeLayout.LayoutParams lpRelativeLayout_Property = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);

다음 레이아웃의 속성을 지정해주기 위해, RelativeLayout.LayoutParams 를 사용합니다.
(LinearLayout 을 사용해서 만들었다면. LinearLayout .LayoutParams :: 해당 레이아웃에 맞는 Params를 가져옵니다. )
xml에서 android:layout_width / heigth 를 지정해주는 것처럼 RelativeLayout.LayoutParams 에서 인자로 넓이 / 높이 를 받게 됩니다.


[ 이해 하시리라 믿겠습니다 . . . ㅡ 3 - ]


rlRelativeLayout.setLayoutParams( lpRelativeLayout_Property )
중요! 레이아웃 설정만 해서 끝나는것이 아닙니다. 속성 지정이 끝나면, setLayoutParams 를 이용하여, 설정값을 세팅한 변수를 입력해서, 세팅하고자하는 레이아웃에게 넘겨줘야됩니다.


이제 RelativeLayout 의 크기 설정이 끝났다.
다음 Layout 안에 들어갈 뷰를 생성해보자.

TextView tvText = new TextView(ctCtex);
위에 설명한 레이아웃 생성방식과 동일합니다. new 를 통해서 객체 생성과 동시에 인자로 컨텍스트를 넘겨줍니다.


RelativeLayout.LayoutParams lptvText_Property = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
lptvText_Property.addRule(RelativeLayout.CENTER_VERTICAL);
lptvText_Property.addRule(RelativeLayout.CENTER_HORIZONTAL);

마찬가지로 레이아웃에서 설정하던 방식과 동일합니다. 눈여겨 볼점은 addRule 이라는 함수부분 입니다.

[Reference ]
.addRule(int verb); or .addRule(int verb, int anchor);

기본적으로 LayoutParams의 인자로 바로 설정 가능한 값은 w / h (Width 와 Height) 값 밖에 없습니다.
xml에서 android:layout_centerHorizontal 과 같이 부가적인 설정 변경은 addRule을 통해 이뤄지게 됩니다.


addRule 을 이용한 설정 몇가지만 간략하게 설명해뒀으니 참고하시길...

더보기



tvText.setText(R.string.hello_world);
텍스트 뷰에 텍스트를 입력하는 부분입니다.
인자로 텍스트 저장 부분의 id 를 넘겨줘도 되고, 아래 처럼 직접 써줘도 됩니다.
위 코드에서는 xml과 똑같이 비교하기 위해 아이디를 연결해줬습니다. XML 코드없이 만들기 위해선 직접 입력해줘야겠죠??

tvText.setText("Hello World"); 문자열을 직접 입력해서 넣어줘도 됨.





rlRelativeLayout.addView(tvText);
텍스트 아까전에 속성을 추가해주는 setLayoutParams 처럼 역시 중요한 부분입니다.
사실 간단하면서 당연한부분인데, 중요하다고 하는 점은 쉽게 지나칠수 있다는 점 때문입니다.
xml 에선 < /> 안에 넣으면 자동으로 안에 포함되기때문에 java로 짜다보면 추가해주는 걸 자꾸 깜빡하는 경우가 많습니다.
(저... 저만 그럴수도...)




setContentView(rlRelativeLayout);
xml 코드에서보면 Activity_main.xml 의 주소값을 setContentView의 인자로 집어넣어서 사용합니다.
마찬가지로 위에서 설정된 값을 모두 가지는 레이아웃을 인자로 집어 넣어주게 되면, 최초 안드로이드 예제와 똑같은 결과를 얻을수 있게 됩니다.

http://dark0946.tistory.com/119

<script type="text/javascript"><!--
google_ad_client = "ca-pub-1261983873465389";
/* 글 아래 */
google_ad_slot = "3536356550";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

Posted by 90002

Android APK 파일을 디컴파일 decompile

* 안드로이드을빨리이해하기위한방법

1. OpenSource활용

- http://code.google.com/hosting/

- http://google.com/codesearch

2. Reverse Engineering 활용하여 학습하기

- 자바 클래스 리버싱

- 안드로이드 실행파일 구조와 리버싱

* APK파일 디컴파일(Decompile)하는 방법

1. 디컴파일을 위한 툴 설치

1.ApkTool

- 다운로드 : http://code.google.com/p/android-apktool/downloads/list

- 압축풀기 : android-sdk가 설치된 platform-tools디렉토리안에 apktool디렉토리를 만들어 압축을 푼다.

apktool1.4.1.tar.bz2

apktool-install-windows-r04-brut1.tar.bz2

2.Dex2Jar

- 다운로드 : http://code.google.com/p/dex2jar/downloads/list


- 압축풀기 : android-sdk가 설치된 platform-tools디렉토리안에 dex2jar디렉토리를 만들어 압축을 푼다.

dex2jar-0.0.7.10-SNAPSHOT.zip

3.Java Decompiler

- 다운로드 : http://java.decompiler.free.fr/?q=jdgui

- 압축풀기 : 실행하기 편한 곳에 압축을 풀어 놓는다.

2. 환경변수 잡기

- adb, apktool, dex2jar 명령어를 사용하기 위한 환경변수를 잡는다.

%ANDROID_SDK%\platform-tools

%ANDROID_SDK%\platform-tools\apktool

%ANDROID_SDK%\platform-tools\dex2jar

3. apk 파일 추출

- 폰에 설치된 모든 패키리를 리스트로 보인다.

- 리스트 중에 디컴파일 할 APK파일을 정한다.

- APK파일을 추출한다. (adb shell을 종료 후 수행한다.)

4. ApkTool 실행 (java파일 외 xml, image, db등을 추출할 수 있다.)

- apktool 명령어를 사용하여 apk파일에 있는 파일을 디코딩하여 out폴더에 내보낸다.

- xml파일을 열어 내용을 확인한다.

5. Dex2Jar 실행 (Java파일을 추출할 수 있다.)

- apk파일의 확장자를 zip으로 변경한다.

- 추출한 zip파일의 압축을 풀어 classes.dex 파일을 추출한다.

- Dex2Jar를 실행한다.

- Dex2Jar를 실행하면 아래 jar파일이 생긴다.

6. JD-GDI 실행

- JD-GDI실행하여 classes.dex.dex2jar파일을 열어 소스를 분석한다.

7. Enterprise Architect를 이용하여 클래스 다이어그램으로 분석한다.

- 다운로드 : http://www.sparxsystems.com.au/products/ea/trial.html

- 설치

- 실행

- Java Decompiler에서 open할 파일을 추출한다.

- zip파일을 압축을 푼다.

- Enterprise Architect에서 classes.dex.dex2jar.src디렉토리를 import 한다.

- 클래스 다이어그램을 보고 분석한다.

-----------------------------------------------------------------------------------------------------------------------

제 11회 한국자바개발자 컨퍼런스에서 트랙1, 3번째 세션에서 Reverse Engineering, 안드로이드 학습이란 주제로 발표를 진행합니다.

리버싱이 무엇인지, 안드로이드 리버싱을 통해서 어떻게 학습을 할 수 있는지 다양한 도구와 팁들을 소개합니다.

학습을 목적으로 리버스엔지니어링이 허용되지만 기술을 복제 유혹을 받을 수도 있습니다.

법적이나, 윤리적으로 문제가 된다는 것을 명심하고, 공부한 내용을 서로 공유하며 미소 지을 수 있는 개발문화가 되길 바래봅니다. :D

발표자료와 함께 사용된 동영상 공유합니다.

발표자료 : Reverse Engineering, 안드로이드 학습

자바 클래스 리버싱

안드로이드 실행파일 구조와 리버싱

Reverse Engineering 활용한 학습 예제

  1. 분석할 앱선정과 APK 파일 추출
  2. 디컴파일 후 분석
  3. 클래스 다이어그램으로 - Enterprise Architect
  4. 의존성 검사를 통해 쉽게 - xDepend

http://blog.naver.com/PostView.nhn?blogId=man8408&logNo=110111707630

Posted by 90002

<script type="text/javascript"><!--
google_ad_client = "ca-pub-1261983873465389";
/* 글 제일 위에 */
google_ad_slot = "2059623354";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

사용자정의 다이얼로그. 즉, Custom Dialog에 대해 알아보도록 하겠습니다.

말 그대로 다이얼로그의 띄워줄 모양을 개발자가 정한대로 보여줄 수 있는 다이얼로그 입니다.

버튼과 텍스트뷰를 배치한 후 버튼 클릭 시 가운데 화면과 같은 다이얼로그를 띄워줍니다.

다이얼로그의 해당하는 입력란에 입력 후 확인버튼을 클릭하면 그 값을 텍스트뷰에 보여주는 형식의 프로그램입니다.

=============================================

Project Name : CustomDialog

Package Name : kidsbear.customdialog

android version : 2.2 (8)

java version : jdk 1.6

=============================================




1. res > layout > main.xml 파일을 작성합니다.

간단히 버튼과 텍스트뷰 1개씩을 배치하였고, 버튼 클릭 시 mOnClick() 메소드를 호출하도록 설정하였습니다.

2. res > layout > dialoglayout.xml 파일을 생성/작성합니다.

위와 같은 모양의 레이아웃을 작성합니다.

이 레이아웃은 다이얼로그 안에 보여줄 레이아웃입니다.

어려운것은 없으니 자세한 것은 아래 소스를 통해 확인하시기 바랍니다.



3. CustomDialogActivity.java 파일을 작성합니다.

1) 필요한 변수를 전역변수로 설정해 줍니다.



2) onCreate() 메소드입니다.

LayoutInFlater 객체와 텍스트뷰을 참조한 객체를 생성해줍니다.



3) 버튼 클릭 이벤트 발생 시 호출될 mOnClick() 메소드를 작성합니다.

showDialog() 메소드를 통해 다이얼로그를 생성/호출 합니다.



4) onCreateDialog() 메소드를 오버라이딩합니다.

LayoutInflater의 inflate() 메소드를 통해 우리가 만든 dialoglayout 레이아웃을 인플레이트하여 LinearLayout 객체를 생성합니다.

위에서 인플레이트한 레이아웃을 인수로 setView() 메소드를 통해 다이얼로그의 내부로 보이도록 설정합니다.

setView(View v) 메소드는 인수로 View 객체를 받기 때문에 우리가 만들 수 있는 거의 모든 레이아웃을 적용할 수 있습니다.

확인 버튼 클릭 시 LinearLayout의 위젯들을 참조한 후 값을 추출/가공하여 텍스트뷰에 보여주게 됩니다.

http://blog.naver.com/PostView.nhn?blogId=kittoboy&logNo=110133839293

<script type="text/javascript"><!--
google_ad_client = "ca-pub-1261983873465389";
/* 글 아래 */
google_ad_slot = "3536356550";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

Posted by 90002
이전버튼 1 2 이전버튼

최근에 달린 댓글

최근에 받은 트랙백

글 보관함