What size to store image on server to use with Android app

爱⌒轻易说出口 提交于 2021-02-07 14:20:56

问题


I have an Android app that allows the user to upload profile pics. They are stored 300px X 300px on the server.

In the app, I use them in either 40dp X 40dp or sometimes 100dp X 100dp. The 40dp's images are in ListView's. I actually use a very popular third party LazyList to store the images (using an ImageLoader class) in a cache. Here is the exact library.

I simply show image in my adapter like this:

imageLoader.DisplayImage(profileUrl, holder.iv1);

I take the web URL and display it directly into the ImageView 40dp x 40dp.

Sometimes I notice image degradation. Where the image is partially loaded, then is corrupted.

One theory is that going from a large image on the server and trying to store it in a small area in the actual app, then doing this many times in a ListView, is causing some loading issues.

The question: What is the best way to handle this situation when you have a much larger image in the server than you need to display? I am assuming I may need to use BitMapFactory or a similar class to build a new image. But I am not sure. I feel like I am missing a step.

Here is an example of an image in a ListView that has become corrupted, notice this does not happen to all. (And yes that is Tobias from Arrested Development.)

Follow-up: And how do we take in consideration file size for xxhdpi, xhdpi, etc when the image is coming from server and not the resources folder?

enter image description here


回答1:


The library you are using looks like it is barely maintained anymore (last update is at least a year old). There are several newer and likely better libraries that solve the same problem. My favorite is Square's Picasso. It is very simple to use and solves the image loading inside a ListView problem very well.

To more directly answer some of your questions:

What is the best way to handle this situation when you have a much larger image in the server than you need to display?

You need to subsample the Bitmap down to the target size. Google has a pretty good write up on all of this here.

First you have to decode the bitmap setting the inJustDecodeBounds boolean to get the bitmap size.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

Then you can compute your sample size based on your target height and width.

public 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) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

Then you can use the computed sample size to load the down sampled Bitmap. The final code would look something like

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

And how do we take in consideration file size for xxhdpi, xhdpi, etc when the image is coming from server and not the resources folder?

You can compute the target pixel size you want to downsize your bitmap to using the following snippet:

float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, "10", context.getResources().getDisplayMetrics());

TL;DR

Use Square's Picasso and it will solve all of your problems.




回答2:


I'd suggest adding an argument to the URL you use to request the image (e.g. &size=small) and having your server keep multiple sizes of each image around. Some benefits to this are:

  1. Less data usage from the app
  2. Better image quality (not having to resample the iamge)
  3. Better performance (large bitmaps take much longer to load)

The downsides are:

  1. More complexity (logic for determining which size to request)
  2. More storage requirements on your server

I think the pros far outweigh the cons, and you'll end up with a much better user experience.

For your followup, you could conceivably even have arguments for each density (e.g. &density=mdpi) which would serve the appropriate size (and you could just switch on getResources().getDisplayMetrics().densityDpi to get the argument value).

For example:

int densityDpi = getResources().getDisplayMetrics().densityDpi;
if (densityDpi <= DisplayMetrics.DENSITY_MEDIUM) {
    return "mdpi";
} else if (densityDpi <= DisplayMetrics.DENSITY_HIGH) {
    return "hdpi";
} else if (densityDpi <= DisplayMetrics.DENSITY_XHIGH) {
    return "xhdpi";
} else if (densityDpi <= DisplayMetrics.DENSITY_XXHIGH) {
    return "xxhdpi";
} else {
    return "xxxhdpi";
}


来源:https://stackoverflow.com/questions/23504708/what-size-to-store-image-on-server-to-use-with-android-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!