当我尝试捕获图像或将图像从图库上载到Firebase时出现此错误。我知道在问过这个问题之前,我尝试了所有可能的解决方案。
这是清单文件:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
以下是logcat报告:
ImageLoader must be init with configuration before using
at com.nostra13.universalimageloader.core.ImageLoader.checkConfiguration(ImageLoader.java:613)
at com.nostra13.universalimageloader.core.ImageLoader.displayImage(ImageLoader.java:236)
at com.nostra13.universalimageloader.core.ImageLoader.displayImage(ImageLoader.java:209)
at com.nostra13.universalimageloader.core.ImageLoader.displayImage(ImageLoader.java:316)
at com.example.sahil.ignite.util.UniversalImageLoader.setImage(UniversalImageLoader.java:55)
at com.example.sahil.ignite.fragments.PostFragment.getImagePath(PostFragment.java:48)
at com.example.sahil.ignite.SelectPhotoDialog.onActivityResult(SelectPhotoDialog.java:72)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:156)
at android.app.Activity.dispatchActivityResult(Activity.java:6317)
PostFragment.java
public class PostFragment extends Fragment implements SelectPhotoDialog.OnPhotoSelectedListener {
private static final String TAG = "PostFragment";
@Override
public void getImagePath(Uri imagePath) {
Log.d(TAG, "getImagePath: setting the image to imageview");
UniversalImageLoader.setImage(imagePath.toString(), mPostImage);
//assign to global variable
mSelectedBitmap = null;
mSelectedUri = imagePath;
}
@Override
public void getImageBitmap(Bitmap bitmap) {
Log.d(TAG, "getImageBitmap: setting the image to imageview");
mPostImage.setImageBitmap(bitmap);
//assign to a global variable
mSelectedUri = null;
mSelectedBitmap = bitmap;
}
//widgets
private ImageView mPostImage;
private EditText mTitle, mDescription, mPrice, mCountry, mStateProvince, mCity, mContactEmail;
private Button mPost;
private ProgressBar mProgressBar;
//vars
private Bitmap mSelectedBitmap;
private Uri mSelectedUri;
private byte[] mUploadBytes;
private double mProgress = 0;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_post, container, false);
mPostImage = view.findViewById(R.id.post_image);
mTitle = view.findViewById(R.id.input_title);
mDescription = view.findViewById(R.id.input_description);
mPrice = view.findViewById(R.id.input_price);
mCountry = view.findViewById(R.id.input_country);
mStateProvince = view.findViewById(R.id.input_state_province);
mCity = view.findViewById(R.id.input_city);
mContactEmail = view.findViewById(R.id.input_email);
mPost = view.findViewById(R.id.btn_post);
mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar);
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
init();
return view;
}
private void init(){
mPostImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: opening dialog to choose new photo");
SelectPhotoDialog dialog = new SelectPhotoDialog();
dialog.show(getFragmentManager(), getString(R.string.dialog_select_photo));
dialog.setTargetFragment(PostFragment.this, 1);
}
});
mPost.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: attempting to post...");
if(!isEmpty(mTitle.getText().toString())
&& !isEmpty(mDescription.getText().toString())
&& !isEmpty(mPrice.getText().toString())
&& !isEmpty(mCountry.getText().toString())
&& !isEmpty(mStateProvince.getText().toString())
&& !isEmpty(mCity.getText().toString())
&& !isEmpty(mContactEmail.getText().toString())){
//we have a bitmap and no Uri
if(mSelectedBitmap != null && mSelectedUri == null){
uploadNewPhoto(mSelectedBitmap);
}
//we have no bitmap and a uri
else if(mSelectedBitmap == null && mSelectedUri != null){
uploadNewPhoto(mSelectedUri);
}
}else{
Toast.makeText(getActivity(), "You must fill out all the fields", Toast.LENGTH_SHORT).show();
}
}
});
}
private void uploadNewPhoto(Bitmap bitmap){
Log.d(TAG, "uploadNewPhoto: uploading a new image bitmap to storage");
BackgroundImageResize resize = new BackgroundImageResize(bitmap);
Uri uri = null;
resize.execute(uri);
}
private void uploadNewPhoto(Uri imagePath){
Log.d(TAG, "uploadNewPhoto: uploading a new image uri to storage.");
BackgroundImageResize resize = new BackgroundImageResize(null);
resize.execute(imagePath);
}
public class BackgroundImageResize extends AsyncTask<Uri, Integer, byte[]>{
Bitmap mBitmap;
public BackgroundImageResize(Bitmap bitmap) {
if(bitmap != null){
this.mBitmap = bitmap;
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(getActivity(), "compressing image", Toast.LENGTH_SHORT).show();
showProgressBar();
}
@Override
protected byte[] doInBackground(Uri... params) {
Log.d(TAG, "doInBackground: started.");
if(mBitmap == null){
try{
RotateBitmap rotateBitmap = new RotateBitmap();
mBitmap = rotateBitmap.HandleSamplingAndRotationBitmap(getActivity(), params[0]);
}catch (IOException e){
Log.e(TAG, "doInBackground: IOException: " + e.getMessage());
}
}
byte[] bytes = null;
Log.d(TAG, "doInBackground: megabytes before compression: " + mBitmap.getByteCount() / 1000000 );
bytes = getBytesFromBitmap(mBitmap, 100);
Log.d(TAG, "doInBackground: megabytes before compression: " + bytes.length / 1000000 );
return bytes;
}
@Override
protected void onPostExecute(byte[] bytes) {
super.onPostExecute(bytes);
mUploadBytes = bytes;
hideProgressBar();
//execute the upload task
executeUploadTask();
}
}
private void executeUploadTask(){
Toast.makeText(getActivity(), "uploading image", Toast.LENGTH_SHORT).show();
final String postId = FirebaseDatabase.getInstance().getReference().push().getKey();
final StorageReference storageReference = FirebaseStorage.getInstance().getReference()
.child("posts/users/" + FirebaseAuth.getInstance().getCurrentUser().getUid() +
"/" + postId + "/post_image");
UploadTask uploadTask = storageReference.putBytes(mUploadBytes);
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(getActivity(), "Post Success", Toast.LENGTH_SHORT).show();
//insert the download url into the firebase database
Uri firebaseUri = taskSnapshot.getDownloadUrl();
Log.d(TAG, "onSuccess: firebase download url: " + firebaseUri.toString());
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Post post = new Post();
post.setImage(firebaseUri.toString());
post.setCity(mCity.getText().toString());
post.setContact_email(mContactEmail.getText().toString());
post.setCountry(mCountry.getText().toString());
post.setDescription(mDescription.getText().toString());
post.setPost_id(postId);
post.setPrice(mPrice.getText().toString());
post.setState_province(mStateProvince.getText().toString());
post.setTitle(mTitle.getText().toString());
post.setUser_id(FirebaseAuth.getInstance().getCurrentUser().getUid());
reference.child(getString(R.string.node_posts))
.child(postId)
.setValue(post);
resetFields();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(getActivity(), "could not upload photo", Toast.LENGTH_SHORT).show();
}
}).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
double currentProgress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
if( currentProgress > (mProgress + 15)){
mProgress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
Log.d(TAG, "onProgress: upload is " + mProgress + "& done");
Toast.makeText(getActivity(), mProgress + "%", Toast.LENGTH_SHORT).show();
}
}
});
}
public static byte[] getBytesFromBitmap(Bitmap bitmap, int quality){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality,stream);
return stream.toByteArray();
}
private void resetFields(){
UniversalImageLoader.setImage("", mPostImage);
mTitle.setText("");
mDescription.setText("");
mPrice.setText("");
mCountry.setText("");
mStateProvince.setText("");
mCity.setText("");
mContactEmail.setText("");
}
private void showProgressBar(){
mProgressBar.setVisibility(View.VISIBLE);
}
private void hideProgressBar(){
if(mProgressBar.getVisibility() == View.VISIBLE){
mProgressBar.setVisibility(View.INVISIBLE);
}
}
/**
* Return true if the @param is null
* @param string
* @return
*/
private boolean isEmpty(String string){
return string.equals("");
}
SelectPhotoDialog.java
public class SelectPhotoDialog extends DialogFragment{
private static final String TAG = "SelectPhotoDialog";
private static final int PICKFILE_REQUEST_CODE = 1234;
private static final int CAMERA_REQUEST_CODE = 4321;
public interface OnPhotoSelectedListener{
void getImagePath(Uri imagePath);
void getImageBitmap(Bitmap bitmap);
}
OnPhotoSelectedListener mOnPhotoSelectedListener;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_selectphoto, container, false);
TextView selectPhoto = (TextView) view.findViewById(R.id.dialogChoosePhoto);
selectPhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: accessing phones memory.");
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, PICKFILE_REQUEST_CODE);
}
});
TextView takePhoto = (TextView) view.findViewById(R.id.dialogOpenCamera);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: starting camera.");
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_REQUEST_CODE);
}
});
return view;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
/*
Results when selecting a new image from memory
*/
if(requestCode == PICKFILE_REQUEST_CODE && resultCode == Activity.RESULT_OK){
Uri selectedImageUri = data.getData();
Log.d(TAG, "onActivityResult: image uri: " + selectedImageUri);
//send the uri to PostFragment & dismiss dialog
mOnPhotoSelectedListener.getImagePath(selectedImageUri);
getDialog().dismiss();
}
/*
Results when taking a new photo with camera
*/
else if(requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK){
Log.d(TAG, "onActivityResult: done taking new photo");
Bitmap bitmap;
bitmap = (Bitmap) data.getExtras().get("data");
//send the bitmap to PostFragment and dismiss dialog
mOnPhotoSelectedListener.getImageBitmap(bitmap);
getDialog().dismiss();
}
}
@Override
public void onAttach(Context context) {
try{
mOnPhotoSelectedListener = (OnPhotoSelectedListener) getTargetFragment();
}catch (ClassCastException e){
Log.e(TAG, "onAttach: ClassCastException: " + e.getMessage() );
}
super.onAttach(context);
}
}
UniversalImageLoader.java
public class UniversalImageLoader {
private static final int defaultImage = R.drawable.ic_name;
private Context mContext;
public UniversalImageLoader(Context context) {
mContext = context;
}
public ImageLoaderConfiguration getConfig(){
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.showImageOnLoading(defaultImage)
.showImageForEmptyUri(defaultImage)
.showImageOnFail(defaultImage)
.considerExifParams(true)
.cacheOnDisk(true).cacheInMemory(true)
.cacheOnDisk(true).resetViewBeforeLoading(true)
.imageScaleType(ImageScaleType.EXACTLY)
.displayer(new FadeInBitmapDisplayer(300)).build();
ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(mContext)
.defaultDisplayImageOptions(defaultOptions)
.memoryCache(new WeakMemoryCache())
.diskCacheSize(100 * 1024 * 1024).build();
return configuration;
}
/**
* this method can be sued to set images that are static. It can't be used if the images
* are being changed in the Fragment/Activity - OR if they are being set in a list or
* a grid
* @param imgURL
* @param image
*/
public static void setImage(String imgURL, ImageView image){
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(imgURL, image);
}
}
RotateBitmap.java
public class RotateBitmap {
private static final String TAG = "RotateBitmap";
private Context mContext;
/*
----------------------------- Image Rotation --------------------------------------------------
*/
private static Bitmap rotateImage(Bitmap img, int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
img.recycle();
return rotatedImg;
}
/**
* This method is responsible for solving the rotation issue if exist. Also scale the images to
* 1024x1024 resolution
*
* @param selectedImage The Image URI
* @return Bitmap image results
* @throws IOException
*/
public Bitmap HandleSamplingAndRotationBitmap(Context context, Uri selectedImage)
throws IOException {
mContext = context;
int MAX_HEIGHT = 1024;
int MAX_WIDTH = 1024;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
BitmapFactory.decodeStream(imageStream, null, options);
imageStream.close();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
imageStream = context.getContentResolver().openInputStream(selectedImage);
Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
img = rotateImageIfRequired(img, selectedImage);
return img;
}
private static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee a final image
// with both dimensions larger than or equal to the requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
// This offers some additional logic in case the image has a strange
// aspect ratio. For example, a panorama may have a much larger
// width than height. In these cases the total pixels might still
// end up being too large to fit comfortably in memory, so we should
// be more aggressive with sample down the image (=larger inSampleSize).
final float totalPixels = width * height;
// Anything more than 2x the requested pixels we'll sample down further
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
}
return inSampleSize;
}
/**
* Rotate an image if required.
*
* @param img The image bitmap
* @param selectedImage Image URI
* @return The resulted Bitmap after manipulation
*/
private Bitmap rotateImageIfRequired(Bitmap img, Uri selectedImage) throws IOException {
InputStream input = mContext.getContentResolver().openInputStream(selectedImage);
ExifInterface ei;
try {
ei = new ExifInterface(input);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
return rotateImage(img, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotateImage(img, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotateImage(img, 270);
default:
return img;
}
} catch (NullPointerException e) {
Log.e(TAG, "rotateImageIfRequired: Could not read file." + e.getMessage());
}
return img;
}
}
答案 0 :(得分:1)
您尚未在ImageLoader
中初始化onCreateView
。在onCreateView
之后添加以下行:
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(getActivity()));
Application
或Activity
类(在首次使用ImageLoader
之前)
public class MyActivity extends Activity {
@Override
public void onCreate() {
super.onCreate();
// Create global configuration and initialize ImageLoader with this config
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
...
.build();
ImageLoader.getInstance().init(config);
...
}
}
答案 1 :(得分:1)
有一个更好的方法可以在Application类的onCreate上对其进行初始化。扩展应用程序并在onCreate方法上覆盖它:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Create global configuration and initialize ImageLoader with this config
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
...
.build();
ImageLoader.getInstance().init(config);
...
}
}