从资产文件夹加载图像

69

我正在尝试从asset文件夹加载图像,然后将其设置为ImageView。我知道如果使用R.id.*会更好,但前提是我不知道图像的id。基本上,我正在尝试通过文件名动态加载图像。

例如,我随机从数据库中检索表示牛的元素,现在我的应用程序将显示一个'cow'图像通过ImageView。这也适用于数据库中的所有元素。(假设每个元素都有一个对应的图像)

如何从asset文件夹加载图像?

9个回答

132

看一下这个代码。在这个教程中,您可以了解如何从资产文件夹加载图像。

// 加载图像

try 
{
    // get input stream
    InputStream ims = getAssets().open("avatar.jpg");
    // load image as Drawable
    Drawable d = Drawable.createFromStream(ims, null);
    // set image to ImageView
    mImage.setImageDrawable(d);
    ims .close();
}
catch(IOException ex) 
{
    return;
}

10
使用完流应该关闭它,你不应该忘记这一点。 - string.Empty
我认为最好的方法是使用try-with-resources。这可以确保流始终关闭,而无需编写所有内容。 - chris2112
@NicolasTyler 当执行离开当前作用域并且没有更多对该对象的引用时,InputStream对象会自动销毁。 - gregn3
@NicolasTyler 我无法访问付费链接,但我找到了这个其他的SO讨论:`所以,是的,如果你想写干净的代码,你应该自己关闭它。如果GC最终调用流的finalize()方法(如下所示),它会自动关闭,但你不应该依赖于它。始终关闭你的资源,这是唯一确定的方法。` - gregn3

56

给你:

  public Bitmap getBitmapFromAssets(String fileName) throws IOException {
    AssetManager assetManager = getAssets();

    InputStream istr = assetManager.open(fileName);
    Bitmap bitmap = BitmapFactory.decodeStream(istr);
    istr.close();

    return bitmap;
}

5
不要忘记:istr.close()。 - Andrii Kovalchuk

32

如果您在代码中知道文件名,调用这个函数不会成为问题:

ImageView iw= (ImageView)findViewById(R.id.imageView1);  
int resID = getResources().getIdentifier(drawableName, "drawable",  getPackageName());
iw.setImageResource(resID);

你的文件名将与drawableName相同,因此你不必处理资产。


5
只要图像是可绘制的并且扩展名是有效的图像扩展名,就无需包括扩展名。 - Erol
2
没有太大的差别。我会说使用资源可以由于索引使其变得更快,更实用,并且还可以避免编译时的命名错误问题。此外,大多数API使用资源ID。Drawable除了索引之外,还为您提供了应对屏幕密度碎片化的选项,而Asset不应该依赖于密度。在较小的屏幕和/或低规格手机(RAM、CPU)上放置大图片可能会导致真正的麻烦并影响用户体验和应用程序的响应能力。对我来说,资产更偶尔使用。 - Erol
3
它确实适用于 assets 文件夹吗?对于 res 文件夹,它肯定适用,但这是我见过的唯一一个说它也可以在 assets 上工作的参考文献。但它对我不起作用 - 有人验证过吗? - Amir Uval
2
只有在drawableName中没有扩展名时才能正常工作。 - faizal
13
@uval 对啊,为什么这个被选为答案呢?问题是关于从“assets”文件夹加载的。我猜OP并不真正关心文件实际位于哪里。请参考osayilgan和Chirag Raval的答案,以获取使用“assets”文件夹的示例。 - Alan
显示剩余7条评论

7

有些答案可能会回答这个问题,但我从来不喜欢它们中的任何一个,所以最终我写了这篇文章,希望能对社区有所帮助。

从资产中获取 Bitmap

public Bitmap loadBitmapFromAssets(Context context, String path)
{
    InputStream stream = null;
    try
    {
        stream = context.getAssets().open(path);
        return BitmapFactory.decodeStream(stream);
    }
    catch (Exception ignored) {} finally
    {
        try
        {
            if(stream != null)
            {
                stream.close();
            }
        } catch (Exception ignored) {}
    }
    return null;
}

从资产中获取Drawable:

public Drawable loadDrawableFromAssets(Context context, String path)
{
    InputStream stream = null;
    try
    {
        stream = context.getAssets().open(path);
        return Drawable.createFromStream(stream, null);
    }
    catch (Exception ignored) {} finally
    {
        try
        {
            if(stream != null)
            {
                stream.close();
            }
        } catch (Exception ignored) {}
    }
    return null;
}

5
根据Android开发者文档,使用位图加载可能会降低应用程序性能。这是链接!因此文档建议使用Glide库。
如果要从assets文件夹中加载图像,则使用Glide库可以更轻松地实现。只需在build.gradle(Module:app)中添加依赖项,从https://github.com/bumptech/glide下载即可。
 dependencies {
  implementation 'com.github.bumptech.glide:glide:4.9.0'
  annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
}

示例例子:

// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
  ...
  ImageView imageView = (ImageView) findViewById(R.id.my_image_view);

  Glide.with(this).load("file:///android_asset/img/fruit/cherries.jpg").into(imageView);
}

如果以上方法不起作用:请使用以下代码中的view对象替换this对象(仅当您的代码中应用了以下充气方法时)。
 LayoutInflater mInflater =  LayoutInflater.from(mContext);
        view  = mInflater.inflate(R.layout.book,parent,false);

这里的 Asset 文件夹的 Url 表示为:**file:///android_asset/**,img 是 Asset 文件夹中的文件夹(Assets/img)。 - Prakash Karkee

4
public static Bitmap getImageFromAssetsFile(Context mContext, String fileName) {
        Bitmap image = null;
        AssetManager am = mContext.getResources().getAssets();
        try {
            InputStream is = am.open(fileName);
            image = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
    }

3
这在我的使用情况下有效:
AssetManager assetManager = getAssets();
ImageView imageView = (ImageView) findViewById(R.id.imageView);
try (
        //declaration of inputStream in try-with-resources statement will automatically close inputStream
        // ==> no explicit inputStream.close() in additional block finally {...} necessary
        InputStream inputStream = assetManager.open("products/product001.jpg")
) {
    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
    imageView.setImageBitmap(bitmap);
} catch (IOException ex) {
    //ignored
}

(另请参见https://javarevisited.blogspot.com/2014/10/right-way-to-close-inputstream-file-resource-in-java.html

0

您可以简单地使用此 Kotlin 扩展函数,其中 String 被引用为 fileName

fun String.assetsToBitmap(context: Context): Bitmap? {
    return try {
        val assetManager = context.assets
        val inputStream = assetManager.open(this)
        val bitmap = BitmapFactory.decodeStream(inputStream)
        inputStream.close()
        bitmap
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

使用示例

val myBitmap = "sample.png".assetsToBitmap(context)

-1
WebView web = (WebView) findViewById(R.id.webView);
web.loadUrl("file:///android_asset/pract_recommend_section1_pic2.png");
web.getSettings().setBuiltInZoomControls(true);

8
TS 询问的是 ImageView,而不是 WebView 容器。为图像显示嵌入网络浏览器会产生极大的开销。 - ruX
@ruX 使用 WebView 不会增加额外负担。你不需要嵌入一个浏览器来使用 WebView。此外,如果你想要为你的图片或文本添加缩放/平移功能,WebView 是一个不错的选择。 - Nj Subedi
@njs证据呢?WebView是嵌入式网络浏览器。 - ruX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接