지식메모/안드로이드 Android

반응형




우선 아래와 같이 asset 폴더에 폰트파일을 추가해준다.





폰트파일의 경로는 C:\Windows\Fonts 여기서 찾을 수 있다.


그런 다음 폰트를 바꾸고 싶은 뷰에다 적용을 해주면되는데 개인적으로 버튼의 텍스트 폰트를 바꾸고 싶었다.



Button btn2 = (Button)findViewById(R.id.button_custom);
btn2.setOnClickListener(this);
	
Typeface typeFace = Typeface.createFromAsset(getAssets(), "fonts/NEXONFootballGothicB.ttf"));  //asset > fonts 폴더 내 폰트파일 적용
btn2.setTypeface(typeFace);


위와 같이 버튼에 폰트를 적용하였다.


Typeface typeFace = Typeface.createFromAsset(getAssets(), "fonts/NEXONFootballGothicB.ttf")); // 폰트 설정 후

btn2.setTypeface(typeFace); //btn2 버튼에 폰트 적용


끝!


반응형
반응형




xml 작성 중 error: Apostrophe not preceded by / 계속 이런 에러가 났다 


왜 그런고 하니 어퍼스트로피 이 원인이었다.


본문은


creates a profile to share a friend's sending 


이러하였고 그래서 어퍼스트로피 전에 역슬래시를 추가해주었다.


creates a profile to share a friend\'s sending 


문제가 해결되었다!



반응형
반응형




안드로이드 시스템 언어설정을 변경하면 앱도 같이 변경하게 하고 싶었다.


프로젝트 폴더를 보면 


values 라는 폴더가 있는데 이 폴더가 기본 폴더이다.


내가 필요한 건 영어였기 때문에


values-en 폴더를 만들었다.





국가별 코드는 아래 링크에서 확인할 수 있다


http://developer.android.com/reference/java/util/Locale.html


위 링크에서 Field 항목에서 확인할 수 있다.


영어는 이렇게 나온다


public static final Locale ENGLISH

Added in API level 1

Locale constant for en.



values-en 폴더를 만들었다면 이제 string,xml 을 영어로 바꿔줘야 한다.


 values 폴더 내 string.xml 은 한글로


values-en 폴더 내 string.xml 은 영어로 작성한다.



이렇게 해주면 시스템 언어가 한글이면 values 폴더를 따르게 되어 한글로 나타나고


영어면 values-en 폴더를 따르게 되어 영어로 나타난다.


예를 들면


 values 폴더 내 string.xml

 values-en 폴더 내 string.xml 

 <string name="app_name">안드로이드 앱</string>




  <string name="app_name">AndroidApp</string>




이렇게 작성해준다면 그림과 같이 알아서 영어로 나타난다.


그래서 layout 폴더에 각 액티비티에 해당하는 xml 파일에 다음과 같은 코드를 추가해준다.


 android:text="@string/app_name"


<TextView       

         android:id="@+id/text2"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/app_name"

         />




이런 식으로 "@string/해당 string name" 을 지정해주면 

values, values-en 폴더를 생성해 두었기 대문에 자동으로 분기가 되어 

한글이면 한글, 영어면 영어로 변경된다.



하지만 xml이 아닌 JAVA 로 언어셋팅을 해주었다면 어떻게 해주어야 할까



아래 코드를 통해 JAVA에서도 분기가 가능하다



Locale locale = getResources().getConfiguration().locale;
String language =  locale.getLanguage();



위 코드로 현재 시스템 언어가 어떤건지 값을 알아낼 수 있다.


만약 영어로 변경했다면 language 에는 "en" 스트링 값이 저장될 것이다.


그렇다면 이 값으로 분기를 해준다.


EditText et_star = (EditText)findViewById(R.id.edit);
	if(language.equals("en"))
		et_star.setText("Hello!");
	else
		et_star.setText("안녕하세요");





이렇게 language.equals("en") 영어라면 


et_star.setText("Hello!");

 Hello! 를 셋팅 


그게 아니라면 


et_star.setText("안녕하세요");

안녕하세요 를 셋팅 


할 수 있다. 


이렇게 해서 다른 언어도 분기 가능하다.



자유로운 언어 변경을 위해서는 xml 파일에서 string.xml 을 통해 문구를 설정 하는게 편하다는 것을 배울 수 있었다.



그런데 한가지 문제가 있었는데 영어로 언어변경을 하면 앱 테마가 진저브레드? 시절로 바뀌는 문제가 있었다.


앱 사용에는 문제가 없었지만 이 부분도 한번 찾아봐야겠다.





반응형
반응형





if문이 자꾸 늘어나고 또 나중에 수정할 때 건드리는 부분이 많아져서 어떻게 할까 고민하던 중 

Map을 이용하여 하는 방법에 대해 알게 되었다.


즉 이러한 if 문을



	public static BitmapDrawable getSeasonBitmapDrawble(Context context, String str_season){

		BitmapDrawable img_season = null;
		if(str_season.equals("13")){
		   img_season =BitmapDrawable)context.getResources().getDrawable(R.drawable.year13);
		}else if(str_season.equals("15")){
		   img_season =BitmapDrawable)context.getResources().getDrawable(R.drawable.year15);
		}else if(str_season.equals("여름")){
		   img_season =BitmapDrawable)context.getResources().getDrawable(R.drawable.summer);
		}else if(str_season.equals("봄")){
		   img_season =BitmapDrawable)context.getResources().getDrawable(R.drawable.spring);
		}
		        return img_season; 
		}



Map의 key, value를 사용하여 바꿔보는 것이었다.


살펴보니


img_season =BitmapDrawable)context.getResources().getDrawable(R.drawable.year13);


이 부분이 반복적이었다.


그리고 하나 새로운 사실을 알게 되었는데


R.drawable.year13


이 이미지 값이 int 형이었다는 것이다. 그냥 보고 String 인 줄 알았었다.


그래서 HashMap 선언시 <String, Integer>로 해주었다.


<13,R.drawable.year13>


이런 식으로 저장하기 위함이었다.



일단 값들을 HashMap에 넣어놓았다.



static HashMap<String, Integer> map = new HashMap<String, Integer>(); //HashMap 선언
	public static HashMap getMap() {
        
        map.put("Special", R.drawable.special);
        map.put("봄", R.drawable.spring);
        map.put("여름", R.drawable.summer);
        map.put("가을", R.drawable.fall);
        map.put("겨울", R.drawable.winter);

        map.put("09", R.drawable.year09);
        map.put("10", R.drawable.year10);
        map.put("11", R.drawable.year11);
        map.put("12", R.drawable.year);
        map.put("13", R.drawable.year13);
        map.put("14", R.drawable.year14);
        map.put("15", R.drawable.year15);
        
        
        return map;
}


그리고 이미지 세팅을 위한 코드



public static BitmapDrawable getSeasonBitmapDrawble(Context context, String str_season){
		
		BitmapDrawable img_season = null;
		img_season = (BitmapDrawable)context.getResources().getDrawable(getMap().get(str_season));
		
        return img_season; 
	}




img_season = (BitmapDrawable)context.getResources().getDrawable(getMap().get(str_season));


getMap().get(str_season) 이 부분으로 Map에서 str_season로 들어온 key 값을 찾아 int 형 value 값을 불러오도록 하였다.


하지만 값이 몇백 몇천개로 늘어났을 경우


이렇게 바꾼다고 해서 전보다 깔끔하고 보기 편해지긴 했지만 성능적인 면에서 더 좋아지는 건지에 대한 의문이 들었다.


어차피 이미지 세팅 할 때마다 getMap()을 거쳐야 하기 때문이다.


좀 더 좋은 방법이 없을까 찾아보았는데



private static HashMap<String, Integer> map;
 
    public static HashMap getMap() {
        if (map == null) {
            map = new HashMap<String, Integer>();
 
            map.put("Special", R.drawable.special);
            map.put("봄", R.drawable.spring);
            map.put("여름", R.drawable.summer);
            map.put("가을", R.drawable.fall);
            map.put("겨울", R.drawable.winter);
         
            map.put("09", R.drawable.year09);
            map.put("10", R.drawable.year10);
            map.put("11", R.drawable.year11);
            map.put("12", R.drawable.year);
            map.put("13", R.drawable.year13);
            map.put("14", R.drawable.year14);
            map.put("15", R.drawable.year15);
        }
                 
        return map;
    }



이렇게 해주면 처음 값이 불릴 때 map이 null 이기 때문에 map.put 이 실행되고 


다음에 다시 값이 불릴 때는 map에 값이 들어있기 때문에 if( map == null) 을 실행하지 않고 바로 map을 반환한다.


이렇게 되면 처음 한번만 실행되고 그 이후에는 갖다 쓰기만 하면 된다.


이런 방식을 싱글톤 방식?이 있다고 하는데 이것도 해당하는 건지 모르겟다.


그냥 이런 방법도 있구나 하고 알아볼 수 있는 시간이었다.




반응형
반응형




안드로이드 체크박스를 이용하여 액티비티간 값 전달하기


필요한 코드만 적어서 이대로 실행하면 에러가 나므로 알맞게 수정이 필요함


check.xml 에 체크박스 선언



<CheckBox
    android:id="@+id/option1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="15sp" />

<CheckBox
    android:id="@+id/option2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="15sp" />



CheckActivity.java 에서 체크했을 때 동작 코드 추가


public class CheckActivity implements OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);// 액티비티 생성 setContentView(R.layout.check);// check.xml //버튼 선언 Button button=(Button)findViewById(R.id.button_result); button.setOnClickListener(this); // option1 체크박스가 눌렸을 때 findViewById(R.id.option1).setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { Checked(v); // 체크되었을 때 동작코드 } }); // option2 체크박스가 눌렸을 때 findViewById(R.id.option2).setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { Checked(v); // 체크되었을 때 동작코드 } }); } public String Checked(View v) { // 체크되었을 때 동작할 메소드 구현 // TODO Auto-generated method stub CheckBox option1 = (CheckBox) findViewById(R.id.option1); // option1체크박스 // 선언 CheckBox option2 = (CheckBox) findViewById(R.id.option2); // option1체크박스 // 선언 String resultText = ""; // 체크되었을 때 값을 저장할 스트링 값 if (option1.isChecked()) { // option1 이 체크되었다면 resultText = "option1"; } if (option2.isChecked()) { resultText = "option2"; // option2 이 체크되었다면 } return resultText; // 체크된 값 리턴 } @Override public void onClick(View v) { if (v.getId() == R.id.button_result) { //button_result 이라는 버튼이 생성되었다고 가정. Intent it = new Intent(this, MainActivity.class); // MainActivity.java로 보내기 위한 인텐트 선언 it.putExtra("it_check", Checked(v)); // it_check 라는 이름하에 체크된 값을 전달 startActivity(it); // MainActivity.java를 실행하면서 값을 전달 } } }



MainActivity.java에서 값 전달 받기



public class MainActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);//액티비티 생성 setContentView(R.layout.main);//main.xml Intent it=getIntent(); //인텐트 받기 선언 //이전에 보냈던 it_check의 값을 받아 str에 저장 String str= it.getStringExtra("it_check"); //즉 str = "option1" 또는 "option2" 가 들어있음 //이 값을 이용하여 필요한 동작 구현 if(str.equals("option1"){ //str 값이 option1 이라면 //필요한 동작 코드 작성 }else if(str.equals("option2"){ //str 값이 option2 라면 //필요한 동작 코드 작성 } } }


동작 순서는 check.xml -> CheckActivity.java -> MainActivity.java 이렇게 된다






반응형
반응형




Android library projects cannot be launched 에러가 발생한다면


프로젝트 우클릭 > propertise > Android 탭을 보면 다음과 같은 화면이 나타나는데


Is Libaray 체크 해제해주면 된다.



반응형
반응형

참고링크

http://biig.tistory.com/37


당황하지 않고

로그캣에서


Caused by: java.lang.NullPointerException: println needs a message

at android.util.Log.println_native(Native Method)

at android.util.Log.d(Log.java:138)

at com.example.eerrortest.MainActivity.onCreate(MainActivity.java:16)



Caused by 부분을 주목하고 그 밑에 해당 액티비티에 에러 라인을 보고 해결하면된다.

반응형
반응형





그냥 간단하게 사진 자르기 해서 이미지 넣으려고 했는데


킷캣에서 부터 팅기는 현상이 발생했다.



팅기는 영상.



정말 뜬금없다. 킷캣 전부터는 쭉 잘 되던거였는데... 


웃긴 건 이상하게 특정사진만 자르면 팅긴다. 원본사진은 100kb밖에 안되는 사진인데도 말이다.


도대체 원인 뭔지 한참을 찾아헤맸다.


어찌어찌 해결을 됐는데 완벽한 해결책은 아니다..


킷캣문제인가 해서 찾아보기도 하고..


참고한 링크들이다.


http://blog.tstore.co.kr/107


https://plus.google.com/112692779577336772166/posts/9MbmSsUcd1e


http://www.androidside.com/plugin/mobile/board.php?bo_table=B49&wr_id=81704


안드로이드 사이드 위 글을 보고 해결을 했다.


사진 크롭 코드를 보면 이런 부분이 있다.

기존 코드는 이렇게 되어있었는데


intent.putExtra("outputX", 120);

intent.putExtra("outputY", 130);


안드로이드사이드 글에서 이게 문제라는 댓글을 보았다.



그래서 저 숫자를 

intent.putExtra("outputX", 100);

intent.putExtra("outputY", 100);


100로 작게 바꿔주었다.


그랬더니?? 신기하게 팅기지가 않는다. 최소한 내 폰에서는...



그래서 임시방편으로나마 해결을 했는데 찜찜하다.

다른 폰에서는 자르기는 되는데 자른 이미지가 깨진건지 안나온다;;;



찾아보면서 얻은 결론은


 메모리 부족으로 발생하는 것이다.

 바인더 Intent에 1MB 이상의 데이터를 넘기게되면 발생할 수 있다.

보통 제공되는 크롭을 사용하게 되면 발생하므로 이미지 크롭의 경우 직접 구현해서 사용하는게 낫다는 의견

하지만 직접 구현할 능력이..;; 그리고 찾아본 예제들은 거의 다 기본 제공 크롭소스이다..



마지막으로 위 영상의 예제 코드를 올린다.

아마도 다 이 코드를 쓸 것이다. 퍼질대로 퍼진 대중적인 코드(xml은 제외)



package com.example.camera

import java.io.File;
import com.example.camera.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends Activity implements OnClickListener {
	private ImageView mPhotoImageView;// 이미지 받기
	private ImageView foot;
	private Uri mImageCaptureUri;

	private static final int PICK_FROM_CAMERA = 0;
	private static final int PICK_FROM_ALBUM = 1;
	private static final int CROP_FROM_CAMERA = 2;
	LinearLayout bar, mother = null;
	FrameLayout container = null;
	Bitmap bm = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Button mButton = (Button) findViewById(R.id.load);
		mPhotoImageView = (ImageView) findViewById(R.id.profile);
		mButton.setOnClickListener(this);
	}

	private void doTakePhotoAction() {
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

		// 임시로 사용할 파일의 경로를 생성
		String url = "tmp.jpg";

		mImageCaptureUri = Uri.fromFile(new File(Environment
				.getExternalStorageDirectory(), url));

		intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT,
				mImageCaptureUri);

		// 특정기기에서 사진을 저장못하는 문제가 있어 다음을 주석처리 합니다.
		// intent.putExtra("return-data", true);
		startActivityForResult(intent, PICK_FROM_CAMERA);

	}

	private void doTakeAlbumAction() {
		// 앨범 호출
		Intent intent = new Intent(Intent.ACTION_PICK);
		intent.setType(android.provider.MediaStore.Images.Media.CONTENT_TYPE);
		startActivityForResult(intent, PICK_FROM_ALBUM);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode != RESULT_OK) {
			return;
		}

		switch (requestCode) {
		case CROP_FROM_CAMERA: {
			// 크롭이 된 이후의 이미지를 넘겨 받습니다.
			// 이미지뷰에 이미지를 보여준다거나 부가적인 작업 이후에
			// 임시 파일을 삭제합니다.
			final Bundle extras = data.getExtras();

			if (extras != null) {
				Bitmap photo = extras.getParcelable("data");
				mPhotoImageView.setImageBitmap(photo);
			}

			// 임시 파일 삭제
			File f = new File(mImageCaptureUri.getPath());
			if (f.exists()) {
				f.delete();
			}

			break;
		}

		case PICK_FROM_ALBUM: {
			// 이후의 처리가 카메라와 같으므로 일단 break없이 진행합니다.
			// 실제 코드에서는 좀더 합리적인 방법을 선택하시기 바랍니다.

			mImageCaptureUri = data.getData();
		}

		case PICK_FROM_CAMERA: {
			// 이미지를 가져온 이후의 리사이즈할 이미지 크기를 결정합니다.
			// 이후에 이미지 크롭 어플리케이션을 호출하게 됩니다.

			Intent intent = new Intent("com.android.camera.action.CROP");
			intent.setDataAndType(mImageCaptureUri, "image/*");

			intent.putExtra("outputX", 120);
			intent.putExtra("outputY", 130);
			// intent.putExtra("aspectX", 1);
			// intent.putExtra("aspectY", 1);
			intent.putExtra("scale", true);
			intent.putExtra("return-data", true);

			startActivityForResult(intent, CROP_FROM_CAMERA);

			break;
		}
		}
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.load) {
			DialogInterface.OnClickListener cameraListener = new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					doTakePhotoAction();
				}
			};

			DialogInterface.OnClickListener albumListener = new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					doTakeAlbumAction();
				}
			};

			DialogInterface.OnClickListener cancelListener = new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
			};

			new AlertDialog.Builder(this).setTitle("업로드할 이미지 선택")
					.setPositiveButton("사진촬영", cameraListener)
					.setNeutralButton("앨범선택", albumListener)
					.setNegativeButton("취소", cancelListener).show();

		}

	}
}




팅길 때 찍힌 로그.



12-14 20:59:51.831: E/JavaBinder(1242): !!! FAILED BINDER TRANSACTION !!!

12-14 20:59:51.831: I/ActivityManager(1242): Restarting because process died: ActivityRecord{42d64570 u0 com.example.camera/.MainActivity t1511}

12-14 20:59:51.831: D/AlwaysOnTopManagerService(1242): setRearTouchLongPress(): flag = false, mIsLongPress = false

12-14 20:59:51.851: W/WindowManager(1242): view not successfully added to wm, removing view

12-14 20:59:51.861: E/JavaBinder(1242): !!! FAILED BINDER TRANSACTION !!!

12-14 20:59:51.861: W/ActivityManager(1242): Exception when starting activity com.example.camera/.MainActivity

12-14 20:59:51.861: W/ActivityManager(1242): android.os.TransactionTooLargeException

12-14 20:59:51.861: W/ActivityManager(1242): at android.os.BinderProxy.transact(Native Method)

12-14 20:59:51.861: W/ActivityManager(1242): at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:761)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1072)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1168)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStack.resumeTopActivityLockedInner(ActivityStack.java:2327)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1482)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2196)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1077)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:964)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:5364)

12-14 20:59:51.861: W/ActivityManager(1242): at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:427)

12-14 20:59:51.861: W/ActivityManager(1242): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2159)

12-14 20:59:51.861: W/ActivityManager(1242): at android.os.Binder.execTransact(Binder.java:404)

12-14 20:59:51.861: W/ActivityManager(1242): at dalvik.system.NativeStart.run(Native Method)

12-14 20:59:51.872: D/WindowManager(1242): win:Window{435b3a88 u0 com.example.camera/com.example.camera.MainActivity}mOemFlagWin:null,mSaveOemFlags:0,mCurrentFocus:Window{449c9898 u0 com.android.gallery3d/com.android.gallery3d.filtershow.crop.CropActivity}

12-14 20:59:51.882: I/ActivityManager(1242): Start proc com.example.camera for activity com.example.camera/.MainActivity: pid=6109 uid=10007 gids={50007}

12-14 20:59:51.882: D/ActivityManager(1242): checkHideDockBarApplication.result = NOK

12-14 20:59:51.892: D/dalvikvm(6109): Late-enabling CheckJNI

12-14 20:59:51.922: D/dalvikvm(6109): Debugger has detached; object registry had 1 entries

12-14 20:59:51.922: E/JavaBinder(1242): !!! FAILED BINDER TRANSACTION !!! 


위 로그를 보고 어느 분이 달아주신 댓글..


TransactionTooLargeException 발생한거네요..
바인더 Intent에 1MB 이상의 데이터를 넘기게되면 발생할 수 있습니다.
보통 제공되는 크롭을 사용하게 되면 발생하구요.. 이미지 크롭의 경우 직접 구현해서 사용하는게 낫습니다.


나중에 좀 더 완벽한 해결책을 적용할 수 있으면 좋겠다.




반응형

+ Recent posts