티스토리 뷰
Clone project - Book App - Step 2 (uploading/loading pdf w firebase cloud)
Agrafenaaa 2021. 11. 1. 19:52결과화면
I Pdf파일 업로드
1. PdfAddActivity: FirebaseStorage(클라우드)에 저장 -> 실제 저장
private fun uploadPdfToStorage() {
// upload pdf to firebase storage
Log.d(TAG, "uploadPdfToStorage: uploading the attached file to firebase storage")
progressDialog.setMessage("Uploading pdf file")
progressDialog.show()
val timestamp = System.currentTimeMillis()
// pdf path in firebase storage
val filePathAndName = "Books/$timestamp"
// storage ref
val storageReference = FirebaseStorage.getInstance().getReference(filePathAndName)
storageReference.putFile(pdfUri!!)
.addOnSuccessListener {taskSnapshot ->
Log.d(TAG, "uploadPdfToStorage: The file attached has been successfully uploaded")
// get uri of the file
val uriTask: Task<Uri> = taskSnapshot.storage.downloadUrl
while(!uriTask.isSuccessful);
val uploadedPdfUrl = "${uriTask.result}"
uploadPdfInfoToDb(uploadedPdfUrl, timestamp)
}
.addOnFailureListener{e ->
Log.d(TAG, "uploadPdfToStorage: failed to upload. Error: ${e.message}")
progressDialog.dismiss()
Toast.makeText(this, "Failed to upload the attached file", Toast.LENGTH_SHORT).show()
}
}
2.PdfAddActivity - 업로드 목록 불러오기에 필요한 정보를 별도로 RealtimeDB에 저장
private fun uploadPdfInfoToDb(uploadedPdfUrl: String, timestamp: Long) {
// upload pdf into to firebase db
Log.d(TAG, "uploadPdfInfoToDb: uploading the file to db")
progressDialog.setMessage("Uploading the pdf file")
// get an uid of the current user
val uid = firebaseAuth.uid
// setup data to upload
val hashMap: HashMap<String, Any> = HashMap()
hashMap["uid"] = "$uid"
hashMap["id"] = "$timestamp"
hashMap["title"] = "$title"
hashMap["description"] = "$description"
hashMap["categoryId"] = "$selectedCategoryId"
hashMap["url"] = "$uploadedPdfUrl"
hashMap["timestamp"] = timestamp
hashMap["viewCnt"] = 0
hashMap["downloadCnt"] = 0
// db ref
val ref = FirebaseDatabase.getInstance().getReference("Books")
ref.child("$timestamp")
.setValue(hashMap)
.addOnSuccessListener {
Log.d(TAG, "uploadPdfInfoToDb: uploaded to firebase db")
progressDialog.dismiss()
Toast.makeText(this, "Successfully uploaded to firebase db", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {e ->
Log.d(TAG, "uploadPdfInfoToDb: failed to upload into firebase. Error: ${e.message}")
progressDialog.dismiss()
Toast.makeText(this, "Failed to upload the attached file into firebase", Toast.LENGTH_SHORT).show()
}
}
3.PdfAddActivity - 선택된 카테고리값 추출
private fun categoryPickDialog(){
Log.d(TAG, "categoryPickDialog: Showing pdf category pic dialog")
//get string array of categories from arrayList
val categoriesArray = arrayOfNulls<String>(categoryArrayList.size)
for(i in categoryArrayList.indices){
categoriesArray[i] = categoryArrayList[i].category
}
// alert
val builder = AlertDialog.Builder(this)
builder.setTitle("Select category")
.setItems(categoriesArray){dialog, which ->
// item click event
selectedCategoryTitle = categoryArrayList[which].category
selectedCategoryId = categoryArrayList[which].id
// set category to textview
binding.categoryTv.text = selectedCategoryTitle
Log.d(TAG, "categoryPickDialog: Selected Category Id: $selectedCategoryId, Title: $selectedCategoryTitle")
}
.show()
}
II Pdf파일 정보 불러오기
1. ModelPdf 생성 (uid, id, title, description, categoryId, url, timestamp, viewCnt, downloadCnt)
2. MyApplication
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
}
companion object{
// create a static method to convert timestamp to the proper date format
fun formatTimeStamp(timestamp: Long): String{
val cal = Calendar.getInstance(Locale.ENGLISH)
cal.timeInMillis = timestamp
return DateFormat.format("dd/MM/yyyy", cal).toString()
}
// get the uploaded file size
fun loadPdfSize(pdfUrl: String, pdfTitle: String, sizeTv: TextView){
val TAG = "PDF_SIZE_TAG"
val ref = FirebaseStorage.getInstance().getReferenceFromUrl(pdfUrl)
ref.metadata
.addOnSuccessListener{
Log.d(TAG, "loadPdfSize: get metadata")
val bytes = StorageMetadata().sizeBytes.toDouble()
Log.d(TAG, "loadPdfSize: Size Bytes $bytes")
val kb = bytes/1024
val mb = kb/1024
if(mb>=1){
sizeTv.text = "${String.format("%.2f", mb)} MB"
}else if(kb>=1){
sizeTv.text = "${String.format("%.2f", kb)} KB"
}else {
sizeTv.text = "${String.format("%.2f", bytes)} bytes"
}
}
.addOnFailureListener{ e ->
Log.d(TAG, "loadPdfSize: Failed to get metadata, ERROR: ${e.message}")
}
}
// get the file and its metadata from firebase storage with uri
fun loadPdfFromUrlSinglePage(
pdfUrl: String,
pdfTitle: String,
pdfView: PDFView,
progressBar: ProgressBar,
pagesTv: TextView?
){
val TAG = "PDF_THUMBNAIL_TAG"
val ref = FirebaseStorage.getInstance().getReferenceFromUrl(pdfUrl)
ref.getBytes(Constants.MAX_BYTES_PDF)
.addOnSuccessListener{ bytes ->
Log.d(TAG, "loadPdfSize: Size Bytes $bytes")
// Set pdfView
pdfView.fromBytes(bytes)
.pages(0)
.spacing(0)
.swipeHorizontal(false)
.enableSwipe(false)
.onError { t->
progressBar.visibility = View.INVISIBLE
Log.d(TAG, "loadPdfFromUrlSinglePage: ${t.message}")
}
.onPageError{ page, t ->
progressBar.visibility = View.INVISIBLE
Log.d(TAG, "loadPdfFromUrlSinglePage: ${t.message}")
}
.onLoad { nbPages ->
Log.d(TAG, "loadPdfFromUrlSinglePage: pages - $nbPages")
progressBar.visibility = View.INVISIBLE
// if pagesTv param is not null
if(pagesTv != null){
pagesTv.text = "$nbPages"
}
}
.load()
}
.addOnFailureListener{ e ->
Log.d(TAG, "loadPdfSize: Failed to get metadata, ERROR: ${e.message}")
}
}
// get category title with categoryId
fun loadCategory(categoryId: String, categoryTv: TextView){
val ref = FirebaseDatabase.getInstance().getReference("Categories")
ref.child(categoryId)
.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
val category: String = "${snapshot.child("category").value}"
categoryTv.text = category
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
}
)
}
}
}
3.AdapterPdfAdmin 데이터 핸들링
override fun onBindViewHolder(holder: HolderPdfAdmin, position: Int) {
// get data
val model = pdfArrayList[position]
val pdfId = model.id
val categoryId = model.categoryId
val title = model.title
val description = model.description
val pdfUrl = model.url
val timestamp = model.timestamp
//convert timestamp to the selected format
val formattedDate = MyApplication.formatTimeStamp(timestamp)
//set data
holder.titleTv.text = title
holder.descriptionTv.text = description
holder.dateTv.text = formattedDate
//get further details
MyApplication.loadCategory(categoryId, holder.categoryTv)
MyApplication.loadPdfFromUrlSinglePage(pdfUrl, title, holder.pdfView, holder.progressBar, null)
MyApplication.loadPdfSize(pdfUrl, title, holder.sizeTv)
}
4.PdfListAdminActivity - 업로드한 pdf 목록 카테고리별 불러오기
private fun loadPdfList() {
// init arrayList
pdfArrayList = ArrayList()
val ref = FirebaseDatabase.getInstance().getReference("Books")
ref.orderByChild("categoryId").equalTo(categoryId)
.addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
pdfArrayList.clear()
for(ds in snapshot.children){
// get data
val model = ds.getValue(ModelPdf::class.java)
// add it to list
if (model != null) {
pdfArrayList.add(model)
Log.d(TAG, "onDataChange: ${model.title} ${model.categoryId}")
}
}
// setup adapter
adapterPdfAdmin = AdapterPdfAdmin(this@PdfListAdminActivity, pdfArrayList)
binding.booksRv.adapter = adapterPdfAdmin
}
override fun onCancelled(error: DatabaseError) {
}
})
}
느낀점: 중간에 geolocation하다가 emulator를 바꾸면서 이것저것 지연이 되었으며 그동안 pdf 업로드 관련 그나마 존재하던 지식조차 증발했다. 그나마 불러오기하고 잘못된 마크 사용으로 디버깅만 하다 보니 조금 다시 기억이 살아나는 거 같기도 하지만 반복을 무수하게 해야지 체득 가능할 듯하다😅
* emulator에 pdf파일 업로드하는 방법 (android 11, api 30 기준)
- 우측 하단 Device File Explorer -> 실행중인 device 선택 -> storage -> emulated -> 0 -> Download - 마우스 우측 클릭 -> Upload
- Emulator -> Files -> Android SDK built for x86 -> Downloads로 들어가면 업로드한 pdf파일 확인 가능
Ref: https://www.youtube.com/channel/UCT132T980-1lhm0hcZFy4ZA
'App > Android Native' 카테고리의 다른 글
Clone project - Book App - Step 9 (comments) (0) | 2021.12.29 |
---|---|
Clone project - Book App - Step 3 (update/delete book info) (0) | 2021.11.01 |
Clone project - Book App - Step 1 (RecyclerView w Filter) (0) | 2021.10.25 |
Android - Unsplash API w retrofit2 - 2 (0) | 2021.10.14 |
Android - Unsplash API w retrofit2 - 1 (0) | 2021.10.08 |
- Total
- Today
- Yesterday
- AndroidWirelessDebug
- mvvm
- flutter
- laravel9
- flutter_android_app_links
- Android
- Laravel
- flutter_storage_not_working_for_the_first_time
- retrofit_generator_conflicts_with_freezed
- android_app_links
- futter_api
- querydslKotlinError
- android_domain
- WirelessDebug
- unsplashAPI
- FlutterWirelessDebuginAOS
- RunAFlutterProjectIniPhoneFromVSCode
- retrofit_toJson()_error
- retrofit_generator
- phplaravel
- flutter_secure_storage_issue_iOS
- querydsl5.0.0jakarta
- Kotlin
- android_app_link_domain_works_with_adb_but_not_works_with_browser
- querydslQclass
- KotlinFlow
- dagger-hilt
- MultipleFirebaseEnvironments
- FirebaseConfigurationForMultipleBuildTypes
- android_app_links_domain
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |