#java #android #firebase #firebase-realtime-database #android-recyclerview
#java #Android #firebase #firebase-realtime-database #android-recyclerview
Вопрос:
Я новичок в Android, и я создаю приложение, которое отображает загруженные пользователем изображения одежды. Я могу отлично загружать изображения, но по какой-то причине я не могу отображать изображения из базы данных firebase realtime в RecyclerView
. Я искал решение в течение нескольких недель.
Пожалуйста, помогите мне. Большое вам спасибо за ваше время.
TopActivity.java
public class TopActivity extends AppCompatActivity {
FloatingActionButton fab;
//Uploading Images to Firebase
private static final int PICK_IMAGE = 1;
private Uri ImageUri;
ArrayList ImageList = new ArrayList();
private int upload_count = 0;
private ProgressDialog progressDialog;
ArrayList urlStrings;
List<String> imagesEncodedList;
Uri uri,mImageUri;
String imageEncoded;
ArrayList<Uri> mArrayUri = new ArrayList<>();
RecyclerView recyclerView;
DatabaseReference databaseReference,dbreference;
private ArrayList<Tops> topslist;
private TopsAdapter topsAdapter;
private Context mContext;
StorageReference ImageFolder,Folder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_top);
fab = findViewById(R.id.fab);
recyclerView=findViewById(R.id.recyclerView);
GridLayoutManager gridLayoutManager=new GridLayoutManager(TopActivity.this,2);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setHasFixedSize(true);
topslist = new ArrayList<>();
GetDataFromFirebase();
progressDialog = new ProgressDialog(TopActivity.this);
progressDialog.setMessage("Uploading Images Please Wait");
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(intent,PICK_IMAGE);
}
});
}
private void uploadImage(){
urlStrings = new ArrayList<>();
progressDialog.show();
ImageFolder = FirebaseStorage.getInstance().getReference().child("Tops");
for (upload_count = 0; upload_count < mArrayUri.size(); upload_count ) {
Uri IndividualImage = (Uri) mArrayUri.get(upload_count);
final StorageReference ImageName = ImageFolder.child("Top_" IndividualImage.getLastPathSegment());
ImageName.putFile(IndividualImage).addOnSuccessListener(
new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
ImageName.getDownloadUrl().addOnSuccessListener(
new OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
urlStrings.add(String.valueOf(uri));
if (urlStrings.size() == mArrayUri.size()) {
storeLink(urlStrings);
}
}
}
);
}
}
);
}
}
private void storeLink(ArrayList<String> urlStrings) {
HashMap<String,String > hashMap = new HashMap<>();
for (int i = 0; i <urlStrings.size() ; i ) {
hashMap.put("Top " i, urlStrings.get(i));
}
databaseReference = FirebaseDatabase.getInstance().getReference("TopsFolder");
databaseReference.push().setValue(hashMap)
.addOnCompleteListener(
new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(TopActivity.this, "Successfully Uploaded", Toast.LENGTH_SHORT).show();
}
}
}
).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(TopActivity.this, "" e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
progressDialog.dismiss();
ImageList.clear();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
try {
if (requestCode == PICK_IMAGE amp;amp; resultCode == RESULT_OK
amp;amp; null != data) {
imagesEncodedList = new ArrayList<String>();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
if (data.getData() != null) {
mImageUri = data.getData();
// Get the cursor
Cursor cursor = getContentResolver().query(mImageUri,
filePathColumn, null, null, null);
// Move to first row
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
imageEncoded = cursor.getString(columnIndex);
cursor.close();
uploadImage();
} else {
if (data.getClipData() != null) {
ClipData mClipData = data.getClipData();
for (int i = 0; i < mClipData.getItemCount(); i ) {
ClipData.Item item = mClipData.getItemAt(i);
uri = item.getUri();
mArrayUri.add(uri);
// Get the cursor
Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
// Move to first row
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
imageEncoded = cursor.getString(columnIndex);
imagesEncodedList.add(imageEncoded);
cursor.close();
}
Log.v("LOG_TAG", "Selected Images" mArrayUri.size());
uploadImage();
}
}
} else {
Toast.makeText(this, "You haven't picked Image",
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
.show();
}
super.onActivityResult(requestCode, resultCode, data);
}
private void GetDataFromFirebase(){
//Query query=databaseReference.child("TopsFolder/Tops");
//query.addValueEventListener(new ValueEventListener() {
databaseReference = FirebaseDatabase.getInstance().getReference();
dbreference=databaseReference.child("TopsFolder");
ValueEventListener eventListener = new ValueEventListener() {
@Override
public void onDataChange( DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
Tops tops=ds.child("TopsFolder").getValue(Tops.class);
topslist.add(tops);
}
topsAdapter= new TopsAdapter(getApplicationContext(),topslist);
recyclerView.setAdapter(topsAdapter);
topsAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
};
dbreference.addListenerForSingleValueEvent(eventListener);
}
}
TopsAdapter.java
public class TopsAdapter extends RecyclerView.Adapter<TopsAdapter.ViewHolder> {
private static final String Tag="RecyclerView";
private Context mContext;
private ArrayList<Tops> topslist;
public TopsAdapter(Context mContext, ArrayList<Tops> topslist) {
this.mContext = mContext;
this.topslist = topslist;
}
@NonNull
@Override
public TopsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext())
.inflate(R.layout.top_rv_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Glide.with(mContext)
.load(topslist.get(position).getTop())
.into(holder.ivTopGallery);
}
@Override
public int getItemCount() {
return topslist.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView ivTopGallery;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ivTopGallery=itemView.findViewById(R.id.ivTopGallery);
}
}
}
Tops.java
public class Tops {
//Model Class
public String top;
//Constructors
public Tops(){}
public Tops(String top) {
this.top = top;
}
public String getTop() {
return top;
}
public void setTop(String top) {
this.top = top;
}
}
top_rv_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_height="150dp"
android:layout_width="150dp"
android:padding="10dp"
android:id="@ id/ivTopGallery"
android:scaleType="fitXY"
/>
</LinearLayout>
Вот моя структура базы данных.
Обновление итак, я изменил свой код, чтобы соответствовать структуре данных
Firebase-root
|
--- TopsFolder
|
--- pushedId
| |
| --- top: "https://..."
|
--- pushedId
|
--- top: "https://..."
Вот изменения, которые я внес в свой TopsActivity.java
private void storeLink(ArrayList<String> urlStrings) {
HashMap<String, String> hashMap = new HashMap<>();
databaseReference = FirebaseDatabase.getInstance().getReference("TopsFolder");
for (int i = 1; i <urlStrings.size() ; i ) {
hashMap.put("Top " i, urlStrings.get(i));
databaseReference.push().setValue(hashMap);
}
progressDialog.dismiss();
Toast.makeText(TopActivity.this, "Successfully Uploaded", Toast.LENGTH_SHORT).show();
ImageList.clear();
}
теперь я получаю это как свою структуру данных. Что мне сделать, чтобы получить его в формате, указанном выше?
Ответ №1:
Ваша база данных фактически хранит список String
under TopsFolder
node, и вам нужно получить их в виде списка строк. Поэтому я бы рекомендовал изменить вашу onDataChange
реализацию внутри GetDataFromFirebase
функции следующим образом.
@Override
public void onDataChange( DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
// You should have the elements as an array of string.
Tops[] tops = ds.child("TopsFolder").getValue(Tops[].class);
if (topList != null) toplist.clear(); // Clear the list if there's anything already in the list
topslist = Arrays.asList(tops); // Assign the items to the list from the array that you retrieved from firebase database.
}
topsAdapter= new TopsAdapter(getApplicationContext(), topslist);
recyclerView.setAdapter(topsAdapter);
topsAdapter.notifyDataSetChanged();
}
Это должно решить вашу проблему.
Ответ №2:
Вы не можете сопоставить объекты, которые существуют под TopsFolder
узлом, с объектами типа Tops
, потому что ни один из этих объектов фактически не представляет объект типа Tops
. Однако, если вам нужно сопоставить каждый объект с Tops
объектом, вам необходимо реструктурировать вашу схему следующим образом:
Firebase-root
|
--- TopsFolder
|
--- pushedId
| |
| --- top: "https://..."
|
--- pushedId
|
--- top: "https://..."
Таким образом, каждый объект TopsFolder
представляет Tops
объект. Смотрите, имя свойства — «top», как в вашем Tops
классе, а «значение» — это фактический URL. Требуемый код должен выглядеть следующим образом:
@Override
public void onDataChange( DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String url = ds.getValue(String.class);
if (topList != null) toplist.clear(); // Clear the list if there's anything already in the list
topslist.add(url);
}
topsAdapter= new TopsAdapter(getApplicationContext(), topslist);
recyclerView.setAdapter(topsAdapter);
topsAdapter.notifyDataSetChanged();
}
Редактировать:
Tops tops = new Tops("https://...");
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference topFolderRef = rootRef.child("TopsFolder");
topFolderRef.push().setValue(tops);
Пожалуйста, также не забудьте сделать top
свойство закрытым в вашем Tops
классе.
Комментарии:
1. Привет, спасибо за ответ. Извините, но какие изменения я должен внести в свой TopsActivity.java чтобы мои изображения сохранялись в базе данных реального времени в соответствии со структурой, которую вы показали. Спасибо за ваше время
2. Пожалуйста, проверьте мой обновленный ответ и скажите мне, работает ли он.
3. Привет, я внес некоторые изменения, не могли бы вы проверить обновление, которое я внес в свой вопрос, и помочь мне? Большое вам спасибо
4.Нет, это все еще неверно! Ключи всегда должны быть «top», как имя свойства в вашем классе, а НЕ
Top 1
,Top 2
, и так далее. Один дочерний элемент должен содержать только одинtop: "https://..."
, потому что у вас есть только одно свойство в вашем классе, хорошо?5. Мне очень жаль, но не могли бы вы сказать мне, какие изменения нужно внести в код, чтобы получить структуру, о которой вы упомянули, потому что в приложении пользователь должен выбирать изображения из галереи телефона, и они загружаются в firebase. Я не могу использовать theis
Tops tops = new Tops("https://...");
Ответ №3:
вы можете использовать библиотеку Picasso implementation 'com.squareup.picasso:picasso:2.5.2'
, это работает для меня.
public static void setUrlImageInView(Context context, String url, ImageView view) {
// (optional) use Picasso to download and show to image
Picasso.with(context).load(url).into(view);
}
Еще одна вещь, которую следует учитывать, это то, что вы снова получаете данные от того же дочернего элемента. Вы должны использовать идентификатор документа в вашем примере
Tops tops=ds.child("-MIPf9A2H_.....").getValue(Tops.class);
topslist.add(tops);