일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 글쓰기클럽
- 본앤메이드사용설명서
- 앱부업
- 본앤메이드신발살균건조기
- 전원 꽂을 곳이 있는 카페
- 흙회장
- 흙크루글쓰기클럽1기
- 카공족 인 척하는 아줌마
- 화이자3차접종간격
- k.kakaocdn.net
- 생활환경안전정보시스템
- 실발살균건조기
- 경기도청년면접수당모집
- 빈속에 티라미슈는 무거워
- 본앤메이드
- 카페 FLORA
- 초록누리홈페이지
- 유튜브준비중
- 스마트 스토어 창업
- 안눕법 실
- 깔끔한 꽃차 좋아
- 환경부 초록누리
- 초록누리 사이트
- 비오는날신발말리는방법
- 매일글쓰기
- 화이자3차접종
- 화이자 3차 후기
- 네이버 스마트 스토어
- 카카오뷰
- 화이자 3차부작용
- Today
- Total
우물안에서 보는 하늘도 맑다
힐링 #18 - 오틸라의 안드로이드 앱 만들기 강좌 본문
* 이벤트를 안 받았을 때, 글쓰기 버튼이 안보이는 문제 발생
- 어떤 현상인지 확인은 못해봄. 나중에 확인 해 볼 것~!!!
* Firebase에서 board에 데이타를 추가 할 때, 키값으로 데이타를 입력함
- setValue 로 데이타를 넣으면서 자동으로 지정된 키값 말고
날짜와 시간으로 가공한 idx 값을 이용하여 데이타를 입력 해서, 검색하고 reply를 count 할 수 있게 수정 함
더불어, "0" String으로 지정된, reply와 count와 heart를 0 int 형으로 변경함
firebase와 code상에도 모두 변경함
- 기존에 키값으로 자동으로 입력된 상태
- 변경 후, idx로 입력된 상태
* 댓글을 입력하면 댓글 수가 표시되고, Firebase에 reply 컬럼이 변경됨
* 오류1
- MainAdapter.java 에서
iviewholder.itemReply.setText(idata.reply);
iviewholder.itemCount.setText(idata.count);
를
iviewholder.itemReply.setText(String.valueOf(idata.reply));
iviewholder.itemCount.setText(String.valueOf(idata.count));
변경함
에러메세지 | |
D/AndroidRuntime: Shutting down VM E/AndroidRuntime: FATAL EXCEPTION: main Process: com.bliss.csc.agmhealing, PID: 11129 android.content.res.Resources$NotFoundException: String resource ID #0x0 at android.content.res.Resources.getText(Resources.java:444) at android.widget.TextView.setText(TextView.java:6412) at com.bliss.csc.agmhealing.Adapter.MainAdapter.onBindViewHolder(MainAdapter.java:117) |
* 오류2
- 첫번째 글과 두번째 글 사이에 이미지가 없을 때, 글 아래 댓글 등 기능이 있는 부분이 나타나지 않음
- 이미지 영역이 너무 확장 되어 기능 버튼이 보이지 않거나
- 이미지가 없는 글에 경우, 기능 버튼 아래에 불필요한 하얀 영역이 보임
- CardView에 높이layout_height를 match_parent 에서 wrap_content로 변경 한 후, 아래 댓글 기능 부분이 잘 보임
* 스토리지에 저장된 이미지가 보이지 않음
- 원인 : Storage에 저장된 이미지Url과 이벤트 Task에서 받아온 Url이 다름
Image URL | ||
Storage 저장된 Image URL | firebasestorage.googleapis.com/v0/b/agmhealing3.appspot.com/o/board%2F20201226_113859_0.jpg?alt=media&token=72c525e0-01f0-48f5-89fa-fbb104281328 | 이미지 보임 |
addOnSuccessListener이벤트 내에서 downloadUrlTask.getResult()로 받아온 Image URL | firebasestorage.googleapis.com/v0/b/agmhealing3.appspot.com/o?name=board%2F20201004_144804_1.jpg&uploadType=resumable&upload_id=ABg5-UxO7PiemtnQeB7dvxlNIXrOW4En5ELHFibbQLedqkosQ56dzeoNOGPwyqBlfRZpH0r0K-NinVFK7xkWUCnHdaJdLSqcEA&upload_protocol=resumable | 잘못된 경로 이미지 안보임 |
- 해결방법
Firebase 에 Storage 개발자문서(아래)를 참고하여 URL을 받아 올 수 있게 수정하고
실제 실행 했을 때, Storage에 이미지가 정상적으로 저장되어도 task.isSuccessful()이 false로 되어
이미지URL을 받아오지 않는 문제가 추가로 발생 했다
그래서 이미지 저장 성공여부를 task.isSuccessful()로 확인하지 않고
task.getResult()로 받아온 URL에 정보가 있는지 없는지 여부를 확인하여 처리 했더니 정상적으로 동작하고
URL도 잘 받아와졌다
- 참고 : firebase.google.com/docs/storage/android/upload-files?authuser=0
- 수정 전 소스
WriteActivity.java 중 | |
final ItemData idata = new ItemData(); String image_time = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()); idata.idx = image_time; idata.reg_user = ap.getNickname(); idata.profile = ap.getProfileImage(); idata.title = etTitle.getText().toString(); idata.summary = etContent.getText().toString(); //idata.image = ""; idata.heart = 0; idata.reply = 0; idata.more = "0"; idata.count = 0; idata.reg_date = new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()); if(mList.size() > 0){ int imageCount = 0; //이미지를 업로드를 할 경우 for(ContentData cdata : mList){ ByteArrayOutputStream baos = new ByteArrayOutputStream(); cdata.Bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] data = baos.toByteArray(); mountainsRef = storageRef.child("board/"+image_time+"_"+imageCount+".jpg"); UploadTask uploadTask = mountainsRef.putBytes(data); //async 비동기 uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { idata.image += "none,"; } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { Task<Uri> downloadUrlTask = storageRef.getDownloadUrl();//getDownloadUrl Uri downUri = downloadUrlTask.getResult(); idata.image += downUri.toString()+","; doInsert(idata, true); } }); imageCount++; }//for end |
- 수정 후 소스
WriteActivity.java 중 | |
final ItemData idata = new ItemData(); String image_time = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()); idata.idx = image_time; idata.reg_user = ap.getNickname(); idata.profile = ap.getProfileImage(); idata.title = etTitle.getText().toString(); idata.summary = etContent.getText().toString(); //idata.image = ""; idata.heart = 0; idata.reply = 0; idata.more = "0"; idata.count = 0; idata.reg_date = new SimpleDateFormat("yyyy-MM-dd", Locale.US).format(new Date()); if(mList.size() > 0){ int imageCount = 0; //이미지를 업로드를 할 경우 for (ContentData cdata : mList) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); cdata.Bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] data = baos.toByteArray(); mountainsRef = storageRef.child("board/" + image_time + "_" + imageCount + ".jpg"); final StorageReference finalMountainsRef = mountainsRef; Task<Uri> uploadTask = mountainsRef.putBytes(data).continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() { @Override public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception { if (!task.isSuccessful()) { throw task.getException(); } return finalMountainsRef.getDownloadUrl(); } }).addOnCompleteListener(new OnCompleteListener<Uri>() { @Override public void onComplete(@NonNull Task<Uri> task) { Uri downloadUri = task.getResult(); //Toast.makeText(WriteActivity.this, "succesful : 이미지 첨부 파일 있음" + downloadUri.toString(), Toast.LENGTH_SHORT).show(); Log.d("WriteActivity : ","succesful : 이미지 첨부 파일 있음 : downloadUri.toString() = "+downloadUri.toString()); if(downloadUri != null){ idata.image += downloadUri.toString() + ","; doInsert(idata, true); }else{ idata.image += "none,"; doInsert(idata, false); } } }); imageCount++; }//for end |
- 수정 중 발생한 오류 메세지
.FileNotFoundException 이 발생함
오류메세지 | |
Load failed for none with size [378x1750] class com.bumptech.glide.load.engine.GlideException: Failed to load resource There were 3 causes: java.io.FileNotFoundException(/none: open failed: ENOENT (No such file or directory)) java.io.FileNotFoundException(open failed: ENOENT (No such file or directory)) java.io.FileNotFoundException(open failed: ENOENT (No such file or directory)) call GlideException#logRootCauses(String) for more detail Cause (1 of 3): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, LOCAL There was 1 cause: java.io.FileNotFoundException(/none: open failed: ENOENT (No such file or directory)) call GlideException#logRootCauses(String) for more detail Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed There was 1 cause: java.io.FileNotFoundException(/none: open failed: ENOENT (No such file or directory)) call GlideException#logRootCauses(String) for more detail Cause (1 of 1): class java.io.FileNotFoundException: /none: open failed: ENOENT (No such file or directory) Cause (2 of 3): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class android.os.ParcelFileDescriptor, LOCAL There was 1 cause: java.io.FileNotFoundException(open failed: ENOENT (No such file or directory)) call GlideException#logRootCauses(String) for more detail Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed There was 1 cause: java.io.FileNotFoundException(open failed: ENOENT (No such file or directory)) call GlideException#logRootCauses(String) for more detail Cause (1 of 1): class java.io.FileNotFoundException: open failed: ENOENT (No such file or directory) Cause (3 of 3): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class android.content.res.AssetFileDescriptor, LOCAL There was 1 cause: java.io.FileNotFoundException(open failed: ENOENT (No such file or directory)) call GlideException#logRootCauses(String) for more detail Cause (1 of 1): class java.io.FileNotFoundException: open failed: ENOENT (No such file or directory) 2021-03-23 13:19:43.952 7911-7911/com.bliss.csc.agmhealing I/Glide: Root cause (1 of 3) java.io.FileNotFoundException: /none: open failed: ENOENT (No such file or directory) at libcore.io.IoBridge.open(IoBridge.java:492) at java.io.FileInputStream.<init>(FileInputStream.java:160) at java.io.FileInputStream.<init>(FileInputStream.java:115) at android.content.ContentResolver.openInputStream(ContentResolver.java:1473) at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResourceFromUri(StreamLocalUriFetcher.java:74) at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResource(StreamLocalUriFetcher.java:50) at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResource(StreamLocalUriFetcher.java:13) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:44) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279) at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:393) Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory) at libcore.io.Linux.open(Native Method) at libcore.io.ForwardingOs.open(ForwardingOs.java:166) at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254) at libcore.io.ForwardingOs.open(ForwardingOs.java:166) at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7542) at libcore.io.IoBridge.open(IoBridge.java:478) at java.io.FileInputStream.<init>(FileInputStream.java:160) at java.io.FileInputStream.<init>(FileInputStream.java:115) at android.content.ContentResolver.openInputStream(ContentResolver.java:1473) at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResourceFromUri(StreamLocalUriFetcher.java:74) at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResource(StreamLocalUriFetcher.java:50) at com.bumptech.glide.load.data.StreamLocalUriFetcher.loadResource(StreamLocalUriFetcher.java:13) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:44) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279) at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:393) 2021-03-23 13:19:43.956 7911-7911/com.bliss.csc.agmhealing I/Glide: Root cause (2 of 3) java.io.FileNotFoundException: open failed: ENOENT (No such file or directory) at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:344) at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:231) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1793) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1714) at com.bumptech.glide.load.data.FileDescriptorLocalUriFetcher.loadResource(FileDescriptorLocalUriFetcher.java:20) at com.bumptech.glide.load.data.FileDescriptorLocalUriFetcher.loadResource(FileDescriptorLocalUriFetcher.java:12) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:44) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.onDataFetcherFailed(DecodeJob.java:408) at com.bumptech.glide.load.engine.SourceGenerator.onLoadFailedInternal(SourceGenerator.java:160) at com.bumptech.glide.load.engine.SourceGenerator$1.onLoadFailed(SourceGenerator.java:83) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.startNextOrFail(MultiModelLoader.java:167) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onLoadFailed(MultiModelLoader.java:154) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:49) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279) at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:393) 2021-03-23 13:19:43.998 7911-7911/com.bliss.csc.agmhealing I/Glide: Root cause (3 of 3) java.io.FileNotFoundException: open failed: ENOENT (No such file or directory) at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:344) at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:231) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1793) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1714) at com.bumptech.glide.load.data.AssetFileDescriptorLocalUriFetcher.loadResource(AssetFileDescriptorLocalUriFetcher.java:20) at com.bumptech.glide.load.data.AssetFileDescriptorLocalUriFetcher.loadResource(AssetFileDescriptorLocalUriFetcher.java:11) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:44) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.onDataFetcherFailed(DecodeJob.java:408) at com.bumptech.glide.load.engine.SourceGenerator.onLoadFailedInternal(SourceGenerator.java:160) at com.bumptech.glide.load.engine.SourceGenerator$1.onLoadFailed(SourceGenerator.java:83) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.startNextOrFail(MultiModelLoader.java:167) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onLoadFailed(MultiModelLoader.java:154) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:49) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.onDataFetcherFailed(DecodeJob.java:408) at com.bumptech.glide.load.engine.SourceGenerator.onLoadFailedInternal(SourceGenerator.java:160) at com.bumptech.glide.load.engine.SourceGenerator$1.onLoadFailed(SourceGenerator.java:83) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.startNextOrFail(MultiModelLoader.java:167) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onLoadFailed(MultiModelLoader.java:154) at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:49) at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:70) at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279) at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:393) java.io.IOException: Invalid device key response. at huk.a(:com.google.android.gms@201817022@20.18.17 (040700-311416286):46) at hui.a(:com.google.android.gms@201817022@20.18.17 (040700-311416286):41) at hud.a(:com.google.android.gms@201817022@20.18.17 (040700-311416286):0) at hug.a(:com.google.android.gms@201817022@20.18.17 (040700-311416286):10) at fzn.call(:com.google.android.gms@201817022@20.18.17 (040700-311416286):5) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at sji.b(:com.google.android.gms@201817022@20.18.17 (040700-311416286):12) at sji.run(:com.google.android.gms@201817022@20.18.17 (040700-311416286):7) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at spj.run(:com.google.android.gms@201817022@20.18.17 (040700-311416286):0) at java.lang.Thread.run(Thread.java:923) |
* 오틸라의 안드로이드 앱 만들기 강좌 : 힐링 # 18
* 다음은 삭제 기능 고고고~!
하지만!! 위에 기능버튼(댓글수 표시, 하트수 표시 등)들이 안보이는 오류 수정하고 19강으로 갈것!!
* Festina lente 님 블로그 글 참조~!
- Cloud Firestore 와 Realtime database에 차이를 깔끔하게 정리 해 놓으셨음
'경단녀에서 "나"로 돌아가기 > 안드로이드' 카테고리의 다른 글
힐링 #19- 오틸라의 안드로이드 앱 만들기 강좌 (0) | 2021.02.06 |
---|---|
안드로이드 스튜디오 4.1 업데이트 중, org.jetbrains.android 오류 그리고 해결 (0) | 2021.01.20 |
오틸라의 안드로이드 앱 만들기 강좌 : 힐링 #17 (0) | 2020.12.19 |
오틸라의 안드로이드 앱 만들기 강좌 : 힐링 #15 (0) | 2020.11.29 |
오틸라의 안드로이드 앱 만들기 강좌 : 힐링 #14 (0) | 2020.11.20 |