블로그 이미지
매몰

모바일 어플리케이션 개발 1인 기업 고영진모바일입니다. 저와 함께 맛깔스러운 앱을 만들어 보아요~

Rss feed Tistory
개발/android 2019.01.17 17:27

EditText에 자동으로 단위 콤마 넣기



NumberFormat 을 이용하면 숫자에 단위 콤마를 쉽게 찍을수 있다.


하지만 이를 EditText에 적용할려고 하면 한가지 문제가 생긴다.


입력할때마다 콤마가 찍혀야 하는데...

addTextChangedListener에서 NumberFormat으로 콤마를 찍으면 당연히 텍스트가 변경되므로 다시 리스너가 호출된다. 즉, 호출이 무한 반복되면서 앱이 멈추게 된다.


그래서 살짝 꼼수를 부려봤다.


EditText 밑에 같은 크기의 TextView를 깔고 여기에 콤마를 찍은 텍스트를 대신 써주고,

후에 EditText를 동기화 하는 것이다. 물론, EditText는 투명하게 설정해 안보이게 한다.


사실 임시 방편으로 만든것인데.. 생각보다 잘 작동해 계속 쓰고 있다 ㅎㅎㅎ



소스는 다음과 같다. 요즘 뜨고 있다는 코틀린으로 작성했다~


class NumberEditText: RelativeLayout {

private var editText: EditText
private var textView: TextView

init {
editText = EditText(context)
textView = TextView(context)

initBase()
}

constructor(context: Context): super(context) {
editText = EditText(context)
textView = TextView(context)

initBase()
}

private fun initBase() {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)

//EditText가 안보이도록 투명 처리한다
editText.setTextColor(Color.TRANSPARENT)
editText.setBackgroundColor(Color.TRANSPARENT)
editText.gravity = gravity

textView.gravity = gravity

//TextView 위에 EditText를 생성한다
addView(textView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))
addView(editText, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))

editText.setOnTouchListener { view, motionEvent ->
//EditText를 터치하면 TextView의 내용을 동기화 한다
if (motionEvent.action == MotionEvent.ACTION_UP) {
//내용을 쓸때 입력 커서 위치가 변경되지 않도록 조정한다
val length = textView!!.text.length - (view as EditText).text.length
val selectionStart = view.selectionStart + length
val selectionEnd = view.selectionEnd + length

//내용을 쓰고 커서 위치를 조정한 후 적용되도록 포커스를 요청한다
view.setText(textView?.text)
view.setSelection(selectionStart, selectionEnd)
view.requestFocus()
}

false
}

editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {

}

override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

}

override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
//콤마를 찍어 TextView에 쓴다
textView.text = getNumberText(s.toString())
}
})
}

private fun getNumberText(text: String): String {
return if (text.length > 1) NumberFormat.getNumberInstance().format(text.replace(",", "").toDouble()) else text
}
}



수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요

사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
2018.12.23 11:39

유한하지만 끝이 없는... 시간의 역사


스티븐 호킹.. 그가 대단한것은 상상만으로 이론을 완성했다는 점이다.

손과 발이 자유롭지 못했으니 아마도 그림이나 도표 같은것을 그려보지 못하지 않았을까?


머리속의 생각을 손으로 직접 형상화 하지 않고 정리한다는것은 정말 어려운 일이다.

코딩을 할때도 알고리즘을 직접 작성해 보기 전에는 머리속으로 아무리 생각해봤자 이해하기 힘들다.


이런점에서 천재 물리학자인 그의 저서.. 시간의 역사는 특별하다.

고인이 되었지만 그의 상상이 우리에게 시간이란 무엇인가를 말해주고 있기 때문이다.





저자가 말하는 시간이란 한마디로 "유한하지만 경계가 없다"다. 이것을 무경계 이론이라 부른다.


그럼 유한하지만 경계가 없다라는 말은 대체 무슨 뜻일까?

솔직히 좀 모순된 이야기일수도 있다. 유한하지만 무한하다라는 말로도 이해되기 때문이다.

저자가 쉽게 풀어쓸려고 애를 썼지만 내가 머리가 나쁜지 완벽히 이해할수는 없었다.

그냥 언젠가는 끝이 오겠지만 그 끝이 전혀 특별하지 않는 또다른 시작일수도 있다. 다시 말해 시작과 끝이 있지만 그것이 별반 다른점이 없으니 둘을 나누는 것는 무의미하다. 정도로만 알아도 좋을듯 하다.





그밖에 블랙홀과 시간여행이 관심을 끄는 대목이다.


사실 블랙홀은 모든것을 빨아드리기만 하는건 아니라고 한다. 이런점을 저자는 블랙홀이 그다지 검지 않다라고 표현한다. 에너지를 내뿜기도 한다는 것이다. 


우주의 빈공간은 수많은 입자와 반입자로 꽉차있다. 이 입자와 반입자는 한쌍으로 합쳐져 소멸하고 다시 분리되어 생성되기를 반복하여 실제로는 없는것 처럼 느껴진다. 하지만 만약, 블랙홀로 입자와 반입자중 하나가 떨어진다면, 나머지 한쪽은 짝을 잃어 소멸되지 않고 남아있게 된다. 이것이 마치 블랙홀의 복사에너지처럼 보이게 된다. 원래 사라져야 할 물질이 남아있으니 에너지가 방출된 꼴이 된것이다.





시간여행은 가능할까? 결론부터 말하자면 이론적으로는 가능하다.

빛보다 빠른 물질은 없기 때문에 일반적으로는 불가능하지만 휘어 있는 시공을 통한다면 가능하다는 것이다.


이러한 시공을 벌레구멍이라고 한다. 실제로 이것은 소설이 아니라 과학적으로 증명된 것이라고 한다.

물론, 발견할수 있다면 말이다.


하지만 발견해도 다시 돌아오는 벌레구멍을 찾지 못할 가능성이 크기 때문에 시간여행을 했다는 모험담을 듣기는 힘들수 있다.



더 흥미진진한 내용이 책속이 있다. 한번 읽어보기 바란다. 후회하지 않을것이다.



수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요



사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
개발/php, javascript 2018.11.26 10:09

round()를 5의 배수로도 반올림 해보자



왜 반올림은 0으로만 할까?

0말고 다른수로도 반올림 해보는건 어떨까?


라는 생각을 가끔씩 해봤는데.. 솔직히 별 필요성을 느끼지 못했었다.

그런데 주식 관련한 로보어드바이저를 만들면서 필요해졌다. 호가를 찍을때 5단위가 되기 때문이다.


아래와 같이 php의 반올림 함수인 round()를 이용하여 5의 배수로 반올림 해주는 코드를 짜봤다.


원리는 굳이 설명안해도 될만큼 간단하다. 여기서 볼것은 round() 함수의 두번째 인수인 반올림 자릿수도 고려한다는 사실이다. 이러한 편리한 기능은 살려놔야 코딩하는 재미가 있다ㅎㅎ




function roundCenter($price, $precision) {

//지정한 자릿수로 반올림 (1)

$round = round($price, $precision);

//지정한 자릿수 이하가 5가 되도록 변경 (2)

$square = -$precision;

$digit = pow(10, $square);

$center = (floor($price / $digit) * $digit) + (5 * pow(10, $square -1));

//(1)과 (2)를 원래 숫자와 비교하여 더 가까운 것을 택함

return abs($price - $round) < abs($price - $center) ? $round : $center;

}




결과값으로 검증해 보자...


echo roundCenter(573424.2517, 3).'<br />';

echo roundCenter(573424.2517, 2).'<br />';

echo roundCenter(573424.2517, 1).'<br />';

echo roundCenter(573424.2517, 0).'<br />';

echo roundCenter(573424.2517, -1).'<br />';

echo roundCenter(573424.2517, -2).'<br />';

echo roundCenter(573424.2517, -3).'<br />';




출력...


573424.2515
573424.25
573424.25
573424.5
573425
573400
573500




위에서 보듯이 지정 자릿수가 3이면 소수점 3째짜리까지 나오거나 소수점 4째자리가 5인 수가 나온다.




수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요

사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
2018.10.20 22:01

진짜를 찾아라... 워렌 버핏의 재무제표 활용법


워렌 버핏. 주식에 관심이 없어도 한번쯤은 들어봤을 이름이다.

세계 부자 순위에 항상 올라오는 인물이기 때문이다.


그가 지은...줄 알고 샀지만 사실은 그의 며느리였던 메리 버핏이 12년동안 그를 지켜보면서 쓴 책이라고 한다. 조금은 실망스러웠지만 내용을 보니 역시 베스트셀러였다!! 전혀 손색이 없었다.




살짝 내용을 들려준다면... 지속성...

이 한단어면 충분히 설명될것 같다.





버핏이 부자가 될수 있었던 것은 일명.. "장기적인 경쟁우위"를 가진 기업에 투자했기 때문이다.

"장기적인 경쟁우위"란 오랫동안 다른 회사들보다 더 많은 돈을 번다는 뜻인데 이는 재무제표로 알수 있다.





예를 들면,

매출은 다른 회사보다 적지만 순이익률이 더 높다면 앞으로는(장기적으로는) 더 많은 돈을 번다는 증거이므로 경쟁우위를 가졌다고 본다.

또한 현금은 많지만 7년동안 채권, 주식 발행 또는 사업 매각을 많이 했다면 지속적 경쟁우위가 없다고 판단한다.





특히, 내가 받은 가장 값진 배움은 자기주식이다.

자기주식이란, 발행한(타인에게 판매한) 회사주식을 회사돈으로 다시 사드린것을 말하는데, 당연히 보유 현금을 줄게 해서 마치 재무제표가 안좋은것처럼 보이게 한다. 하지만 이는 곧 회사가 그만큼 재정적 여유가 있다는 증거이며, 지출할 배당금도 줄기 때문에 우량주의 판단 근거가 된다.





버핏은 또한 "채권성 주식"이란 말로도 유명하다.

채권처럼 앉아서 이자를 받아먹으면서도 주식처럼 수익률 높은 투자를 한다는 것인데

지속적인 경쟁우위에 있는 안정적인 기업을 장기간 보유해서 큰 수익을 낸다는 의미이다.






물론, 주식하는분들은 이게 말이야 쉽지 실제로 그러기 어렵다는것을 알것이다.

하지만 버핏은 그 어려운것을 해냈다. 즉, 불가능한 일은 아니라는것이다. 


진짜를 찾자. 느낌적인 느낌, 도박사의 느낌이 아니라 재무제표를 보고 진짜 좋은 투자감을 찾자.

이것이 버핏이 우리에게 해주고 싶은 말이 아닐까.


수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요


사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
개발/android 2018.09.27 13:30

sqlite의 time이 자정을 인식 못할 경우, 간단한 꼼수 해결법



안드로이드의 sqlite 데이터베이스를 사용하는 도중 이상한 점을 하나 발견했다.


time 데이터타입에서 00시 또는 24시, 즉 자정일때 time() 함수가 먹히질 않는다는 점이다.


예를 들면,

(time 데이터타입의 field1 시각 +  int 데이터타입의 field2 초) > 특정시각


을 비교할때


SELECT * FROM table1 WHERE time(field1, field2 ||' seconds') > 23:59:30

와 같이 사용한다.


하지만 이때, field1이 23:59:00 이고 field2가 60초 이상이면 자정이 넘어가면서 SELECT 결과가 항상 아무것도 안나오게 된다. field1이 24:00:00 이상이어도 마찬가지다.


이걸 해결하기 위해 만방으로 살펴봤지만... 역시 코딩은 꼼수가 최고다.


그냥... 자정이 넘어갈것 같으면 시간을 앞당겨주면 된다ㅎㅎ



다음과 같이 해보자~

private String getTime(String time, String addtime) {
return "time('" + time + "'" + addtime + ")";
}

private String getTime(String field, String addfield, String addtime) {
return "time(" + field + "," + addfield + "||' seconds'" + addtime + ")";
}

private Cursor fetch(SQLiteDatabase db, String time) {
//특정시각 time이 21시보다 크면 3시간을 앞당겨 준다.
String addText = Integer.parseInt(time.substring(0, 2)) < 22 ? "" : ",'-3 hours'";

return db.rawQuery("SELECT * FROM table1 WHERE " + getTime("field1", "field2", addText) + "<" + getTime(time, addText), null);
}

자정이 넘어 갔을때 시간을 앞당겨 비교해 주면 정상적으로 작동한다. 


수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요



사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
2018.08.27 17:36

수학적 편견... 대량살상 수학무기


사법부의 재판 거래가 사실로 밝혀지면서 차라리 인공지능한테 재판을 맡기자는 우스갯소리까지 나온다.

그만큼 사법부의 신뢰가 떨어졌다는 의미이다. 그렇다면 왜 하필 인공지능한테 맡기자는 말이 나왔을까? 인공지능은 신뢰할수 있다는 말인가? 아마 많은 사람들이 그렇게 생각할지도 모른다.





많은 사람들의 기대와는 달리, 인공지능의 근간인 알고리즘은 완벽하지 않다. 그 이유는 간단하다. 사람이 만들기 때문이다. IT업종의 종사자 특히, 프로그래머라면 이런한 불편한 진실을 너무나도 잘 알것이다. 기술력도 문제가 되겠지만 그보다는 편견과 조작하고 싶은 욕망이 그렇게 만든다. 즉, 애초부터 불평등이 프로그램되어 있을수 있다는 말이다. WMD, 이책에서 저자가 말하는 대량살상 수학무기가 바로 그런 경우다.





수학이 어떻게 대량살상하는 무기가 되었을까? 

수학 모형은 본질적으로 과거의 패턴이 반복될것이라는 가정이기 때문에 한계가 있는데도 마치 앞날을 다보여주는 것처럼 이용되고 있기 때문이다.





과거의 패턴을 이용하는것은 때로는 잔인하다. 만약 학자금 대출을 받아 졸업했다면 알고리즘은 또 대출을 받을거라 분석하고 대출 상품을 집중적으로 권할것이다. 즉, 다른이보다 대출 유혹을 더 받는다는 것이다.





잔인한데도 과거 패턴을 이용하는것은 순전히 효율성 때문이다. 범죄 예방 프로그램을 예로 보자. 불심검문을 할때 모든 지역을 대상으로 하기 보단 과거 범죄율이 높았던 지역만을 대상으로 하는것이 효율성 측면에서는 더 좋다. 더 적은 인력으로 더 많은 잠재 범죄자를 확인할 수 있으니 말이다. 하지만 범죄율이 높다는 것은 불심검문을 그만큼 많이 했다는 얘기도 된다. 다시 말해 과거 범죄율 때문에 더 많은 확인을 받게 되고 이는 다시 범죄율이 더 증가하는 악순환이 반복된다.


특히 알고리즘이 가난한 동네에서 많이 일어나는 경범죄를 다룬다면 이 지역 사람들은 불심검문으로 범죄자가 되어 취업이나 각종 사업에서 불이익을 받을 가능성이 커질 것이다.





물론 모든 인공지능 알고리즘이 수학무기가 된다는것은 아니다. 공공데이터를 이용하여 교통체증을 줄이는것은 누가 봐도 좋은일이기 때문이다. 그렇다면 수학무기는 뭐가 다른것일까? 그것은 대리 데이터다.


공공데이터는 직접적인 데이터다. 즉, 데이터 그 자체만으로도 교통체증을 파악할수 있다. 하지만 범죄율 하나만으로는 한 사람의 범죄를 파악할 수 없고 어림짐작만 할 수 있을뿐이다. 어림짐작으로 한사람의 인생을 바꾼다면 누가 봐도 나쁜일이지 않는가.





애석하게도 대리 데이터는 알고리즘에 많은 부분을 차지하고 있다. 사람의 일은 너무나도 복잡하고 영향을 여기저기서 받기 때문에 직접 데이터가 존재하기 힘들고 그나마 있는 데이터도 개인 정보법에 의해 나라에서 엄격하게 관리하기 때문이다. 그러니 사설업체에서는 대리데이터를 사용할수 밖에 없다.


개인 한사람이 아닌, 개인이 속한 부류를 찾아 나를 파악한다는 말이다. 내가 아무리 공부를 잘하고 돈 벌 능력이 있어도 가난하다고 알려진 곳에서 태어났다면 난 무능한 사람이 되는 것이다. 현대판 신분제가 아닐수 없다.





예전에는 사람들의 편견속에서 그래 왔다면, 이젠 인공지능으로 부터 확정을 받은 것이다. 더군다나 수학적으로 증명되었으니 편견이라고 오해라고 하소연 할수도 없게 되었다.


우리는 앞으로 사람을 닮은 인공지능, 아니 편견까지 닮은 인공지능을 상대해야 한다. 인공지능의 최종 목표는 사람이 되는것이기 때문이다. 


그렇다면 어떻게 상대해야 할까? 알고리즘을 투명하게 관리하는수밖에 없다. WMD의 가장 큰 문제점은 평가를 받는 우리들이 그 알고리즘에 대해 피드백을 취할 수 없는 점이다.


알고리즘의 원리는 무엇이며, 영향을 받는 요소는 어떻게 수집되며, 나와 관련된 정보는 제대로된 정보인지 투명하게 공개되어야 한다. 그리고 누구든지 이의를 제기하고 고칠수 있어야 한다.


강력한 무기를 사용할때는 도덕성과 민주주의가 필요하다. 알고리즘을 감시하자.


수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요




사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
개발/ios 2018.07.30 15:07

스레드에서 반복문으로 UI를 변경할때 주의할점



내가 만든 스레드에서 UI를 바꿀수 없다는것은 누구나 알것이다. 물론 젖먹이 개발자 시절에 난 몰랐다...


어잿든 내 스레드에서 UI를 바꿀려면 메인스레드를 호출해야 한다. ios 에서는 DispatchQueue.main.async 이 그 역활을 한다.


짐작했겠지만 메인스레드는 새로 만들어지는게 아니므로 당연히 동기적으로 움직인다. 


최근까지도 이 사실을 자주 망각했다. 바로 반복문에서 메인스레드를 호출할때였다.


내 스레드에서 메인스레드를 반복문으로 돌릴때는 서로가 따로 놀기 때문에 (내 스레드와 메인스레드가 서로 비동기라서) 메인스레드에서 UI가 아직 변경되지도 않았는데 내 스레드에서 또 호출해 버린다. 이렇게 되면 버벅거리는 현상이 발생한다.


테스트할때서야 버벅거림을 발견하고 짜증내다 아... 하고 숙연해 진적이 한둘이 아니었다.


아래를 보면 스레드에서 ui를 10번 갱신한다.

하지만 apply변수를 뺀다면 10번이 다 갱신 되지 않고 중간에 몇번은 건너뛰어 결국 일부만 실행되는것 처럼 보일것이다.



//스레드 시작

Thread(target: self, selector: #selector(runLoop), object: nil).start()



//스레드 실행 함수

@objc func runLoop() {

    var apply = true

    var count = 0

        

    while count < 10 {

        //메인스레드에서 작업이 완료되었을때만 실행

        if apply {

            //시작

            apply = false

            count += 1

                

            DispatchQueue.main.async {

                //ui 변경

                //...

                setNeedsDisplay()

                    

                //완료

                apply = true

            }

        }

    }

}




쉽게 말해 동기화를 해야 한다는 말이다.


알면서도 실수할수 있으니 항상 유념하자.



수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요





사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
2018.06.23 22:53

못판다 하면 안되갔구나... 나는 내성적인 영업자입니다




언제부터인가 내성적이란 단어가 나와 함께했다.


내성적이라 함은 나서기 싫어하고, 조용하고, 소극적이고, 혼자서 즐기는 것을 좋아하는 뭐 이런거 같다.

다 나에게 들어맞는 말이다ㅎㅎ


솔직히 커 가면서 내성적인것이 싫었다. 당연히 항상 중심에서 멀어져 있었고, 존재감도, 자신감도 없었기 때문이다. 또 외향적인 친구들을 보면 뭔가 멋져 보이기도 했다.


그래서 여기서 벗어나고자 나름 꽤나 노력했던것 같다. 어쩌면 지금도 그러는 중일지도 모른다.

하지만 번번히 실패했다. 맞지 않는 옷을 입은듯 왠지 불편해서 딱 어느선까지만 가고 막혔다.


실패에서 더 많은걸 배운다고 했던가ㅎ

자꾸 같은곳에서 거꾸러지면서 소중한 한가지를 배울 수 있었다. 


단점만 덮을려고 했지. 장점을 키울 생각은 안했구나...


따지고 보면 내성적이라서 얻은것도 많았다.

사람들의 주목을 받지 않았기 때문에 비교적 방해없이 내 일에 집중할 수 있었고,

왠만한건 혼자서 해결하다 보니 정신력도 강해졌다.


내가 지금 꿈을 꾸며 개발자의 길을 온전히 가게 해준것도 다 이 덕일지도 모르겠다.


그러는중 이책을 만났다. 신기하게도 살아온 날과 살아갈 날이 다 적혀 있는듯 했다...






취업이 아닌 창업을 택하면서 개발자이지만 영업은 피할수 없는 숙명이 되었다.

그런데 영업자의 자질은 역시 듣기 란다. 여기서 뿐만 아니라 다른 책에서도 종종 나오는 얘기다. 정말 중요한게 맞나 보다. 듣기는 내 특기인데 잘되었다ㅎㅎ 내성적인 사람들의 특기이기도 하다.







하지만 무작정 듣기만 한다고 다 되는것은 아니다.

말하는 사람의 의도를 잘 파악해주어야 한다.


진짜로 나를 비난할려고 화를 내는것인지...

고객문의를 받아보면 대부분이 화가 난듯하다... 하지만 그것은 비난할려고 하는게 아니라 고쳐달라는 것이다. 고객은 교양없고 무식하지 않다. 왜냐하면 나와 똑같은 인격체이기 때문이다. 그저 실망했을 뿐이다. 실망을 풀어주면 된다. 같이 싸우지 말고, 고객이 지적한곳을 고치겠다고 하면 금방 해결된다. 해결될수 없는거라도 최소한의 노력하는 모습을 보여주면 이해해 준다. 물론 예외도 있으니... 힘들다ㅎㅎ







명심해야 할게 있다. 나도 개발자라서 그런지 괜히 전문용어 운운하며 대서사시를 늘어놓고 싶은 충동을 느낄때가 많다. 정말 그랬다간 오히려 무식함을 드러내는 짓이다. 반성한다.


글쓰기나 발표등을 한번이라도 해본사람은 알겠지만 간단한 문장을 만들기란 결코 쉽지 않다...

내 뜻을 다 전달하면서도 쉽고 간결한... 그런 문장 말이다


트럼프가 저소득층에 속한 저학력 노동자들에게 지지받는 이유가 있다고 한다. 그들의 언어로 쉽게 말하기 때문이다. 실제로 그의 영어를 들어보면 나같은 영포자도 알수 있는 쉬운단어가 많다.


고객을 대할때는 고객의 언어로 통일하자~

꼭 열변을 토할 필요도 없다. 내성적인 사람도 충분히 할 수 있는 말이다.







우리가 가장 걱정하는게 나왔다.

영업은 인맥이다. 거의 정형화된 문구이다. 여기서 소심인들은 영업을 포기한다.

하지만 인맥 영업은 현장에서 하수라고 한다. 왜냐하면 가장 쉽기 때문이다. 또한 물리적인 비용뿐만 아니라 정신적인 비용도 의외로 많이 든다.


영업은 인맥이 아니라 신뢰로 하는것이다. 작가가 강조하듯이 굳이 가까운 사이가 될려고 하지 않아도 서로간에 신뢰만 쌓이면 언제든지 마음을 열수 있다.


물론, 인맥 쌓는게 신뢰를 얻는것이다 라고 말할수도 있겠지만 우리 소심인들에게는 어울리지 않는다.

우리는 우리 방식대로 하면 된다. 핵심은 신뢰 그 자체라고 생각한다. 







사업자를 막 내고 의욕적으로 앱을 만들던 시절때 일이다.

앱을 한 10개쯤 만들어 놓으면 성공한 사람이 되어 있겠지~ 하며 일을 했다.

긍정적인 사람이 성공한다는 말도 있으니ㅎ


하지만 세상은 그리 만만치 않았다. 어느덧 10개가 넘는 앱을 만들었지만 길은 아직도 멀어보였다.

그러는중 문득 이런 생각이 들었다.


너무 막연하게 성공을 꿈꿨던건 아닐까


그렇다... 아무 계획없이 일을 했던 것이다.

뭔가 이루고 싶다면 그에 걸맞는 계획과 실행도 필요하다. 나는 그저 잘될거야 라는 자기 위로만 하고 있었을뿐이었다.


영업에 있어서도 내성적이냐, 외향적이냐 보다는 계획과 실행을 얼마다 잘하냐가 중요할 것이다.







손자병법에는 이런말이 있다.

약점 가운데 가장 큰 약점은 약하다는 것을 두려워하는 것이다.


내성적이라서 못할건 없다. 도전하자.


수제앱장인


 

 

CEO

Developer

S/W Enginner

고영진


실패만 하고 있어도 꿈을 포기하지 않는 남자
제가 직접 경험하고 습득한 지식을 위주로 올릴게요


사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
개발/android 2018.06.07 14:03

Intent 전달 방식을 모방하여 부모 activity를 호출하기


IOS에서는 prepare()을 통해서 부모 controller를 쉽게 전달할 수 있다.

하지만 Android에서는 Intent로 activity를 전달하기 쉽지 않다.


뭐, Intent 말고도 여러 전달 방식이 있기 때문에 상관없지만...

깔끔하게 코딩하고 싶은 마음에 함 만들어 보았다.


static을 이용하지만, 마치 Intent로 전달하는것 같은 느낌으로ㅎㅎ



public class BaseActivity extends FragmentActivity {

private static final String KEY_PARAM_CONTEXT_ID = "ParamContextId";

//전달할 Context를 담는 Map
private static HashMap<Long, Context> mParamContextMap = null;

//전달된 Context를 저장할 인스턴스
private Context mParamContext;

//부모 Activity에서 호출되어 Context를 받는다
public static void putParamContext(Intent intent, Context context) {

//Map이 널이면 즉 Context가 하나도 없다면 생성한다
if (mParamContextMap == null)
mParamContextMap = new HashMap<>();

//현재 시간을 식별자로 전달 Intent에 저장한다. 이는 Context가 static에 담아지기 때문에 상속받은 모든 activity에서 만약에 있을 출동을 막기 위함이다.
long id = System.currentTimeMillis();
intent.putExtra(KEY_PARAM_CONTEXT_ID, id);

//위의 식별자를 해당 키로 하여 Map에 Context를 담는다.
mParamContextMap.put(id, context);
}

//부모 Activity의 Context를 반환한다.
protected Context getParamContext() {
return mParamContext;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//전달된 Context가 있다면 실행한다.
if (mParamContextMap != null) {
long id = getIntent().getLongExtra(KEY_PARAM_CONTEXT_ID, 0);
if (id != 0) {
//Context를 인스턴스에 저장하고 static Map에서는 삭제한다.
mParamContext = mParamContextMap.get(id);
mParamContextMap.remove(id);
}

//Map에 아무것도 없다면 널로 풀어준다.
if (mParamContextMap.size() == 0)
mParamContextMap = null;
}
}
}




부모 Activity에서 자식 Activity 호출...


Intent intent = new Intent(this, MyActivity.class);
BaseActivity.putParamContext(intent, this);
startActivity(intent);



자식 Activity에서 부모 Activity 호출...


public class MyActivity extends BaseActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

    Context parentContext = getParamContext();

//부모 Context롤 이용하여 작업한다.

//

//

}

}


 

 



수제 앱 장인: 고영진


(주)고영진모바일

1인기업 대표이사 겸 개발자

  

     실패만 하고 있어도 꿈을 포기하지 않는 남자 

     제가 직접 경험하고 습득한 지식을 위주로 올릴게요

 






사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
2018.05.15 20:10

너의 마음속 듣기...어떻게 원하는 것을 얻는가



만약, "그건 안돼요" 라는 말을 듣는다면 나는 어떤 말로 이어나가야 할까?

누구나 한번쯤은 겪는 고민이다. 특히, 정말 간절할때는 더욱더 그렇다.


입장을 바꿔 내가 "그건 안돼요"라는 말을 한다고 생각해 보자.

나는 왜 안된다고 말을 했을까? 


모두 그렇지는 않지만 대부분은 정말 안돼서가 아니라 내가 잃을게 있거나 얻는게 없기 때문일 것이다.


그렇다. 상대방도 그래서 거절하는것이다.

즉, 상대방도 뭔가 얻게 해주면 된다.


사람들이 가지고 싶어하는것은 값비싼 금은보화만이 아니다.

외로운 사람들은 말동무가 필요할 것이고, 시간이 없는 사람은 여유를 갖고 싶을것이다.


나에겐 사소하지만 상대방에게는 필요한 그 무엇을 주면 어렵지 않다.


하지만 문제는 다른사람들이 필요로 하는것을 우리는 잘 모른다

그래서 경청이 중요하다. 너의 마음속 듣기... 


이 책의 표현을 빌린다면 인간적인 소통을 통해 상대방의 머리속 그림을 그려보는것.. 부터 협상은 시작된다.




 

 



수제 앱 장인: 고영진


(주)고영진모바일

1인기업 대표이사 겸 개발자

  

     실패만 하고 있어도 꿈을 포기하지 않는 남자 

     제가 직접 경험하고 습득한 지식을 위주로 올릴게요

 




사업자 정보 표시
고영진모바일 | 고영진 | 서울특별시 관악구 낙성대동 서울대연구공원 SK상생혁신센터 | 사업자 등록번호 : 109-11-82076 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2010-서울강서-0217호 | 사이버몰의 이용약관 바로가기
TOTAL 69,581 TODAY 10