【问题标题】:ImageView in Android Causing App to CrashAndroid中的ImageView导致应用程序崩溃
【发布时间】:2010-07-06 04:56:00
【问题描述】:

我有一个应用程序使用存储在 SD 卡或手机上的照片。

我有 2 个活动似乎存在某种问题(用于查看和编辑记录的活动)。单个记录通过存储提供相关照片位置的 URI 来引用照片。

当我单击我的 View 活动时,我传递了 URI,然后使用 URI 设置 ImageView。在 View Activity 中,我有一个菜单选项,可让您访问 Edit Activity。当您单击编辑时,我再次传递照片的 URI,并使用该 URI 设置 ImageView。这两个活动都可以单独显示。

但是,当我单击“后退”按钮从“编辑”移动到“查看”时,应用程序崩溃了。最初,崩溃是 OutOfMemory 异常。通过在两个活动的 onPause 函数中添加对 ((BitmapDrawable)mImageView.getDrawable()).getBitmap().recycle() 的调用,我克服了这个异常。

回收代码到位后,执行从编辑移回视图,然后在某处崩溃。我已经逐步完成了生命周期函数,并且执行成功,除了 onCreate。执行永远不会再次到达 onCreate。

我知道这与 ImageView 有关,因为当我从 View 活动的布局中删除 ImageView 时,不再发生崩溃。

这是崩溃发生时的初始堆栈跟踪:

Thread [<3> main] (Suspended (exception RuntimeException))  
    ViewRoot.draw(boolean) line: 1356   
    ViewRoot.performTraversals() line: 1097 
    ViewRoot.handleMessage(Message) line: 1613  
    ViewRoot(Handler).dispatchMessage(Message) line: 99 
    Looper.loop() line: 123 
    ActivityThread.main(String[]) line: 4203    
    Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
    Method.invoke(Object, Object...) line: 521  
    ZygoteInit$MethodAndArgsCaller.run() line: 791  
    ZygoteInit.main(String[]) line: 549 
    NativeStart.main(String[]) line: not available [native method]  

在这个堆栈跟踪之后,如果我在 Eclipse 中继续推动“Step Over”,堆栈跟踪最终会像这样:

Thread [<3> main] (Suspended)   
    ThreadGroup.uncaughtException(Thread, Throwable) line: 884  
    NativeStart.main(String[]) line: not available [native method]  

【问题讨论】:

    标签: android


    【解决方案1】:

    我找到了解决这个问题的方法。

    部分归功于 Janusz 的回答,我能够找到其他解决方案。在我的 View 和 Edit 类中,我添加了一个私有 Bitmap 类变量 (mBitmap)。在 onCreate 中,我检索并存储图像位置的 URI。在 onPause 中,我回收位图。在 onResume 中,我更新了这个函数以使用新的类变量 mBitmap(我确信有更好的方法来设置 Bitmap,所以大家随时指出)。此外,使用这个新代码,我最初在 Edit 类中遇到了崩溃。如果你去编辑,然后点击“主页”按钮,应用程序会崩溃。我发现该问题的解决方案是在 Edit.onPause 中将图像视图的位图设置为 null。问题是 imageView 保留了指向位图的指针,即使在我回收位图之后也是如此。见Android "Trying to use recycled bitmap" error?

    protected void onResume()
    {
        mBitmap = null;
        try
        {
            mBitmap = Bitmap.createBitmap(Media.getBitmap(this.getContentResolver(), mPicUri));
        }
        catch(Exception e)
        {}
    
        mImageView.setImageBitmap(mBitmap);
        mImageView.setAdjustViewBounds(true);
        mImageView.setMaxHeight(100);      //purposely showing image as 100x100 picture
        mImageView.setMaxWidth(100);
        mImageView.invalidate();
    
        super.onResume();
    }
    
    protected void onCreate()
    {
        mPicUri = //the picuture location URI
    }
    
    protected void onPause()
    {
        mBitmap.recycle();
        mImageView.setImageBitmap(null);  //in my Edit class
    }
    

    【讨论】:

      【解决方案2】:

      如果您从 Activity First 更改为 Second,Activity First 将暂停。然后 onPause 方法将回收位图。
      如果从 Activity Second 切换 Back 到 First Activity First 已经存在,不需要再次调用 onCreateMethod。相反,只有 onResume 方法被调用,告诉活动它再次出现在屏幕上。此时,imageview 尝试将图像绘制到屏幕上,但由于图像被回收,您的应用程序崩溃。

      如果你真的需要回收位图,你必须在调用你的活动的超级 onResume 方法之前在 onResume 方法中重置它。

      【讨论】:

      • 您好 Janusz,感谢您的回复。不幸的是,这对我不起作用。从编辑移回查看时,我仍然收到相同的崩溃。我进行了以下更改: 在 onCreate 中,我删除了 ImageView 的设置,而我只是检索和存储图片位置的 URI。在 onResume 中,我添加了代码以根据保存在 onCreate 中的 URI 设置图像 URI。然后在onPause中,我调用recycle。
      • 之所以这样设置,是因为我在调试器中观察到的执行流程,如下:启动应用程序后,我从主页面移动到视图,它调用这些函数:onCreate(),然后是 onResume()。当我从 View 移动到 Edit 时,流程是: View 的 onPause 被调用(循环调用)。使用后退按钮从 Edit 移回 View,调用 View 的 onResume(调用 setImageURI)。这执行得很好,但后来应用程序崩溃了。有没有比回收更好的清除 ImageView 的方法?
      • 另一个观察结果。我通过调用 ((BitmapDrawable)mImageView.getDrawable()).getBitmap() 抓取了被引用的位图,并检查了地址。我注意到在调用回收之前和之后地址是相同的。我原以为地址被回收后会有所不同。从Edit返回View时,地址完全相同。
      【解决方案3】:

      从流中显示位图图像并将其显示在 ImageView 中而不会导致任何崩溃的最佳方法是:

      public void getImage(final  ImageView imageView , final String picUrl) {
      
          class GetImage extends AsyncTask<String,Void,Bitmap> {
            @Override
              protected void onPreExecute() {
                  super.onPreExecute();
              Log.i("Download","Profile Picture Downloaded");
              }
      
              @Override
              protected void onPostExecute(Bitmap b) {
                  super.onPostExecute(b);
                  imageView.setImageBitmap(b);
              }
      
              @Override
              protected Bitmap doInBackground(String... params) {
                  URL url = null;
                  Bitmap image = null;
                  Bitmap finalImage=null;
                  try {
                      url = new URL(picUrl);
                      image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
                      finalImage= resize(image,120,120);
                  } catch (MalformedURLException e) {
                      e.printStackTrace();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
                  return finalImage;
              }
          }
      
          GetImage gi = new GetImage();
          gi.execute();
      }
      

      方法有2个参数,ImageView包含我们的Image和Image URL,你只需要调用带有参数的方法,图片就会显示出来。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-08
        • 2013-12-02
        • 2014-09-09
        • 1970-01-01
        • 1970-01-01
        • 2022-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多