본문 바로가기
Front-end/Android (안드로이드 앱 개발)

Android Studio , Firebase 파이어베이스 : 실시간 데이터베이스 데이터 읽고 쓰기 (like. 인별그램)

by javapp 자바앱 2021. 1. 12.
728x90


시나리오

 

사진 올리기

앨범에서 사진을 선택하고 제목, 내용을 쓴다.

 

데이터 쓰기

사진 올리기 데이터를 파이어베이스 실시간데이터베이스에 저장, 스토리지에 사진을 저장한다.

 

데이터 읽기 (올린 사진 보기)

파이어베이스에서 실시간 데이터베이스 데이터를 가져온다.

 

시나리오

 


사진 올리기

 

올릴 게시물 데이터 객체

<ImageDTO.java>

public class ImageDTO
{
    private String imageUrl;
    private String title;
    private String description;
    private String uid;
    private String userId;
    
    getter setter
}

 

파이어베이스 인스턴스 생성

<UploadActivity.java>

    private FirebaseAuth mAuth;
    private FirebaseStorage storage;
    private FirebaseDatabase database;
    
        mAuth = FirebaseAuth.getInstance();
        storage = FirebaseStorage.getInstance();
        database = FirebaseDatabase.getInstance();

 

스토리지, 실시간 데이터베이스 저장 (쓰기)

JSON 유형 타입 : String, Long , Double, Boolean, Map<String, Object>, List<Object>

 

Uri downloadUrl = task.getResult();

<UploadActivity.java>

더보기


public class UploadActivity extends AppCompatActivity {
   
private Button btnBack, btnOk;
   
private ImageView ivProfile;
   
private TextInputEditText etTitle, etDesc;
   
private String imageUrl="";
   
private int GALLEY_CODE = 10;

   
private FirebaseAuth mAuth;
   
private FirebaseStorage storage;
   
private FirebaseDatabase database;

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView(R.layout.
activity_upload);

       
mAuth = FirebaseAuth.getInstance();
       
storage = FirebaseStorage.getInstance();
       
database = FirebaseDatabase.getInstance();
        initView();
        listener();
    }

   
private void initView()
    {
       
btnBack = (Button)findViewById(R.id.btn_profile_back);
       
btnOk = (Button)findViewById(R.id.btn_profile_Ok);
       
ivProfile = (ImageView)findViewById(R.id.iv_profile);
       
etTitle = (TextInputEditText)findViewById(R.id.dt_profile_title);
        
etDesc =(TextInputEditText)findViewById(R.id.dt_profile_desc);
    }
   
private void listener()
    {
       
btnBack.setOnClickListener(new View.OnClickListener() {
           
@Override
           
public void onClick(View v) {
                onBackPressed();
            }
        });
       
btnOk.setOnClickListener(new View.OnClickListener() {
           
@Override
           
public void onClick(View v) {
               
//파이어베이스에 파일 업로드와 데이터 베이스 저장
               
uploadImg(imageUrl);
            }
        });
       
//이미지 업로드
       
ivProfile.setOnClickListener(new View.OnClickListener() {
           
@Override
           
public void onClick(View v) {
               
//로컬 사진첩으로 넘어간다.
               
Intent intent = new Intent(Intent.ACTION_PICK);
                intent.setType(MediaStore.Images.Media.
CONTENT_TYPE);

                startActivityForResult(intent,
GALLEY_CODE);
            }
        });
    }

   
//사진 고른 돌아오는 코드
   
//로컬 파일에서 업로드
   
@Override
   
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
       
if(requestCode == GALLEY_CODE)
        {
           
imageUrl = getRealPathFromUri(data.getData());
            RequestOptions cropOptions =
new RequestOptions();
            Glide.with(getApplicationContext())
                    .load(
imageUrl)
                    .apply(cropOptions.optionalCircleCrop())
                    .into(
ivProfile);
        }

       
super.onActivityResult(requestCode, resultCode, data);
    }

   
//절대경로를 구한다.
   
private String getRealPathFromUri(Uri uri)
    {
        String[] proj=  {MediaStore.Images.Media.
DATA};
        CursorLoader cursorLoader =
new CursorLoader(this,uri,proj,null,null,null);
        Cursor cursor = cursorLoader.loadInBackground();

        
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        String url = cursor.getString(columnIndex);
        cursor.close();
       
return  url;
    }

   
private void uploadImg(String uri)
    {
       
try {
           
// Create a storage reference from our app
           
StorageReference storageRef = storage.getReference();

            Uri file = Uri.fromFile(
new File(uri));
           
final StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment());
            UploadTask uploadTask = riversRef.putFile(file);


            Task<Uri> urlTask = uploadTask.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();
                    }

                   
// Continue with the task to get the download URL
                   
return riversRef.getDownloadUrl();
                }
            }).addOnCompleteListener(
new OnCompleteListener<Uri>() {
               
@Override
               
public void onComplete(@NonNull Task<Uri> task) {
                   
if (task.isSuccessful())
                    {
                        Toast.makeText(UploadActivity.
this, "업로드 성공", Toast.LENGTH_SHORT).show();

                       
//파이어베이스에 데이터베이스 업로드
                       
@SuppressWarnings("VisibleForTests")
                        Uri downloadUrl = task.getResult();

                        ImageDTO imageDTO =
new ImageDTO();
                        imageDTO.setImageUrl(downloadUrl.toString());
                        imageDTO.setTitle(
etTitle.getText().toString());
                        imageDTO.setDescription(
etDesc.getText().toString());
                        imageDTO.setUid(
mAuth.getCurrentUser().getUid());
                        imageDTO.setUserId(
mAuth.getCurrentUser().getEmail());

                       
//image 라는 테이블에 json 형태로 담긴다.
                        //database.getReference().child("Profile").setValue(imageDTO);
                        //  .push()  : 
데이터가 쌓인다.
                       
database.getReference().child("Profile").push().setValue(imageDTO);

                        Intent intent =
new Intent(getApplicationContext(), UserActivity.class);
                        startActivity(intent);

                    }
else {
                       
// Handle failures
                        // ...
                   
}
                }
            });

        }
catch (NullPointerException e)
        {
            Toast.makeText(UploadActivity.
this, "이미지 선택 안함", Toast.LENGTH_SHORT).show();
        }
    }

}

 

 

사진은 스토리지에 저장하고 저장한 uri(스토리지 경로)를 가져온다

    private void uploadImg(String uri)
    {
        try {
            // Create a storage reference from our app
            StorageReference storageRef = storage.getReference();

            Uri file = Uri.fromFile(new File(uri));
            final StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment());
            UploadTask uploadTask = riversRef.putFile(file);


            Task<Uri> urlTask = uploadTask.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();
                    }

                    // Continue with the task to get the download URL
                    return riversRef.getDownloadUrl();
                }
            }).addOnCompleteListener(new OnCompleteListener<Uri>() {
                @Override
                public void onComplete(@NonNull Task<Uri> task) {
                    if (task.isSuccessful())
                    {
                        Toast.makeText(UploadActivity.this, "업로드 성공", Toast.LENGTH_SHORT).show();

                        //파이어베이스에 데이터베이스 업로드
                        @SuppressWarnings("VisibleForTests")
                        Uri downloadUrl = task.getResult();

                        ImageDTO imageDTO = new ImageDTO();
                        imageDTO.setImageUrl(downloadUrl.toString());
                        imageDTO.setTitle(etTitle.getText().toString());
                        imageDTO.setDescription(etDesc.getText().toString());
                        imageDTO.setUid(mAuth.getCurrentUser().getUid());
                        imageDTO.setUserId(mAuth.getCurrentUser().getEmail());

                        //image 라는 테이블에 json 형태로 담긴다.
                        //database.getReference().child("Profile").setValue(imageDTO);
                        //  .push()  :  데이터가 쌓인다.
                        database.getReference().child("Profile").push().setValue(imageDTO);

                        Intent intent = new Intent(getApplicationContext(), UserActivity.class);
                        startActivity(intent);

                    } else {
                        // Handle failures
                        // ...
                    }
                }
            });

        }catch (NullPointerException e)
        {
            Toast.makeText(UploadActivity.this, "이미지 선택 안함", Toast.LENGTH_SHORT).show();
        }
    }

 

 

실시간데이터 저장하는 부분

                        //image 라는 테이블에 json 형태로 담긴다.
                        //database.getReference().child("Profile").setValue(imageDTO);
                        //  .push()  :  데이터가 쌓인다.
                        database.getReference().child("Profile").push().setValue(imageDTO);

 

 

올린 게시물 엑티비티 (읽기)

<UploadedImageActivity.java>

리싸이클러뷰를 이용하여 데이터 보여준다.

 

옵저버 패턴 ( 값 이벤트 수신대기 )

리스너는 이벤트 발생 시점에 데이터베이스에서 지정된 위치에 있던 데이터를 포함하는 DataSnapshot을 수신합니다. 스냅샷에 대해 getValue()를 호출하면 데이터의 자바 객체 표현이 반환됩니다. 해당 위치에 데이터가 없는 경우 getValue()를 호출하면 null이 반환

 

public class UploadedImageActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private List<ImageDTO> imageDTOList = new ArrayList<>();
    private List<String> uidList = new ArrayList<>();

    private FirebaseDatabase firebaseDatabase;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_uploaded_image);

        firebaseDatabase = FirebaseDatabase.getInstance();
        recyclerView = findViewById(R.id.rcv_uploadedimg);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        final UploadedImageAdapter uploadedImageAdapter = new UploadedImageAdapter(imageDTOList, uidList);
        recyclerView.setAdapter(uploadedImageAdapter);//데이터 넣기기

        //옵저버 패턴 --> 변화가 있으면 클라이언트에 알려준다.
        firebaseDatabase.getReference().child("Profile").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {  //변화된 값이 DataSnapshot 으로 넘어온다.
                //데이터가 쌓이기 때문에  clear()
                imageDTOList.clear();
                for(DataSnapshot ds : dataSnapshot.getChildren())           //여러 값을 불러와 하나씩
                {
                    ImageDTO imageDTO = ds.getValue(ImageDTO.class);
                    imageDTOList.add(imageDTO);
                }
                uploadedImageAdapter.notifyDataSetChanged();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });
    }
}

 

게시물 리싸이클러뷰 어댑터

<UploadedImageAdapter.java>

class UploadedImageAdapter extends RecyclerView.Adapter<UploadedImageAdapter.ViewHolder>
{
    private List<ImageDTO> imageDTOList = new ArrayList<>();
    private List<String> uidList = new ArrayList<>();
    private FirebaseStorage storage;
    private Context context;

    public UploadedImageAdapter(){}
    public UploadedImageAdapter(List<ImageDTO> imageDTOList, List<String> uidList)
    {
        this.imageDTOList = imageDTOList;
        this.uidList = uidList;
        storage = FirebaseStorage.getInstance();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
    {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(R.layout.uploaded_image_item,parent,false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, final int position)
    {
        holder.textViewUser.setText(imageDTOList.get(position).getUserId());
        holder.textViewTitle.setText(imageDTOList.get(position).getTitle());
        holder.textViewDesc.setText(imageDTOList.get(position).getDescription());
        holder.imageViewHeart.setImageResource(R.drawable.favorite_border_black_24dp);

        context = holder.itemView.getContext();
        String url = imageDTOList.get(position).getImageUrl();
        Glide.with(context)
                .load(url)
                .placeholder(R.drawable.g3)
                .into(holder.imageView);

    }

    @Override
    public int getItemCount() {
        return imageDTOList.size();
    }

    //ViewHolder 클래스
    class ViewHolder extends RecyclerView.ViewHolder
    {
        public TextView textViewUser;
        public TextView textViewTitle;
        public TextView textViewDesc;
        public ImageView imageView;
        public ImageView imageViewHeart;

        public ViewHolder(@NonNull View itemView)
        {
            super(itemView);
            textViewUser = itemView.findViewById(R.id.item_user);
            textViewTitle = itemView.findViewById(R.id.item_title); //파라메타 id 찾기
            textViewDesc = itemView.findViewById(R.id.item_desc);
            imageView = itemView.findViewById(R.id.item_image);
            imageViewHeart= itemView.findViewById(R.id.item_heart);
        }
    }
}

 

 


실시간 데이터베이스 개별 쓰기

private void writeNewUser(String userId, String name, String email) {
    User user = new User(name, email);

    mDatabase.child("users").child(userId).setValue(user);
}
mDatabase.child("users").child(userId).child("username").setValue(name);

 

데이터 개별 읽기

 

addValueEventListener() keep listening to query or database reference it is attached to.

But addListenerForSingleValueEvent() executes onDataChange method immediately and after executing that method once, it stops listening to the reference location it is attached to.

    for(DataSnapshot ds : dataSnapshot.getChildren()) {
        String key = ds.getKey();
        String city = ds.child("city").getValue(String.class);
        String name = ds.child("name").getValue(String.class);
    }

 

데이터 업데이트 

Map<String, Object> map = new HashMap<>();
map.put("pushToken", token);

mDatabase.child("users").child(userId).updateChildren(map);

 

데이터 삭제

.removeValue();





.setValue(null);

Map<String, Object> stringObjectMap ... 
.updateChildren(stringObjectMap);

댓글