0

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

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

这是我经过一番研究后发现的:

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

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

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

笔记:

  • drawables 占 APK 文件大小的大部分 (20mb/25mb)。
  • 我已经压缩了图像文件,并且正在使用 ProGuard。

更新:

Drawable经过更多研究,在我看来,通过使用引用的可绘制对象的自定义属性和一个子类而不是 native 来稍微修改它们后,加载/使用下载的 XML 可绘制对象是可能的BitmapDrawable。所以上面的 XML drawable 例子会变成这样:

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

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

参考:

4

5 回答 5

2

XML 文件和drawables 只是为了帮助开发者,这些不是android 编程的基本部分。如果你想从服务器下载,你可以这样做。您需要做的是在 Java 文件中手动创建布局和其他内容。IE

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 中返回这个 Layout!

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

希望能帮助到你。

于 2013-09-17T15:22:13.727 回答
2

首先,如果您的应用程序具有密集的 ui 交互,那么该大小还不错。此外,在某些时候用户需要下载该drawables,为什么不从google playstore 安装呢?无论如何,如果您真的想这样做,您可以执行以下操作:

对于您的布局中的引用,您需要从每个具有对可绘制对象的引用的小部件中连接并实现您自己的标签。例如,如果您的旧布局如下所示:

<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);

请记住检查myFirstFrame,mySecondFramemyThirdFrame是否已经在缓存中。如果没有,则下载并添加它们。

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

于 2013-09-22T20:27:17.330 回答
1

我怀疑你的drawable是否会这么多(20MB)我的意思是drawable只是xml文件。因为这些以后不能下载你有没有适当地优化你的代码以实现可重用性

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

我的建议

注意:如果您正在寻找,downloadable xml drawables那么答案是否定的,它不可能必须与 apk 一起使用,您也可以按照以下方式进行优化

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

正如您的问题所说,如何对您的代码使用已下载的可绘制对象

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

于 2013-09-21T16:44:05.910 回答
0

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

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

于 2013-09-25T08:03:13.490 回答
0

根据您的要求,您不能在运行时更改 xml 可绘制对象。

另外,如果您仍然需要此功能,您可以在应用程序的启动屏幕上下载它并按照您使用 BitmapDrawable 的建议设置它运行时。

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

从其他资源中我读到你不能在运行时更改资源文件,如可绘制、原始、字符串,因为它的 id 无法在运行时创建。

于 2013-09-19T06:15:19.223 回答