일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Gradle
- Coroutines
- Python
- AWS
- 백준
- 코드포스
- activity
- android
- pandas
- boj
- GitHub
- TEST
- Rxjava
- relay
- Kotlin
- Compose
- MyVoca
- Hilt
- Coroutine
- 암호학
- MiTweet
- textfield
- androidStudio
- architecture
- ProGuard
- 코루틴
- Codeforces
- livedata
- 쿠링
- 프로그래머스
- Today
- Total
이동식 저장소
MiTweet 개발일지 7 본문
이번 일지에서는 로컬 트윗 데이터베이스를 만들고, 타임라인을 불러와 보여주면서 데이터베이스에 저장하는 과정에 대해 서술해 본다. 사실 이번 글도 생략된 부분이 많다. 중간 과정을 보는 재미도 있긴 한데 코딩할 때는 딴 생각이 잘 안 나서..
데이터베이스 구현
올해 초에 단어장 앱을 만들 때는 ``SQLite``를 사용했었는데, 요즘은 ``NoSQL(Not only SQL)``이 각광받고 있다고 하여 여러 구현체 중 오픈 소스 ``MongoDB Realm``을 사용해 보기로 했다.
// at build.gradle(project level)
dependencies {
// ...
classpath 'io.realm:realm-gradle-plugin:7.0.0'
}
// at build.gradle(app level)
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
``Realm``에 넣을 데이터 스키마를 정의한다. 이때 ``RealmObject``를 상속해야 하며, 클래스와 필드 모두 ``open``으로 정의해야 한다. 지금은 트윗 객체를 넣을 것이므로 트윗의 ID와 로그인한 계정의 ID를 저장한다. 나중에 다중 계정을 지원할 수 있으니 미리 대비하는 차원에서 계정 ID를 넣었다.
open class TweetDBObject(open var userId: Long = -1, @PrimaryKey open var tweetId: Long = -1) :
RealmObject()
새로 로드되는 모든 트윗은 데이터베이스에 저장되어야 한다. DB 관리를 쉽게 하기 위해 트윗 로드 관련 작업을 하나의 객체에 몰아줄 필요가 생겼는데, 나는 싱글턴 패턴을 사용하였다.
object TwitterAPI {
// operations...
}
코틀린에서는 ``object`` 키워드로 싱글턴 객체를 만들 수 있다. 이제 ``getInstance()`` 안 써도 된다!
타임라인 로드
트위터 API에서 홈 타임라인을 불러와 보여준다. 성능을 고려하면 비동기적으로 불러오는 게 맞지만, 일단 테스트를 위해 동기 메소드를 사용한다.
그런데 API 1.1에서는 트윗에 달린 답글의 수를 직접 알 수 없다. ``reply_id``로 직접 검색해야 하는데, 검색을 여러 번 하다 보니 금방 리밋에 걸린다. 실제로 사용하는 상황이 아니라 개발하면서 테스트하는 도중에도 리밋이 걸려서, 결국 API v2를 직접 구현하기로 했다.
Q. 그냥 라이브러리 쓰면 되지 않나?
지금 쓰고 있는 ``Twitter4J``는 2년 전에 개발이 중단된 상태이다. 다른 라이브러리가 있지만 하나는 아직 개발 중이고 하나는 프로젝트 import가 안 돼서.. ㅠㅠ
그런데 지금 API v2는 아직 개발 중이라서, 타임라인 로드는 안 된다. 타임라인을 불러오는 부분만 1.1 버전을 사용하고, 타임라인에 속한 각 트윗 정보는 v2로 불러와야 한다. 일해라 트위터
옛날에 전적 앱 만들 때에도 HTTP request를 써 본 경험이 있기에 바로 시작했다.
API v2 구현
API v2에는 여러 기능이 있지만, 일단 지금 필요한 트윗 로드 관련 기능만 구현한다. 다음의 로직을 구현한다.
- 요청 보내기
- 응답을 받아 객체로 파싱하기
- 파싱한 결과를 앱에 보여주기
API v2에서는 투표 정보도 받아올 수 있어서, 나중에 투표도 보여줄 수 있도록 ``TweetMiniView``를 수정할 계획이다.
``Volley``를 이용하여 요청을 보내고, ``Gson``을 사용하여 json 문자열을 코틀린 객체로 파싱한다. 파싱한 트윗을 ``RecyclerView``에 보여주면 된다.
implementation 'com.android.volley:volley:1.1.1'
implementation 'com.google.code.gson:gson:2.8.6'
그런데 ``Volley``는 본질적으로 비동기적이다. 따라서 트윗을 보여주는 부분 역시 비동기적으로 실행되게 해야 하는데, 나는 요청이 성공했을 때 실행할 함수를 API 함수에 인자로 넘겨 주는 방식으로 구현했다. 대략 이런 식이다.
// at TwitterAPI
fun loadTimeline(callback: (TweetsV2) -> Unit) {
val request = object : StringRequest(Method.GET,
url,
Response.Listener {
val tweets = gson.fromJson(it, TweetsV2::class.java)
callback(tweets)
}, Response.ErrorListener {
it.printStackTrace()
})
}
requestQueue.add(request)
}
// at fragment
TwitterAPI.loadTimeline(::setTimelineRecyclerView)
요청이 성공하면 가운데의 ``Response.Listener`` 부분이 실행되는데, 이곳에서 응답을 파싱하여 ``callback``을 실행한다. ``callback``에서는 ``TweetRecyclerView``를 ``Visible``로 바꾸고 어댑터를 설정한다.
타임라인을 성공적으로 로드했다. 그런데 플텍 계정의 트윗은 로드되지 않아서 찾아보니 OAuth 2.0을 사용하기 때문이라고 한다. 플텍 계정의 트윗까지 로드하려면 HTTP request를 보낼 때 OAuth 1.0a를 사용해서 인증해야 한다. 이 부분이 굉장히 어려워 보여서 일단 TODO로 남겨놓는다.
데이터베이스에서 트윗 로드
트위터 공앱의 동작 원리를 생각해 보면, 데이터베이스에 저장된 트윗을 보여준 다음 최신 타임라인을 로드한다.
- 데이터베이스에서 트윗 id를 내림차순으로 최대 20개 로드
- 로드한 id로 트윗을 불러와서 보여줌
- 최신 타임라인 로드(바로 윗 부분)
Realm.getDefaultInstance().where<TweetObject>().findAll().sort("tweetId", Sort.DESCENDING)
위의 코드를 실행하면 ``RealmResults<TweetObject>``를 얻을 수 있다. ``RealmResults``는 ``List``를 상속했기 때문에 리스트를 사용하는 것처럼 조작하면 된다.
그런데 ``RecyclerView``에 최신 타임라인이 추가될 때 데이터베이스에서 로드한 트윗이 밑으로 내려가 버린다. 공앱처럼 기존 트윗은 그대로 있고 그 위에 트윗을 추가해야 하는데, 이 부분 구현이 어려워 최우선 TODO로 남겨놓는다.
일단 데이터베이스 트윗+최신 트윗은 제대로 로드된다.
``TweetMiniView`` 수정
원래 ``name``과 ``username``(@로 시작하는 아이디)는 한 줄에 표시했는데, ``username``이 아주 경우 오른쪽 날짜가 안 보이는 불상사가 발생하여.. ``name``과 ``username``을 세로로 표시하도록 수정했다.
TODO
- 타임라인을 로드할 때 ``RecyclerView``가 맨 위로 스크롤되지 않게 해야 함
- OAuth 1.0a 구현
- 리트윗을 제대로 보여주도록 수정하기
- ``TweetMiniView``에 기능 추가하기(리트윗, 마음에 들어요 등)
'프로젝트 > MiTweet' 카테고리의 다른 글
MiTweet 개발일지 9 (0) | 2020.09.11 |
---|---|
MiTweet 개발일지 8 (0) | 2020.09.08 |
MiTweet 개발일지 6 (0) | 2020.08.28 |
MiTweet 개발일지 5 (0) | 2020.08.27 |
MiTweet 개발일지 4 (0) | 2020.08.19 |