尝试decodeStream时出错类错误

时间:2014-01-28 16:01:52

标签: android decode inflate-exception

我很精疲力竭。我整天都在努力。在我的应用程序中我有100个ImageViews,但我得到一个java.outofmemory错误所以我决定解码和调整文件大小,但我无法管理它工作。 有人可以查看代码并建议我吗?

MainActivity代码:     公共类MainActivity扩展Activity实现OnClickListener {

ImageView display;
int toPhone;
private Context context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    System.gc();
    context = this;
    toPhone = R.drawable.wal1;
    display = (ImageView) findViewById(R.id.WPdisplay);
    ImageView image1 = (ImageView) findViewById(R.id.WPimg1);
    ImageView image2 = (ImageView) findViewById(R.id.WPimg2);
    ImageView image3 = (ImageView) findViewById(R.id.WPimg3);
    ImageView image4 = (ImageView) findViewById(R.id.WPimg4);
    ImageView image5 = (ImageView) findViewById(R.id.WPimg5);
    Button setWall = (Button) findViewById(R.id.BsetWall);
    image1.setOnClickListener(this);
    image2.setOnClickListener(this);
    image3.setOnClickListener(this);
    image4.setOnClickListener(this);
    image5.setOnClickListener(this);
    setWall.setOnClickListener(this);
    }

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

public Bitmap decodeAndResizeFile(int resID) {
     try {
            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;

我认为在下一行我有一个问题,因为它说没有使用局部变量bmp的值

            Bitmap bmp= BitmapFactory.decodeResource(context.getResources(), resID, o);
           // BitmapFactory.decodeStream(new FileInputStream(f), null, o);

            // The new size we want to scale to
            final int REQUIRED_SIZE = 70;

            // Find the correct scale value. It should be the power of 2.
            int width_tmp = o.outWidth, height_tmp = o.outHeight;
            int scale = 1;
            while (true) {
                if (width_tmp / 2 < REQUIRED_SIZE
                        || height_tmp / 2 < REQUIRED_SIZE)
                    break;
                width_tmp /= 2;
                height_tmp /= 2;
                scale *= 2;
            }
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize = scale;
            return BitmapFactory.decodeResource(context.getResources(), resID, o2);

     } finally {

        }
    }

@Override
public void onClick(View v) {
    Bitmap bmpp;
    switch (v.getId()){
    case R.id.WPimg1:
         display.setImageResource(R.drawable.wal1);
         toPhone = R.drawable.wal1;

在下一行我试图解码它(我正在为每个图像做这个)

         bmpp = decodeAndResizeFile(toPhone);
         //Bitmap bmpp = decodeAndResizeFile(file);
         break;
    case R.id.WPimg2:
         display.setImageResource(R.drawable.wal2);
         toPhone = R.drawable.wal2;  
         bmpp = decodeAndResizeFile(toPhone);
        display.setImageBitmap(bmpp);
         break;
    case R.id.WPimg3:
         display.setImageResource(R.drawable.wal3);
         toPhone = R.drawable.wal3;
         bmpp = decodeAndResizeFile(toPhone);
         break;
    case R.id.WPimg4:
         display.setImageResource(R.drawable.wal4);
         toPhone = R.drawable.wal4;
         bmpp = decodeAndResizeFile(toPhone);
         break;
    case R.id.WPimg5:
         display.setImageResource(R.drawable.wal5);
         toPhone = R.drawable.wal5;
         bmpp = decodeAndResizeFile(toPhone);
         break;
    case R.id.BsetWall:
         try{
             WallpaperManager.getInstance(getApplicationContext()).setResource(toPhone);
             Toast.makeText(getApplicationContext(), "Wallpaper was set!", Toast.LENGTH_SHORT).show();
         } catch(IOException e) {
             e.printStackTrace();
             Toast.makeText(getApplicationContext(), "No privileges!", Toast.LENGTH_SHORT).show();
         }
         break;
    }
    }
    }

这是我的Logcat

--- decoder->decode returned false
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0xb3adbba8)
FATAL EXCEPTION: main
Process: app.technozed.testwall, PID: 1250
java.lang.RuntimeException: Unable to start activity ComponentInfo{app.technozed.testwall/app.technozed.testwall.MainActivity}: android.view.InflateException: Binary XML file line #304: Error inflating class <unknown>
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #304: Error inflating class <unknown>
at android.view.LayoutInflater.createView(LayoutInflater.java:620)
at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
at android.view.LayoutInflater.onCreateView(LayoutInflater.java:669)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:694)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:758)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:758)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1929)
at app.technozed.testwall.MainActivity.onCreate(MainActivity.java:28)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
... 11 more
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at android.view.LayoutInflater.createView(LayoutInflater.java:594)
... 26 more
Caused by: java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:587)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:422)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:840)
at android.content.res.Resources.loadDrawable(Resources.java:2110)
at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
at android.widget.ImageView.<init>(ImageView.java:129)
at android.widget.ImageView.<init>(ImageView.java:119)
... 29 more

1 个答案:

答案 0 :(得分:1)

如果您在decodeAndResizeFile()中收到警告'未使用局部变量bmp的值',则可以删除'Bitmap bmp ='部分并将其保留为:

BitmapFactory.decodeResource(context.getResources(), resID, o);

这是因为此调用是使用o.inJustDecodeBounds = true。在这种情况下,只在对象'o'中返回维度并返回一个空位图(因此没有点存储它)。

在您的switch语句中,将每个案例更改为如下所示:

case R.id.WPimg1:
    toPhone = R.drawable.wal1;
    bmpp = decodeAndResizeFile(toPhone);
    display.setImageBitmap(bmpp);
    break;

所以在这里,您将资源解码为缩小的位图,然后将该位图分配给ImageView。您不希望或不需要这样做:

display.setImageResource(R.drawable.wal1);

...因为你冒着OutOfMemoryException的风险,所以你继续用缩放的位图设置'display'。完成这些更改后,您的代码就适合我。我可以看到壁纸预览图像,然后设置壁纸(不要忘记清单中的SET_WALLPAPER权限)。

然而,这并没有解释你的logcat,它似乎是onCreate()膨胀R.layout.activity_main的一个问题。在logcat的末尾,它再次显示OutOfMemoryError。如果我将一个大的jpg分配给XML中的ImageView(OOM结果,因此布局不能膨胀),我可以重新创建此错误。当用XML分配drawable时,你无法“动态”缩小它们,因此创建物理上较小的drawable以便在XML中使用。

编辑:

当您点击图片时,'display'会获得一个新的位图,而旧的位图符合GC的条件。这是一种方法,可以立即释放旧存储器使用的内存,而无需等待GC启动:

将此项从onClick()移动为类变量:

Bitmap bmpp;  //Reference to the same bitmap that 'display' is using

然后在onClick():

Bitmap old_bm = null;  //Reference to hold the old bitmap
switch (v.getId()){
case R.id.WPimg1:
    old_bm = bmpp;  //Set to the bitmap currently being used by 'display'
    toPhone = R.drawable.wal1;
    bmpp = decodeAndResizeFile(toPhone);   //'display' now has a new bitmap
    display.setImageBitmap(bmpp);
    if (old_bm != null)
    {
        old_bm.recycle();  //Recyle the old bitmap
        old_bm = null;     //Clear the reference to allow GC to clean up fully
    }
    break;