일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 |
- DiffUtil.ItemCallback
- kotlin list
- exoplayer cache
- kotlin collection
- 유튜브
- android custom view
- android exoplayer
- 안드로이드
- 시행착오
- android
- getChangePayload
- ktor api call
- AWS EC2
- ktor client
- 스피너
- Python
- android ktor
- ListAdapter
- 독서
- ansi2html
- video caching
- list map
- ExoPlayer
- doc2vec
- map
- build with ai
- ListAdapter DiffUtil
- ChatGPT
- FastAPI
- llm
- Today
- Total
목록분류 전체보기 (100)
버튼 수집상
평소에 코드를 짜면서 ChatGPT를 애용한다. 몇 번씩 피드백을 주고받은 끝에 만족스러운 (제대로 동작하는) 답을 얻게 되면 나는 한번씩 it works! thanks a lot 같은 감사인사를 덧붙인다. 수고를 덜어줬다는 감사의 마음 반, 그리고 만족스러운 답을 받았다는 피드백이 향후 답변에 반영되지는 않을까 하는 의심이 반이었다. 이에 관해서 ChatGPT에게 물어봤다. 모든 대화는 영어로 오갔습니다. 질문 원문은 약간 각색했습니다. 답변 원문은 그대로 싣되, 맥락을 해치지 않는 선에서 요약했으며 임의로 번역했습니다. Q when finding your answer helpful, does showing gratitude towards you make any difference to your ans..
배경 Compose를 아직 도입하지 않은 xml 베이스의 프로젝트에서도 코드로 뷰를 생성해서 쓸 때가 있다. 그럴 때 커스텀뷰를 만들면 반복되는 코드를 은닉하면서 코드 가독성이 좋아진다는 장점이 있다. 커스텀뷰를 만들면서 겪었던 시행착오들과 기억해야할 사항들을 정리해보겠다. 뷰 생성자를 오버라이딩 해준다. class CustomDropDown @JvmOverloads constructor( mContext: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : LinearLayout(mContext, attrs, defStyle) { //... } @JvmOverloads 어노테이션을 붙이면 mContext, attrs, defStyle로 만들 수 있..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/RanpU/btsqBwNzXMH/AuvHwgra8ZKmulzL34Ygi0/img.png)
배경 무한재생되는 30초 내외 분량의 비디오에서 트래픽이 너무 쌓인다고 캐싱이 제대로 되고 있는지 확인 요청이 들어왔다. ExoPlayer는 캐싱 처리를 따로 해줘야 하는데, 기존 코드에서 설정하고 있지 않았다. 확인하기 디버거를 연결한 다음 안드로이드 스튜디오 하단의 App Inspection > Network Inspector 를 켰다. 최초의 요청 이후로도 비디오가 반복되며 재생될 때마다 통신이 오고감을 알 수 있다. 빨간 박스가 그려진 데이터 사이즈는 영상에 따라 달랐다. 기존 코드는 아래와 같다. // player 초기화 private fun initPlayer() { // 싱글턴 오브젝트 ExoPlayerInfo.instance.apply { player = SimpleExoPlayer.Bui..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/3hJuU/btspxa5J7ra/lkZBXq8QPZpFeK99N7lnYk/img.png)
배경 카드뷰 그림자에 색이 들어가게 해달라는 요청이 있었다. 기존에 outlineSpotShadowColor 라는 옵션이 있으나 API 28부터만 지원했다. 그래서 카드뷰를 직접 구현해보기로 했다. 요구사항 1. 카드뷰처럼 elevation, radius 값 지정이 돼야 한다. 2. 그림자 색 지정이 돼야 한다. 요구사항을 충족시키려면 onDraw()로 구현할 수 밖에 없어보였다. attrs.xml (~/res/values) attrs를 선언하면 xml 코드의 app namespace에서 값을 설정할 수 있다. format을 모르겠을 땐, xml에서 다른 어트리뷰트를 cmd + 클릭해서 확인해보면 된다. 시도1 CustomCardView.kt (커스텀 카드뷰의 루트) class CustomCardView..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/lglHY/btso937uByC/aYwpGgDzWGYNMUQxLXdW8K/img.gif)
지난 글에서 ListAdapter DiffUtil 의 getChangePayload 활용법에 대해 적었다. [안드로이드] ListAdapter DiffUtil 제대로 쓰기 - 2 1편에서 ListAdapter에 submitList를 하면서 기존 리스트를 업데이트할 때 리스트 깊은 복사deep copy를 해야 하는 이유에 대해 적었다. 이번엔 ListAdapter DiffUtil의 각 함수를 자세히 알아보겠다. 샘플 코드 collectingbuttons.tistory.com 이제 DiffUtil을 활용해서 expand - collapse 되는 리스트 UI를 만들어보겠다. 임의로 만든 모의데이터 기반이라 도움이 될지는 모르겠다. 샘플 UI 구조 상위 카테고리 ▲ |_ 하위 카테고리 |_ 하위 카테고리 상위 ..
얼마 전에 ListAdapter의 DiffUtil을 쓰는 법에 대한 글을 썼었다. [안드로이드] ListAdapter DiffUtil 제대로 쓰기 - 1 배경 리사이클러뷰에서 부분적으로 UI를 업데이트할 때 (ex: 찜하기) 업데이트한 리스트를 submitList()로 세팅해도 DiffUtil이 제대로 돌아가지 않는 경우가 있었다. 리스트 변경사항을 제대로 감지하 collectingbuttons.tistory.com 글 1편은 ListAdapter 보다 List.map()에 대해 적었다. 그런데 위 글을 적은 후에도 여전히 헷갈리는 부분이 있어서 다시 정리해봤다. 코틀린 Collections 파일에서 map 함수의 시그니처를 보자. /** * Returns a list containing the resu..
배경 최근본상품 api를 만드는 대신, 상품을 열람할 때마다 앱 내부에서 열람 히스토리를 갱신시키기로 했다. 내부DB를 써도 됐지만 상품번호 문자열만 저장하면 돼서 Preference 프리퍼런스를 사용했다. 1. 새로운 요소 - 리스트 0번째에 저장 2. 중복되는 요소 - 기존 요소 삭제, 리스트 0번째에 저장 기본 코드 Preference // 리스트 자료형을 직렬화해서 문자열로 저장 var recentProducts: String get() = preferences.getString(KEY_RECENT_PRODUCTS, null) ?: "" set(value) = preferences.edit { putString(KEY_RECENT_PRODUCTS, value) } 최근본상품 중복체크해서 저장 //..
FastAPI 공식 문서를 참고해서 token api를 구현했다. @app.post("/token") async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): user_dict = fake_users_db.get(form_data.username) if not user_dict: raise HTTPException(status_code=400, detail="Incorrect username or password") user = UserInDB(**user_dict) hashed_password = fake_hash_password(form_data.password) if not hashed_password == user.h..