Open Source UAV Platform
Apple에서 제공하지 않는 유용한 패키지 관리자 설치
brew tap homebrew/science
brew install opencv3 --HEAD --with-contrib
echo /usr/local/Cellar/opencv3/HEAD-85e01f3_4/lib/python2.7/site-packages >> /usr/local/lib/python2.7/site-packages/opencv3.pth
Installing opencv-3.1.0 on MacOS Sierra to use with python
http w3c 문서...가 재밋다...? http 는 rfc 문서..? 고통의 2616 문서 https://tools.ietf.org/html/rfc2616
https://www.phacility.com - 근데 유료
- Title
- Featur/Bug-fix 건
- 어떤 목적
- 어떤 이슈와 연결됐는지
- Description
- 어떤 로직을 추가/수정했는지
- 어떻게 추가 수정했는지
Upsource Code review process with JetBrains UpSource GitHub 의 PullRequest 에 대한 개념을 이해해야 할듯
코드리뷰가 요청이 오면 업무의 최우선순위로 조정되어 즉시 응답하도록 하는 것이 원칙이다. (지금 당장 하든지 아니면 언제부터 할 것인지를 피드백을 반드시 준다.) 이를 바탕으로 현실적으로 수정
- 월~수 : feature/bug-fix 개발이 업무의 최우선 순위
- 목,금 : 코드리뷰가 업무의 최우선 순위이며 코드리뷰 대상은 목요일 출근 전까지 리뷰 요청한 건
- 성능 개선 개발 : 시간복잡도
- 신규 feature 개발 : 잠재적인 오류 검출
- 리팩토링 : 테스트코드나 구조에 대한 물음
- 신규 기술 도입 : 해당 기술의 로직과 그에 대한 물음
- 기타 : 변수명과 같은 코드 컨벤션, 실제 빌드 해서 동작
- oo보다는 xx가 더 나은 것 같아요
- xx는 oo부분을 참고해서 이용하면 되요
- oo는 xx에 의해서 문제되지 않을까요?
- xx를 하려다가 oo로 했는데 어떻게 생각하세요?
리뷰가 완료되면 개발용 브랜치에 통합한다. 최소 1명의 피드백도 진행되지 않은 코드는 통합하지 않는다.
즉시 진행한다.
"p4 mail"이나 gerrit 같은 코드 리뷰 시스템을 사용하는 것도 좋은 듯.. 온라인 상에서의 코드 리뷰
코드 리뷰를 통해서 많이 배운다. 나보다 더 나은 엔지니어로부터 조언을 받을 수 있으니까 -> 실력이 좋은 사람으로부터 배워야 한다!!!
코드리뷰, 이렇게 하고 있습니다. 코드 리뷰 어떻게 하나요?
멀티쓰레딩 환경 시 동기화
http://www.jsonschema2pojo.org/
Vim에서 파일브라우징을 위한 플러그인 Getting Command-T Working on Windows
set tabstop=4
set encoding=cp949
set fileencodings=utf-8,cp949
set langmenu=cp949
set guifont=Gulimche:h12:cHANGEUL
set lines=60 columns=120
객체 생성 시, Builder 패턴을 사용하면 파라미터가 많을 경우 제공 상태를 일관성 있게 하고, object를 생성시킬 때, step-by-step으로 만들 수 있도록 할 수 있다.
- class 안에 중첩 static class를 생성시키고, 바깥쪽 class의 argument들을 안쪽 static class(builder class)로 옮긴다. 바깥쪽 class의 생성자는 private로 선언해서 직접적인 생성을 막는다.
- builder class의 생성자를 public static으로 선언하고 필요한 파라메터들을 요청한다.
- builder class에는 선택적 파라메터에 대한 setter method가 있어야한다. 그리고 선택적 인자를 설정한 후에도 같은 builder object를 리턴해야한다.
- 마지막으로로 클라이언트 프로그램이 요청하는 object를 받을 수 있도록 build method를 만드는데, build method에서는 바깥쪽 class의 생성자가 builder 클래스의 인자를 받을 수 있도록 제공한다.
뭐지?
Html 파서 라이브러리
앱이 기능이 점점 추가되고 복잡해져 가면서 코드가 점점 누더기가 되어갔다. 수정에 대한 부작용을 파악하기 어려워졌고, 테스트의 필요성을 느꼈다. Android App과 TDD-임유진
Service와 Persistence 계층
JRebel,, HotSwap JRebel과 인스턴트-런 비교, 핫/웜/콜드 스왑 요약정리
가속도센서 calculate speed from accelerometer
Android O에서의 백그라운드 처리를 위한 JobIntentService
NestedScrollView를 이용하면 ScrollView안에 ScrollView를 구현할 수 있다.
Firebase 원격 구성으로 클라우드에서 앱의 매개변수를 정의하고 업데이트하면 앱 업데이트를 배포하지 않고도 앱의 모양과 동작을 수정할 수 있습니다. 이 가이드에서는 앱에서 다음 단계에 따라 원격 구성을 사용하는 방법을 다룹니다.
xml에서 사용, CheckBoxPreference 뭥미
안드로이드에서 제공하는 타이머 Handler.sendMessageDelayed 를 사용해서 표시하고 있음
commit()은 Activity의 onSaveInstanceState() 하기전에 수행되어야 하며, 이를 어길시 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 예외가 발생된다 화면갱신이 필요한 경우에는 commit()을 쓰지 말고 commitAllowingStateLoss()를 호출 해서 onSaveInstanceState()와 무관하게 commit를 할 수 있다. fragmenttransaction에 대해서..
TensorFlow 안드로이드 데모를 하기 위해 필요하다 TensorFlow: 머신러닝 tensorflow Bazel 알아보기 gradle 처럼 빌드 시스템, gradle보다 빠르게 빌드할 수 있다
sqlite 에서 보다 빠르게 문자열 검색 full-text-sarch
메모리 관리를 위해 사용,
폰트의 여백 제거
JOE'S GREAT ADAPTER HELL ESCAPE
Between 사용 사례: APT를 활용한 Realm 마이그레이션
RecyclerView DiffUtil로 성능 향상하기
layout 퍼포먼스?? LinearLayout << RelativeLayout <<<<< ConstrainLayout
weight + depth 들어가면 RelativeLayout 이 더 낫고요 뷰 간 관계가 많아지면 ConstraintLayout
Response response = okHttpClient.newCall(request).execute();
mWebView.loadDataWithBaseURL(mUrl, response.body().string();, "text/html", "utf-8", null);
(https://developers-kr.googleblog.com/2015/08/testyourapponandroid60.html) Apps that have been running foreground services (with the associated notification) are not restricted by doze. (http://stackoverflow.com/a/33077301) Doze mode와 foreground서비스
(https://developer.android.com/guide/topics/ui/menus.html?hl=ko)
usb 연결을 mtp->ptp 로 변경해서 테스트 한다... (http://www.clien.net/cs2/bbs/board.php?bo_table=cm_app&wr_id=12979)
android:textAlignment="viewEnd"
다음 폴더를 지우면 해결된다. 프로젝트/obj/local/armeabi
alertDialog.setOnShowListener 사용 (http://stackoverflow.com/a/26087947)
android:launchMode="singleInstance"
android:excludeFromRecents="true"
SingleTask 모드 startActivity()실행시 Activity가 존재하면 Activity를 Destroy하고 재생성한다. Activity에서 startActivityForResult() 실행시 결과를 받을수 없다. (일반적인 어플에서 사용 불필요)
SingleInstance 모드 startActivity()실행시 Activity가 존재하면 재생성하지 않고 기존 Activity를 재활용한다. Activity에서 startActivityForResult() 실행시 결과를 받을수 없다. (일반적인 어플에서 사용 불필요) onStart()에서 getIntent()사용하지 말고 onNewIntent()로 받아야 한다. SingleTop 모드 startActivity()실행시 Activity가 존재하면 재생성하지 않고 기존의 Activity를 재활용한다. Activity에서 startActivityForResult() 실행시 결과를 받을수 있다.
Standard 모드(기본값) startActivity()실행시 Activity 존재여부에 상관없이 재생성하므로 동일 Activity가 여러개 될수 있다. Activity에서 startActivityForResult() 실행시 결과를 받을수 있다. [출처] 안드로이드사이드 - http://www.androidside.com/bbs/board.php?bo_table=B49&wr_id=145947#c_145963
<item name="colorPrimary">#e0e0e0</item>
<item name="colorPrimaryDark">#a6a6a6</item>
<item name="colorAccent">#a6a6a6</item>
문자열의 확장판 Spannable 너는 뭐 하는 녀석이냐?
Adpater 가 있는 상태에서 filter 를 사용하게 된다 performFiltering 에 tokenizer 를 사용함, findTokenStart로 시작위치를 찾음 performFiltering 를 상속받아서 사용하면 될듯 onEditorAction - handleDone 키보드에서 완료 버튼 선택 performCompletion(select), replaceText(keyboard) Adapter 가 없을 때는? filter를 추가하면?
setFilter로 추가하면 단어만 남음, 알아서 필터해주나? setFilter 쓰느겍 낫남?
width, height 값을 조정하기 위해서 minWidth와 minHeight 을 사용
<<<<<<< HEAD
value 에 sw-600dp 에 boolean 값을 넣고 value 로 확인
// 일반
<bool name="isTablet">false</bool>
// sw600dp
<bool name="isTablet">true</bool>
Data Binding Library DataBinding-findViewById 이제 안녕~ 안드로이드 데이터 바인딩-SlideShare
=======
449bd35757ad4be2b3781752bc27d4036c2ae380
onCreateView 너는 뭐니? View onCreateView (String name, Context context, AttributeSet attrs) Standard implementation of LayoutInflater.onCreateView..
Fragment 생성 시, infalte를 호출하면 Activity에서 받아서 View를 구성할 수도 있음
compileSdkVersion이 안 맞을 경우 발생한다.. 프로젝트에서 compliSdkVersion 19 ->compliSdkVersion 21으로 변경하니 빌드됨
gradle error 'This version of android studio is incompatible with the gradle version used.Try disabling the instant run'
File → Settings → Preferences dialog → Build → Execution → Deployment → Instant Run
You can disable instant run answer
gradle version 문제로 gradle-wrapper.properties 에서 gradle version을 변경하니 해결됐다. answer
해당 프로젝트의 설정 된 minSdkVersion 이후에 나온 API를 사용할때 warning을 없애고 개발자가 해당 APi를 사용할 수 있게 합니다.
Palette,Swatch를 활용해서 이미지의 테마색 가져오기
프로젝트명이 "OpenCV Library 2.3.13.1" 로 빌드가 안되서 발생한 에러 프로젝트명을 "OpenCVLibrary"로 변경함
UncaughtExceptionHandler 를 이용해서 비정상 종료를 catch 할 수 있다. Trhead는 발생하는 예외를 uncaughtTread를 호출하게 되어 있다 그래서 Thread의 UncaughExceptionHandler 인스터스를 Thread에 등록해서 예외 발생을 catch 할 수 있다. ExceptionReporter는 UncaughtExceptionHandler 인터페이스를 사용하는 애로 uncaught exceptions를 GoogleAnalytics에 보고할 때, 사용한다.
// Application 클래스
@Override
public void onCreate() {
super.onCreate();
uncaughtExceptionHandler = new MyUncaughtExceptionHandler();
Thread.UncaughtExceptionHandler handler = new ExceptionReporter(
new GoogleAnalyticsUtil(this).getV3EasyTracker(),
GAServiceManager.getInstance(),
uncaughtExceptionHandler,
this);
Thread.setDefaultUncaughtExceptionHandler(handler);
}
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
Logger.d(TAG, "uncaughtException" + getStackTrace(ex));
System.exit(2);
uncaughtExceptionHandler.uncaughtException(thread, ex);
}
}
UncaughtExceptionHandler를 이용한 앱 비정상 종료시 Log전송 및 재실행 하기 ExceptionReporter
row layout 에서 height 을 셋팅했는데 앱 실행 후, 확인해보면 반영이 안됨 문제가 발생하게 된 코드,,
convertView = mInflater.inflate(R.layout.item_setting_menu, null);
두 번째 인자에 null 이 들어가는데 이와 관련한 내용을 찾아보면 다음과 같은 말이 있다. LayoutInflater will automatically attempt to attach the inflated view to the supplied root. the framework has a check in place that if you pass null for the root it bypasses this attempt to avoid an application crash. 음.. 뭔 말인지.. layoutInflater 는 rootView에 inflated view를 붙이려고 시도하는데 rootView가 null 이면 충돌을 피하기 위해 이런 시도를 bypass 한다? 어쨌든 rootView에 null 이 들어가서 row layout 의 root element 에 고정한 height 이 childView의 속성으로 변경이 된 듯하다.. 이것을 다음과 같이 수정한다 수정한 코드
convertView = mInflater.inflate(R.layout.item_setting_menu, parent, false);
원했던 결과를 얻을 수 있다. attachToRoot 파라미턴에 대한 설명 Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML
페이스북이 만든 킹왕짱 종합 선물세트? 크롬 브라우저의 inspect UI를 이용해 각종 정보를 조회한다 (네트워크, Sqlite DB, SharedPreference, UI) (http://facebook.github.io/stetho/)
- 네트워크 로깅
- 앱 내부 sqlite DB SQL 실행
- SharedPreference 조회/수정
- 커스텀 동작 수행할 수 있는 dump plugin
- javascript console
debugCompile 'com.facebook.stetho:stetho:1.4.1'
Stetho.initializeWithDefaults(this)
adb 연결 후 크롬 브라우저에서 chrome://inspect 로 이동
compile 'com.facebook.stetho:stetho-okhttp3:1.4.1'
OkHttpClient.addNetworkInterceptro(new StethoInterceptor());
Square에서 만든 액티비티 메모리 릭 탐지 도구 (https://github.com/square/leakcanary)
SDK가 제공하는 뷰 성능 / 속성 조회 도구 (https://developer.android.com/studio/profile/optimize-ui.html#HierarchyViewer)
안드로이드 스튜디오 2.2 에 추가된, Hierarchy Viewer의 계승자
커스텀 클래스나 오브젝트를 다른 컴포넌트에 전달하는 경우 사용
parcelable을 사용하면 좀 더 쉽게 전달할 수 있다. 사용하지 않을 때,
// 보내는 쪽
Intent intent = new Intent(getActivity(), MovieDetailActivity.class);
intent.putExtra(MovieDetailActivity.CARD_PROFILE, card.getProfileImage());
intent.putExtra(MovieDetailActivity.CARD_NAME, card.getName());
intent.putExtra(MovieDetailActivity.CARD_TIME, card.getUpdatedTime());
intent.putExtra(MovieDetailActivity.CARD_PICTURE, card.getPicture());
intent.putExtra(MovieDetailActivity.CARD_DESCRIPTION, card.getDescription());
intent.putExtra(MovieDetailActivity.CARD_SOURCE, card.getSource());
intent.putExtra(MovieDetailActivity.CARD_ID, card.getId());
startActivity(intent);
// 받는 쪽
String cardName = intent.getStringExtra(MovieDetailActivity.CARD_NAME);
String cardTime = intent.getStringExtra(MovieDetailActivity.CARD_TIME);
String cardProfile = intent.getStringExtra(MovieDetailActivity.CARD_PROFILE);
String cardPicture = intent.getStringExtra(MovieDetailActivity.CARD_PICTURE);
String cardDescription = intent.getStringExtra(MovieDetailActivity.CARD_DESCRIPTION);
String cardSource = intent.getStringExtra(MovieDetailActivity.CARD_SOURCE);
String cardId = intent.getStringExtra(MovieDetailActivity.CARD_ID);
return new Card.Builder()
.id(cardId)
.name(cardName)
.createdTime(cardTime)
.profileImage(cardProfile)
.picture(cardPicture)
.description(cardDescription)
.source(cardSource)
.createCard();
사용할 때,
// 보내는 쪽
Intent intent = new Intent(getActivity(), MovieDetailActivity.class);
intent.putExtra(MovieDetailActivity.CARD_INFO, card);
startActivity(intent);
// 받는 쪽
card = getIntent().getParcelableExtra(CARD_INFO);
parcelable을 쉽게 해주는 parceler 라이브러리가 있음
설정한 Flavor 파일들 중에 원본의 src와 res에 들어있는 중복되는 파일들 교체 빌드 해주는 것
The SwipeRefreshLayout should be used whenever the user can refresh the contents of a view via a vertical swipe gesture.
mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// 이 부분에 리플래시 시키고 싶으신 것을 넣어 주시면 됩니다.
}
});
// 리플래쉬 ui 종료
mSwipeRefresh.setRefreshing(false);
Activity:launchmode 중 sigleTask 와 singleInstance는 한 개의 instance 만을 가질 수 있다. 그래서 항상 stack의 root를 차지한다.
Activity Stack이 다음의 순서로 쌓인 상황에서 A->B->C->D
특정 이벤트가 발생했을 때, A로 가려고 하는 경우 사용
A Activity에 sigleTask option 을 추가하고, 이벤트가 발생했을 때, startActivity를 호출한다.
sigleTask는 다른 activity 들이 자신의 instance 위에 쌓이는 것을 허락해준다. singleInstance는 다른 activity를 자신의 task 안에 포함시키 않는다.
Android moving back to first activity on button click 간단하게 Activity stack 처리하는 방법
라이브러리의 이름과 버전을 분리 별도로 분리하여 관리한다.
<string-array name="my_array">
<item>key1|value1</item>
<item>key2|value2</item>
</string-array>
Map<스트링, String> getKeyValueFromStringArray(Context ctx) {
int id = context.getResources().getIdentifier(resourcename, "array", context.getPackageName());
String[] array = ctx.getResources().getStringArray(id);
Map<String, String> result = new HashMap<>();
for (String str : array) {
String[] splittedItem = str.split("\\|");
result.put(splittedItem[0], splittedItem[1])
}
return result
}
tools:showIn
Android 에서는 retrolambda 플러그인을 사용해서 Lambda를 사용한다
// project level
classpath 'me.tatarka:gradle-retrolambda:3.2.2'
// module level
apply plugin: 'me.tatarka.retrolambda'
// java version 표기 1
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
// java version 표기 2
retrolambda {
javaVersion JavaVersion.VERSION_1_7
}
간단하고 편리하게 Service의 특성을 사용할 수 있다. 클라이언트에서 서비스를 실행하면 Intent를 받아서 Intent Queue 에 순서대로 넣고 IntentService는 Queue에 존재하는 intent를 하나씩 실행하게 된다. Queue가 모두 비워지면 서비스는 종료한다.
IntentService를 실행하면 IntentService는 onHandleIntent 함수를 호출한다.
Queue가 모두 비워지면 IntentService
Activity 가 foreground 상태에서 Intent에 Extra값을 추가하고 StartActivity를 호출하면 onCreate() 대신에 onNewIntent가 호출되고 그 다음에 noResume()가 호출됨 onNewIntent알아보기
string.xml 에 변수 적용하기 dynamic String using String.xml?
xmlns:app="http://schemas.android.com/apk/res-auto"
Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType);
requestbody는 utf8 형태로 저장하기 때문에 utt8로 인코딩된 데이터를 읽는 로직이 필요하다.
private static String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
copy.writeTo(buffer);
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
google 서비스 사용시 에러가 발생하면 proguard 설정에 다음 추가
-keep class com.google.android.gms.** { *; }
-dontwarn com.google.android.gms.**
com.google.android.gms 에서 duplicate zip entry 에러 발생한다면
apply plugin: 'com.google.gms.google-services'
위치를 확인, 이 설정은 gradle file의 아래에 위치해야함
통화 상태에 대한 변화 알림을 받는다.
TelephonyManger의 listen을 호출해 특정 이벤트에 대한 알림을 받을 수 있다. 여기서는 LISTEN_CALL_STATE 이벤트를 사용했다.
TelephonyManager telephony = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); telephony.listen(phoneStateListener,PhoneStateListener.LISTEN_CALL_STATE);
리스너에 대한 예제
private PhoneStateListener phoneStateListener = new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
Log.d(TAG, "incomingNumber :" + incomingNumber);
mIncomingNumber = incomingNumber;
}
};
이벤트 알림을 받을 필요가 없을 때, 다음과 같이 호출한다.
TelephonyManager telephony = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneStateListener,PhoneStateListener.LISTEN_NONE);
안드로이드 6.0 마쉬멜로우에 새롭게 추가된 절전모드 일정시간동안 움직이지 않는 경우, 디바이스는 Doze 모드에 진입하고 앱들은 배터리 소모가 많은 기능, 네트워크 연결, GPS 스캔 등을 활용할 수 없음..
google-services plugin은 google-services.json 파일에서 서비스 이용에 필요한 프로젝트 정보, 클라이언트 정보를 읽어서 처리한다
안드로이드에서는 기본적으로 Java 1.6에서 사용되는 Annotation을 지원한다. 대표적으로 @Override가 있다.
Nullness annotations는 2개의 Annotatinos가 있습니다.
- @NonNull : null을 허용하지 않을 경우
- @Nullable : mull을 허용할 경우
@NonNull에 null을 추가하게 되면 경고 메시지가 표시된다. 개발에 null을 허용하거나, null을 허용하지 않을 경우에 대하여 미리 Annotations을 적용해두면 추후 개발에 문제가 줄어들 수 있다.