Android Firebase多个图像上传 [英] Android Firebase multiple image upload
问题描述
我正在编写一个应用来测试Firebase,用户可以在其中列出带有图像的产品. 我在上传时遇到问题,因为图片已存储,但未链接到产品(图像数组未传递?),并且LeakCanary发出内存不足错误的信号. 感谢所有帮助和投入.
I am writing an app to test out firebase where a user can list a product with images. I'm having issues with the upload as although the pictures are stored, they are not linked to the product (images array not being passed?) and LeakCanary signals an outofmemory error. All help and input appreciated.
这是我的产品型号
@IgnoreExtraProperties
public class Product {
public String uid;
public String seller;
public String name;
public String description;
public String city;
public double price = 0.0;
public List<Uri> images = new ArrayList<>();
public Product () {
}
public Product(String uid, String seller, String name, String description, String city, double price, List<Uri> images) {
this.uid = uid;
this.seller = seller;
this.name = name;
this.description = description;
this.city = city;
this.price = price;
this.images = images;
}
// [START post_to_map]
@Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("uid", uid);
result.put("seller", seller);
result.put("name", name);
result.put("description", description);
result.put("city", city);
result.put("price", price);
result.put("images", images);
return result;
}
}
这是我的AddProductActivity
And here are is my AddProductActivity
public class AddProductActivity extends BaseActivity implements AddProductContract.View, View.OnClickListener {
private AddProductContract.Presenter mPresenter;
private Bitmap mBitmap;
private byte[] mByteArray;
private List<String> mPhotos;
private Button mPublishBtn;
private EditText mProductNameField;
private EditText mProductDescriptionField;
private EditText mProductPriceField;
private DatabaseReference mFirebaseDatabase;
private StorageReference mFirebaseStorage;
private StorageTask mUploadTask;
private List<Uri> uploadedImages = new ArrayList<>();
private LinearLayout mLinearLayout;
private ImageButton mImageButton;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data == null) {
showEmptyImageError();
} else {
mPhotos = (List<String>) data.getSerializableExtra(GalleryActivity.PHOTOS);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_edit_product_2);
mFirebaseDatabase = FirebaseDatabase.getInstance().getReference();
mFirebaseStorage = FirebaseStorage.getInstance().getReference();
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
mToolbar.setTitle(R.string.addItemTextview);
mLinearLayout = (LinearLayout) findViewById(R.id.activity_add_product);
mLinearLayout.setOnClickListener(this);
mImageButton = (ImageButton) findViewById(R.id.imageButton);
mImageButton.setOnClickListener(this);
mPublishBtn = (Button) findViewById(R.id.publishItemBtn);
mPublishBtn.setOnClickListener(this);
mProductNameField = (EditText) findViewById(R.id.productNameField);
mProductDescriptionField = (EditText) findViewById(R.id.productDescriptionField);
mProductPriceField = (EditText) findViewById(R.id.priceField);
// mPresenter = new AddProductPresenter(this);
}
@Override
public void onClick(View view) {
if ((view == mLinearLayout)) {
hideKeyboard();
} else if (view == mImageButton) {
GalleryConfig config = new GalleryConfig.Build()
.limitPickPhoto(8)
.singlePhoto(false)
.hintOfPick("You can pick up to 8 pictures.")
.filterMimeTypes(new String[]{"image/*"})
.build();
GalleryActivity.openActivity(AddProductActivity.this, 2, config);
} else if (view == mPublishBtn) {
final String name = mProductNameField.getText().toString();
final String description = mProductDescriptionField.getText().toString();
final double price = Double.parseDouble(mProductPriceField.getText().toString());
setPublishingEnabled(false);
showErrorToast(getResources().getString(R.string.publishing));
final String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mFirebaseDatabase.child("users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
if (user == null) {
showErrorToast(getResources().getString(R.string.empty_user));
} else {
publishProduct(userId, user.getUsername(), name, description,
user.getCity(), price, mPhotos);
}
setPublishingEnabled(true);
finish();
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("AddProductActivity", "getUser:onCancelled", databaseError.toException());
setPublishingEnabled(true);
}
}
);
}
}
private void setPublishingEnabled(boolean enabled) {
if (enabled) {
mPublishBtn.setVisibility(View.VISIBLE);
} else {
mPublishBtn.setVisibility(View.GONE);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle arrow click here
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
@Override
public void showEmptyImageError() {
Toast.makeText(getApplicationContext(), R.string.empty_image_error, Toast.LENGTH_SHORT).show();
}
private void publishProduct(String userId, String seller, String name, String description,
String city, double price, List<String> images) {
for (String photo : images) {
Uri file = Uri.fromFile(new File(photo));
StorageReference photoRef = mFirebaseStorage.child("images/" + file.getLastPathSegment());
mUploadTask = photoRef.putFile(file);
mUploadTask.addOnFailureListener(exception -> Log.i("It didn't work", "double check"))
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
uploadedImages.add(downloadUrl);
}
});
}
String key = mFirebaseDatabase.child("products").push().getKey();
Product product = new Product(userId, seller, name, description, city, price, uploadedImages);
Map<String, Object> productValues = product.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/products/" + key, productValues);
childUpdates.put("/user-products/" + userId + "/" + key, productValues);
mFirebaseDatabase.updateChildren(childUpdates);
}
//
// private List<Uri> uploadPhotos(List<String> input) {
// images = new ArrayList<>();
// Observable.just(input)
// .map(this::doInBackground)
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .doOnSubscribe(this::onPreExecute)
// .subscribe(this::onPostExecute);
// return images;
// }
//
// private void onPreExecute() {
// Log.i("Start time", "SET");
// Toast.makeText(this, R.string.image_formatting_toast, Toast.LENGTH_SHORT).show();
// }
//
// private List<Uri> doInBackground(List<String> photos) {
// for (String photo : mPhotos) {
// Uri file = Uri.fromFile(new File(photo));
// StorageReference photoRef = mFirebaseStorage.child("images/" + file.getLastPathSegment());
// mUploadTask = photoRef.putFile(file);
//
// mUploadTask.addOnFailureListener(exception -> Log.i("It didn't work", "double check"))
// .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
// @Override
// public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// Uri downloadUrl = taskSnapshot.getDownloadUrl();
// images.add(downloadUrl);
// }
// });
// }
// return images;
// }
//
// private void onPostExecute(List<Uri> uriSet) {
// Toast.makeText(this, R.string.product_visibility_toast, Toast.LENGTH_SHORT).show();
// Log.i("End time", "SET");
// }
}
推荐答案
尝试了解您的代码流,我可以看到一件事:
Trying to understand your code flow, I can see one thing:
在您的publishProduct
方法内部,应将代码(以更新Firebase中的childeren)放入addOnSuccessListener
中,如下所示:
inside your publishProduct
method you should put the code (to update the childeren in Firebase) into the addOnSuccessListener
, like this:
private void publishProduct(String userId, String seller, String name, String description,
String city, double price, List<String> images) {
String key = mFirebaseDatabase.child("products").push().getKey();
for (String photo : images) {
Uri file = Uri.fromFile(new File(photo));
StorageReference photoRef = mFirebaseStorage.child("images/" + file.getLastPathSegment());
mUploadTask = photoRef.putFile(file);
mUploadTask.addOnFailureListener(exception -> Log.i("It didn't work", "double check"))
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
uploadedImages.add(downloadUrl);
Product product = new Product(userId, seller, name, description, city, price, uploadedImages);
Map<String, Object> productValues = product.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/products/" + key, productValues);
childUpdates.put("/user-products/" + userId + "/" + key, productValues);
mFirebaseDatabase.updateChildren(childUpdates);
}
});
}
}
并且,如果您想知道updateChildren
操作是否完成,请添加onComplete和onFailure侦听器,如下所示:
And, if you want to know if the updateChildren
operation is completed or not, add the onComplete and onFailure listeners, like this:
mFirebaseDatabase.updateChildren(childUpdates).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
});
更新
我认为您可以尝试更改数据库结构,从产品的节点中删除图像列表,而在数据库中添加一个节点,该节点将仅存储与每个产品关联的图像列表:
I think you can try to change your database structure, removing the list of images from the product's nodes, adding instead a node in your database that will store only the list of images associated with each product:
"/product-images/" + yourKey + "/" + imageKey
包含他的图像列表. imageKey
与一个图像与另一个图像不同(例如,图像名称). yourKey
可以是userId
或与每个产品关联的密钥,这取决于数据库的结构.然后,您可以尝试在OnSuccessListener
中使用setValue
而不是updateChildren
,如下所示:
contains the list of his images. imageKey
is different from one image the another (it could be for example the image name). yourKey
could be the userId
or the key associated with each product, it depends on how the database is structured. Then, you can try to use setValue
instead of updateChildren
into your OnSuccessListener
, something like this:
mUploadTask.addOnFailureListener(exception -> Log.i("It didn't work", "double check"))
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
mFirebaseDatabase.child("product-images").child(yourKey).child(imageKey).setValue(downloadUrl.toString());
}
});
希望这会有所帮助!
这篇关于Android Firebase多个图像上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!