Android 2013. 7. 26. 10:27

프로젝트를 진행하다보면 거의 모든 매소드에 로그를 사용하는데 


개발중엔 상관없지만 배포 할 때 로그를 안나오게 하는것이 바람직합니다.


이 때, 수 십개의 클래스를 돌아다니며 로그를 지우는 것도 일이지만 


만약 배포 후 버그가 나온다면 지웠던 로그를 다시 작성해야 되는 일이 생깁니다.


이런 불상사를 방지하는 방법이 로그 클래스를 만들어 관리를 해주는 것입니다. 


public class RbLog {

	/** Disable Debug */
	// public static boolean D = false;

	/** Enable Debug */
	public static final boolean D = true;

	public static void d(String tag, String msg) {
		if (D && tag != null && msg != null)
			Log.d(tag, msg);
	}

	public static void d(Activity activity, String msg) {
		if (D && activity != null && msg != null)
			Log.d(activity.getLocalClassName(), msg);

	}
}

위와 같이 d 라는 로그찍는 매소드를 만들어 static으로 선언하게 되면 



RbLog.d(TAG, "Log Test");


이렇게 로그형식으로 똑같이 사용 할 수 있게 됩니다.


개발을 완료하고 배포할 때 boolean형태의 D 변수를 false로 활성화시키면 


d 매소드 조건문에 의하여 if를 통과 못하게되고 모든 로그가 찍히지 않게됩니다. 


버그가 발견되어 다시 디버그를 하고싶을 땐 true로만 바꿔주면 곳곳에 심어놨던 로그들이


다시 찍히게 됩니다. 


추가로 i, e 등의 매소드도 만들어 사용 할 수 있습니다.

posted by 젊은쎄오
:
Android 2013. 7. 25. 16:09

프로젝트 진행 중에 어레이어답터를 커스텀으로 사용해야 할 일이 자주 생겨 


기본적으로 필요한 틀을 만들어 놓은것을 공유합니다. 






필요한 자바파일은 


- 리스트뷰가 있는 MainActivity 

- BaseAdapter를 상속 받고있는MainListAdapter

- 콘텐츠가 들어있는 ExamEntity 


필요한 xml 파일은 


- MainActivity의 Layout인 activity_main.xml 

- 리스트 row를 구성 할 item_row.xml


입니다. 


< MainActivity>

public class MainActivity extends Activity {

	private final String TAG = "MainActivity";

	// list
	private ListView lv_main;
	private ArrayList mExamItemArrayList;
	private MainListAdapter mMainListAdapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Log.d(TAG, "onCreate");

		viewInit();
		setContent();
	}

	/**
	 * init mainview
	 */
	private void viewInit() {

		Log.d(TAG, "viewInit");

		lv_main = (ListView) findViewById(R.id.lv_main);

		mExamItemArrayList = new ArrayList();
		mMainListAdapter = new MainListAdapter(getApplicationContext(),
				mExamItemArrayList, R.layout.item_row);

		lv_main.setAdapter(mMainListAdapter);

	}

	/**
	 * set content
	 */
	private void setContent() {
		Log.d(TAG, "setContent");

		for (int itemCount = 0; itemCount < 20; itemCount++) {
			ExamEntity mExamEntity = new ExamEntity();

			mExamEntity.title = "Title : " + itemCount;
			mExamEntity.content = "Content : " + itemCount;

			mExamItemArrayList.add(mExamEntity);

		}

		mMainListAdapter.notifyDataSetChanged();

	}

}


MainActivity에선 기본적은 어답터와 리스트뷰 연결 등의 초기 작업을 하고


setContent 매소드를 통하여 entity에 리스트 row에 뿌릴 콘텐츠를 저장합니다. 




<MainListAdapter>

public class MainListAdapter extends BaseAdapter {

	final String TAG = "MainListAdapter";

	public Context mContext;
	private ArrayList mExamItemArrayList;
	private LayoutInflater mLayoutInflater;
	int resource;

	public MainListAdapter(Context context,
			ArrayList mExamItemArrayList, int resource) {
		mContext = context;
		this.mExamItemArrayList = mExamItemArrayList;
		this.mLayoutInflater = (LayoutInflater) context
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		this.resource = resource;
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mExamItemArrayList.size();
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(final int position, View convertView, ViewGroup parent) {

		Holder holder = new Holder();
		if (convertView == null) {
			convertView = mLayoutInflater.inflate(resource, null);

			// find resource

			holder.tv_title = (TextView) convertView
					.findViewById(R.id.tv_title);
			holder.tv_content = (TextView) convertView
					.findViewById(R.id.tv_content);
			convertView.setTag(holder);

		} else {
			holder = (Holder) convertView.getTag();
		}

		// set content
		String title = mExamItemArrayList.get(position).title;
		String content = mExamItemArrayList.get(position).content;
		holder.tv_title.setText(title);
		holder.tv_content.setText(content);

		// set click listener
		holder.tv_title.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				Toast.makeText(mContext,
						mExamItemArrayList.get(position).title,
						Toast.LENGTH_SHORT).show();

			}
		});

		holder.tv_content.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(mContext,
						mExamItemArrayList.get(position).content,
						Toast.LENGTH_SHORT).show();

			}
		});

		return convertView;
	}

	private class Holder {
		TextView tv_title, tv_content;
	}

}

MainListAdapter에선, row에서 쓸 텍스트뷰를 선언하고 MainActivity에서 넘겨받은 


ArrayList를 이용하여 ExamEntity의 콘텐츠들을 꺼내어 쓰게됩니다.



<ExamEntity>

public class ExamEntity {

	public String title;
	public String content;

}

기본적인 entity입니다. setter와 getter를 추가 할 수 있습니다. 




위 기본틀을 붙여놓고 필요에 따라 리스트 row를 구성하는 row.xml을 수정하고 


그에 맞게 entity, holder, getView()매소드를 수정하여 원하는 리스트뷰를 구성 할 수 있습니다.







소스 첨부 합니다.




ListAdapterExample.zip









posted by 젊은쎄오
:
Android 2013. 7. 9. 17:48

자동 로그인 여부, 또는 설정에서 저장했던 값 등


앱이 종료되어도 보존되어야 하는 데이터를 저장할 때 


흔히 SharedPreferences를 사용한다. 


	SharedPreferences pref = mContext.getSharedPreferences(com.exam.pref,
				Activity.MODE_PRIVATE);
	SharedPreferences.Editor editor = pref.edit();
	editor.putString("key", value);
	editor.commit();


보통 이런식으로 사용하는데 이는 키 값을 수정 할 일이 있거나


찾을 일이 있을 때 따로 키 목록을 작성해 


놓은 곳이 없다면 나중에 관리가 힘들어지는 단점이 있다. 




그래서 아예  Preference 클래스를 하나 만들어 두고 그 클래스에 


int, String, boolean을 담고 꺼내는 getter, setter 매소드와 


사용하는 키 값을 모두 선언하여 


클래스에 점만 찍으면 키, 저장, 꺼내쓰기가 가능하도록 하였다. 



public class RbPreference {

	private final String PREF_NAME = "com.rabiaband.pref";

	public final static String PREF_INTRO_USER_AGREEMENT = "PREF_USER_AGREEMENT";
	public final static String PREF_MAIN_VALUE = "PREF_MAIN_VALUE";
	

	static Context mContext;

	public RbPreference(Context c) {
		mContext = c;
	}

	public void put(String key, String value) {
		SharedPreferences pref = mContext.getSharedPreferences(PREF_NAME,
				Activity.MODE_PRIVATE);
		SharedPreferences.Editor editor = pref.edit();

		editor.putString(key, value);
		editor.commit();
	}

	public void put(String key, boolean value) {
		SharedPreferences pref = mContext.getSharedPreferences(PREF_NAME,
				Activity.MODE_PRIVATE);
		SharedPreferences.Editor editor = pref.edit();

		editor.putBoolean(key, value);
		editor.commit();
	}

	public void put(String key, int value) {
		SharedPreferences pref = mContext.getSharedPreferences(PREF_NAME,
				Activity.MODE_PRIVATE);
		SharedPreferences.Editor editor = pref.edit();

		editor.putInt(key, value);
		editor.commit();
	}

	public String getValue(String key, String dftValue) {
		SharedPreferences pref = mContext.getSharedPreferences(PREF_NAME,
				Activity.MODE_PRIVATE);

		try {
			return pref.getString(key, dftValue);
		} catch (Exception e) {
			return dftValue;
		}

	}

	public int getValue(String key, int dftValue) {
		SharedPreferences pref = mContext.getSharedPreferences(PREF_NAME,
				Activity.MODE_PRIVATE);

		try {
			return pref.getInt(key, dftValue);
		} catch (Exception e) {
			return dftValue;
		}

	}

	public boolean getValue(String key, boolean dftValue) {
		SharedPreferences pref = mContext.getSharedPreferences(PREF_NAME,
				Activity.MODE_PRIVATE);

		try {
			return pref.getBoolean(key, dftValue);
		} catch (Exception e) {
			return dftValue;
		}
	}
}


위와 같이 상단에 각각 사용할 키를 선언하고 타입별로 같은 이름의 setter,getter 매소드를


만들어 놓으면 어디서든 위 클래스를 이용하여 해당키와 한가지 매소드로 원하는 작업 수행이 가능하다.



RbPreference pref = new RbPreference(this);

// set
pref.put(RbPreference.PREF_USER_AGREEMENT, true);

// get
pref.getValue(RbPreference.PREF_USER_AGREEMENT, false);


이런식으로 사용된다. 


posted by 젊은쎄오
:
Android 2013. 5. 6. 23:55

sns에서 자주보이는 현재 보여지는 글이 쓰여진 시점부터 


지금까지의 시간을 표현하는 방법이다. 


출처는 http://gubok.tistory.com/227 여기이고 아래는 소스이다. 



private static class TIME_MAXIMUM{
        public static final int SEC = 60;
        public static final int MIN = 60;
        public static final int HOUR = 24;
        public static final int DAY = 30;
        public static final int MONTH = 12;
}


public static String formatTimeString(Date tempDate) {

	long curTime = System.currentTimeMillis();
	long regTime = tempDate.getTime();
	long diffTime = (curTime - regTime) / 1000;

	String msg = null;
	if (diffTime < TIME_MAXIMUM.SEC) {
			// sec
		msg = "방금 전";
	} else if ((diffTime /= TIME_MAXIMUM.SEC) < TIME_MAXIMUM.MIN) {
		// min
		msg = diffTime + "분 전";
	} else if ((diffTime /= TIME_MAXIMUM.MIN) < TIME_MAXIMUM.HOUR) {
		// hour
		msg = (diffTime) + "시간 전";
	} else if ((diffTime /= TIME_MAXIMUM.HOUR) < TIME_MAXIMUM.DAY) {
		// day
			msg = (diffTime) + "일 전";
	} else if ((diffTime /= TIME_MAXIMUM.DAY) < TIME_MAXIMUM.MONTH) {
		// day
	        msg = (diffTime) + "달 전";
	} else {
		msg = (diffTime) + "년 전";
	}

	return msg;
}



이 부분만 있으면 구현 가능하다. 


그러나 나는 날짜가 yyyy-mm-dd hh:mm:ss format의 String형식으로  


넘어오고 있었기 때문에 이 String을 위와 같은 format의 Date 변수로 변환하는 부분이 필요했다.


String stringDate = "2013-05-06 14:42:00";
java.text.SimpleDateFormat format = new java.text.SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");
java.util.Date date = format.parse(stringDate);


위와 같이 format 형태를 상황에 맞게 만들어 date형태로 변환해 준 다음 


파라미터로 넘겨주면 알맞은 리턴값이 돌아오게 된다. 



posted by 젊은쎄오
:
Android 2013. 5. 6. 23:23

일반적으로 안드로이드에서 텍스트의 컬러를 바꿀때 TextView를 잡아 컬러를 주는데 


이 방법의 단점은 TextView 전체가 한 가지 컬러로 바뀐다는 점이다.


그래서 SpannableStringBuilder를 사용하여  String 변수의 시작점과 끝점을 잡아 


사이값의 컬러를 바꿔줄수있다. 



 
String originText = "과일 상자에 수박을 담아가셨습니다.";
SpannableStringBuilder mSpannableStringBuilder = new SpannableStringBuilder(originText);
mSpannableStringBuilder.setSpan(new ForegroundColorSpan(0xFF04478f), 7,
					originText.length() - 10,
					Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textview.append(mSpannableStringBuilder);


setSpan(Object what, int start, int end, int flags) Mark the specified range of text with the specified object. 


API에는 이렇게 나와있다. 


각각 스타일, 시작점, 끝점, flag 인데 flag를 아직 잘 모르겠다. 구글링 해보니 앞뒤속성 관련 


값 같은데 바꿔도 결과가 같아서 자세히 알아보고 문서 수정보완 해야겠다.


첫번째 자리에 컬러 값이 아닌 


new AbsoluteSizeSpan(10) 이런식으로 넣으면 그 부분만 글자 크기가 달라진다. 


동시 적용하고 싶음 두 줄을 호출하면 된다. 


마지막으로 textview에 setText가 아닌 append 라는게 특이하다. 


결과는 


과일 상자에 수박을 담아가셨습니다.



posted by 젊은쎄오
:
Android 2013. 4. 15. 17:36

EditText 에서 사용하는 hint 속성 주는 방법입니다. 



- hint Color

 android:textColorHint="#ff000000" 


- hint Size ( hint 사이즈는 텍스트 사이즈를 따라갑니다.)

 android:textSize="12sp" 


posted by 젊은쎄오
:
Android 2013. 4. 10. 10:03

xml에서 뷰들에 색을 넣는 방법엔 


android:background="#ff0000ff" 이런식으로 사용합니다. 


이걸 자바 소스에서 사용하는 방법입니다.



 

 textview.setTextColor(0xFF0000ff); 


posted by 젊은쎄오
:
JAVA 2013. 2. 7. 11:10

사용이유 

- 로그인 정보와 같이 고유한 값이 필요할 때 여기저기서 new 로 생성하지않고 

A a = new A.getInstance(); 로 호출하여 고유값을 공유한다.


이렇게 호출 시 최초 호출에  A클래스의 인스턴스 공간이 생성되고 

이 후 호출 시에는 최초 호출한 인스턴스를 가져온다. 


지정한 클래스 인스턴스가 절대로 한개밖에 존재하지 않는것을 보증하고 싶을경우.


데이터 공유용으로는 잘못된사용. 



http://underclub.tistory.com/436

'JAVA' 카테고리의 다른 글

JAVA] 간단한 상속 개념 정리  (0) 2014.02.09
JAVA] 현재 날짜, 시간 구하기  (1) 2011.11.30
JAVA] split으로 문자열 나누기  (0) 2011.10.17
JAVA] 22. 인터페이스 - 1  (0) 2011.08.19
JAVA] drawRect 속성 알아보기  (1) 2011.08.18
posted by 젊은쎄오
:
Android 2012. 10. 8. 17:47
안드로이드 모바일에서 이미 개발된 모바일 웹을 웹뷰로 띄워야 할 때가 있습니다. 


기본 모바일 웹 페이지만 띄우는 작업이면 상관이없는데 


 이 모바일 페이지에서 전화를 건다거나 동영상을 재생한다면 안드로이드는 동작을 안하게되죠 


지금 떠있는 것은 웹뷰이고 웹뷰는 동영상이나 전화거는 뷰가 아니기때문입니다. 


그래서 url을 가지고 동영상, 전화, 메일등을 가려내 해당 뷰로 넘겨주어 


 굳이 모바일 웹쪽을 수정하지않아도 앱단에서 해결 할 수 있는 방법입니다.

 
	private class HelloWebViewClient extends WebViewClient {
		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {
			String origin_url = url;
			String temp_url = origin_url.substring(origin_url.length() - 3,
					origin_url.length());

			if (temp_url.equals("mp4")) {
				
				// 동영상 플레이어로 재생하기 
				
				Intent i = new Intent(Intent.ACTION_VIEW);
				Uri uri = Uri.parse(url);
				i.setDataAndType(uri, "video/mp4");
				startActivity(i);
			} else if (origin_url.startsWith("tel:")) {

				// 전화 걸기 

				Intent call_phone = new Intent(Intent.ACTION_VIEW,
						Uri.parse(origin_url));
				// 현재의 activity 에 대해 startActivity 호출
				startActivity(call_phone);
				return true;

			} else if (origin_url.startsWith("mailto:")) {
				
				// 이메일 보내기 
				
				String email = origin_url.replace("mailto:", "");
				final Intent intent = new Intent(
						android.content.Intent.ACTION_SEND);
				intent.setType("plain/text");
				intent.putExtra(android.content.Intent.EXTRA_EMAIL,
						new String[] { email });
				intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "제목");
				intent.putExtra(android.content.Intent.EXTRA_TEXT, "내용");
				startActivity(Intent.createChooser(intent, "이메일 전송"));

			} else {
				
				// 기본 웹 페이지 넘어가기 
				
				view.loadUrl(url);
			}

			return true;
		}
	}



(2012 10 14 에 내용 추가 )


http://가 아닌 rtsp://로 시작하는 mp4 영상파일은 위 방법으로 재생이 되지않습니다. 

 
if (temp_url.endsWith("mp4")) {
				// 동영상 플레이어로 재생하기
				try {
					Intent i = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
					startActivity(i);
				} catch (URISyntaxException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}


이런 식으로 타입지정하는  i.setDataAndType(uri, "video/mp4"); 이부분을 빼주셔야 재생이 됩니다.





추가로 띄우는 웹 페이지의 크기가 클 때 전체화면에 딱 차게 뜨는 코드도 추가합니다.
 
mWebView = (WebView) findViewById(R.id.MainWebview);
		mWebView.getSettings().setJavaScriptEnabled(true);

		// 웹뷰에 줌 달기
		mWebView.getSettings().setBuiltInZoomControls(true);

		// 웹뷰에 딱맞게 페이지 크기조절
		final WebSettings webSetting = mWebView.getSettings();
		webSetting.setLoadWithOverviewMode(true);
		webSetting.setUseWideViewPort(true);

		mWebView.loadUrl("http://www.naver.com");
		mWebView.setWebViewClient(new HelloWebViewClient());


posted by 젊은쎄오
:
IPhone 2012. 8. 27. 18:10

안드로이드에서는 finish(); 면 되던것이 아이폰에선 복잡하네요 


기본적으로 오브젝티브 C도 익숙치 않아 그냥 따라하기식으로 만들고있습니다.


우선 viewController.h 문서에 스토리보드에서 그린 버튼을 등록합니다.



아래와 같이 버튼에서 소스로 우클릭 드래그를 한 뒤 손을 떼면 


아래와같은 해당 버튼을 컨트롤할 변수명 적는 곳이 나옵니다. 


입력 후 엔터를 치면 자동으로 삽입됩니다.




삽입 한 후 backButton 이라는 매소드를 만들고 해당 매소드 좌측에 빈 동그라미를 클릭하여


버튼으로 링크를 걸어 줍니다. 그럼 이 backButton 이란 매소드는 뒤로가기 버튼의


클릭 리스너 매소드가 됩니다. 




이제 viewController.m 문서로 와서 backButton 매소드를 만든 뒤 



[self.navigationController popViewControllerAnimated:YES]; 이 줄을 


매소드에 추가하면 버튼 눌렀을 때 뒤로가게 됩니다. 














posted by 젊은쎄오
: