从服务器下载drawables以减少APK文件大小

时间:2013-09-17 14:39:23

标签: android apk android-drawable xml-drawable

为了减少APK文件的大小,我想从我的项目中删除drawables(图像和XML文件),并在第一个应用程序启动时从我的服务器下载正确的文件。

问题是如何在我的代码中加载和使用下载的drawable?

这是我在一些研究后发现的:

但我仍然不知道如何加载和使用引用其他drawable的XML drawable,如下所示:

<layer-list>
  <item>
    <bitmap android:src="@drawable/other_drawable" />
  </item>
</layer-list>

对于减少APK文件大小的这个或其他有效想法的任何想法将不胜感激。

注意:

  • drawables构成APK文件大小的大部分(20mb / 25mb)。
  • 我已经压缩了图片文件而我正在使用ProGuard。

更新

经过一些更多的研究,我似乎可以通过使用引用的drawables的自定义属性和Drawable的子类而不是本地BitmapDrawable来修改它们之后加载/使用下载的XML drawables。所以上面的XML drawable示例将变成这样:

<layer-list xmlns:custom="http://schemas.android.com/apk/res-auto">
  <item>
    <custom-bitmap custom:ref="other_drawable" />
  </item>
</layer-list>

虽然,这不是一个非常简单的解决方案,但我不确定它比手动操作更好。

参考文献:

5 个答案:

答案 0 :(得分:2)

XML文件和drawable只是为了帮助开发人员,这些不是android中编程的重要部分。如果要从服务器下载,可以执行此操作。 您需要做的是在Java文件中手动创建布局和其他事项。 我是

RelativeLayout rl =new Relativelayout(Context);// To create Layout
Button button = new Button(Context); // Create Components Like this
button.setText("abc");// Set Properties

现在将组件作为子项添加到布局中。

rl.addView(button,new          Layoutparams(Layoutparams.WRAP_CONTENT,Layoutparams.WRAP_CONTENT));

在onCreate中返回此布局!

对于drawable,在drawable中包含非常重要的内容,并通过HTTP Calls下载其他内容。

希望它有所帮助。

答案 1 :(得分:2)

首先,如果您的应用程序具有强烈的ui交互,那么该大小也不会太糟糕。此外,在某些时刻用户将需要下载那个drawables,为什么不从谷歌Playstore安装?无论如何,如果你真的想这样做,你可以做到以下几点:

对于布局中的引用,您需要从每个具有对drawable引用的窗口小部件进行连接并实现自己的标记。例如,如果您的旧布局如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<ImageView
    android:id="@+id/someImageView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:src="@drawable/somePicture" />

</RelativeLayout>

现在应该是这样的:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.custom"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<com.example.custom.RemoteImageView
    android:id="@+id/someImageView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    custom:remoteSrc="somePicture" />

</RelativeLayout>

请记住在attrs.xml中添加自定义标记定义。在类的实现中,您可以从某个缓存中获取图像(如果存在),如下所示:

public class RemoteImageView extends ImageView {

private String remoteSrc;
private DiskLruImageCache diskCache;

public RemoteImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public RemoteImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    diskCache = new DiskLruImageCache(this, "cache", 1024 * 1024 * 30, CompressFormat.PNG, 70);
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.RemoteImageView, 0, 0);

    try {
        remoteSrc = a.getString(R.styleable.RemoteImageView_remoteSrc);
        Bitmap cachedImage;
        if (!diskCache.containsKey(remoteSrc)) {
            //Download it from Internet and save it into the cache
            //...
            diskCache.put(remoteSrc, bitmapThatYouDownload);
        }
        cachedImage = diskCache.getBitmap(remoteSrc);
        //Use the cachedImage as the bitmap for this view.
    } finally {
        a.recycle();
    }
}

public RemoteImageView(Context context) {
    super(context);
}

}

要查看DiskLruImageCache,您可以查看以下链接:

DiskLruCache

你可以做一些技巧,比如有一个两级缓存,第一个有内存缓存,第二个有磁盘缓存。已经存在的库可以执行这样的操作,但是您需要自定义标记,您可以修改这些库或在类中使用缓存库,如上所示。


对于AnimationDrawable之类的动画列表,您需要在运行时构建动画。例如:

AnimationDrawable animation = new AnimationDrawable();
animation.addFrame(new BitmapDrawable(getResources(),diskCache.get(myFirstFreame)), 100);
animation.addFrame(new BitmapDrawable(getResources(),diskCache.get(mySecondFrame)), 1000);
animation.addFrame(new BitmapDrawable(getResources(),diskCache.get(myThirdFrame)), 1000);
animation.setOneShot(false);

ImageView imageAnim =  (ImageView) findViewById(R.id.img);
imageAnim.setBackgroundDrawable(animation);

请务必检查myFirstFramemySecondFramemyThirdFrame是否已在缓存中。如果没有,则下载并添加它们。

希望这有帮助,但如果我是你,我会保持这个大小,个人不是那么多,我已经开发了一个有很多动画和ui功能的tumblr客户端,而apk大小约为15 MiB

答案 2 :(得分:1)

我怀疑你的drawable是否这么多(20MB)在这里我的意思是drawable是仅xml文件。 因为这些以后无法下载您是否正确优化了可重用性代码

但你可以免费使用图像/原始音频文件或类似的东西

我的建议

注意:如果您正在寻找downloadable xml drawables,那么回答是否是不可能它必须带有apk,您也可以按照以下方式进行操作优化

  • 您应该在安装时下载所有音频/图像和其他文件,因为这是减少apk尺寸的唯一解决方案
  • 你不能对你必须拥有的xml Drawables做任何事情,所以你应该尽可能地优化代码。
  • 对于xml Drawable,您可以查找可重用性

正如您的问题所述,如何使用Downloaded drawable代码

所以答案是你不能使用xml drawable但是你可以用图像做这些事情 并且有明确的方法可以从文件设置drawable或从文件

创建Bitmap

答案 3 :(得分:0)

根据您的要求,您无法在运行时更改xml drawable。

其他如果您仍然需要此功能,可以在应用程序的启动画面下载它,并按照建议使用BitmapDrawable将其设置为运行时。

但是根据我的观点,这不是正确使用它的方式,因为当您创建活动时,您的视图已经在setContentView(layoutID)上呈现。因此,当您调用活动时,它将显示没有图像的空白视图。

从其他资源我已经读过,你不能在运行时更改像drawable,raw,strings这样的资源文件,因为它的id不能在运行时创建。

答案 4 :(得分:0)

您可以使用扩展文件(请参阅http://developer.android.com/google/play/expansion-files.html)并使用jobb工具(http://developer.android.com/tools/help/jobb.html)将资源移到那里。

只要尚未下载扩展文件,您仍然需要处理不可用的资源。