Android: Crash on rotation, horizontal to vertical

11,135

The WindowLeaked exception in the log usually happens when you have some sort of async task that is finishing after the activity that began it is destroyed.

When you rotate the screen, the activity is recreated. Per the Android docs, you should save any instance state in the onPause method, including making sure that any async tasks are stopped. You can recreate in the onCreate method, using the saved bundle.

Share:
11,135
Kelend
Author by

Kelend

Ruby on Rails developer in the RTP area of North Carolina.

Updated on June 05, 2022

Comments

  • Kelend
    Kelend about 2 years

    I'm playing around with android, and I'm creating a simple twitter app to test what I've learned so far. But I've run into a problem that I don't understand. I created a thread to fetch the tweets, no problems there, but then added a ProgressDialog to show when that thread was running. Doing so caused a very unusual behavior. If the user rotates from Vertical orientation, to horizontal orientation, program behaves as expected, no problems, but if he then rotates back, the program crashes saying a window leaked.

    The problem only happens on a horizontal to vertical layout switch. I know of the issues of if you try to rotate while the dialog box is running, but I've made sure that the dialog box has finished running and dismissed before rotating and it will still crash. Heres my code:

    package com.onesmartpuppy.puppytweet;
    import java.util.ArrayList;
    import com.github.droidfu.widgets.WebImageView;
    import winterwell.jtwitter.Twitter;
    import winterwell.jtwitter.Twitter.Status;
    import android.app.ListActivity;
    import android.app.ProgressDialog;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.View.OnClickListener;
    import android.widget.ArrayAdapter;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class PuppyTweet extends ListActivity implements OnClickListener {
    
        private ProgressDialog m_ProgressDialog = null;
        private ArrayList<Status> messages = null;
        private TweetAdapter m_adapter;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            messages = new ArrayList<Status>();
            this.m_adapter = new TweetAdapter(this, R.layout.row, messages);
            setListAdapter(this.m_adapter);
    
            setupButtons();
    
            m_ProgressDialog = ProgressDialog.show(this,    
                 "Please wait...", "Retrieving tweets ...", true);
    
            Runnable findTweets = new Runnable(){
                @Override
                public void run() {
    
                 try {
                    messages = new ArrayList<Status>();
    
                    Twitter ourTwitter = new Twitter("*****", "******");
                    messages = (ArrayList<Status>) ourTwitter.getFriendsTimeline();
    
                    Thread.sleep(1000);
                    Log.i("ARRAY", ""+ messages.size());
                 } catch (Exception e) {
                    Log.e("BACKGROUND_PROC", e.getMessage());
                 }
                  handler.sendEmptyMessage(0);   
                 }
             };
    
            Thread thread =  new Thread(null, findTweets, "FindTweets");
            thread.start();
        }
    
    
    
        private void setupButtons()
        {
         Button refreshButton = (Button) findViewById(R.id.refresh_button);
         refreshButton.setOnClickListener(this);
         Button settingsButton = (Button) findViewById(R.id.settings_button);
         settingsButton.setOnClickListener(this);
         Button tweetButton = (Button) findViewById(R.id.update_button);
         tweetButton.setOnClickListener(this);
        }
    
    
    
     @Override
     public void onClick(View v) {
      switch (v.getId())
      {
      case R.id.settings_button:
       break;
      case R.id.update_button:
       break;
      case R.id.refresh_button:
       break;
      default:
       break;
      }
     }
    
     private Handler handler = new Handler() {
    
             @Override
             public void handleMessage(Message msg) {
                 if(messages != null && messages.size() > 0){
                  m_adapter.clear();
                     m_adapter.notifyDataSetChanged();
                     for(int i=0;i<messages.size();i++)
                      m_adapter.add(messages.get(i));
                 }
                 m_ProgressDialog.dismiss();
                 m_adapter.notifyDataSetChanged();
             }
      };
    
    
      private class TweetAdapter extends ArrayAdapter<Status> {
    
          private ArrayList<Status> items;
    
          public TweetAdapter(Context context, int textViewResourceId, ArrayList<Status> items) {
                  super(context, textViewResourceId, items);
                  this.items = items;
          }
    
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
                  View v = convertView;
                  if (v == null) {
                      LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                      v = vi.inflate(R.layout.row2, null);
                  }
                  Status o = (Status) items.get(position);
    
                  if (o != null) {
                    WebImageView img = (WebImageView) v.findViewById(R.id.webimage);                   
                          TextView tt = (TextView) v.findViewById(R.id.toptext);
                          TextView bt = (TextView) v.findViewById(R.id.bottomtext);
                          if (tt != null) {
                                tt.setText("Name: " + o.user.name);                            }
                          if(bt != null){
                                bt.setText("Status: " + o.getText());
                          }
                          if (img !=null) {
                           img.setImageUrl(o.getUser().profileImageUrl.toString());
                              img.loadImage();
                          }
                  }
                  return v;
          }
    
    
      }
    }
    

    heres the LogCat from where it crashes:

    02-10 16:01:05.237: INFO/ActivityManager(63): Config changed: { scale=1.0 imsi=310/260 loc=ld_US touch=3 keys=2/1/2 nav=3/1 orien=2 layout=18}
    02-10 16:01:05.344: WARN/UsageStats(63): Something wrong here, didn't expect com.onesmartpuppy.puppytweet to be resumed
    02-10 16:01:05.384: INFO/WindowManager(63): Setting rotation to 0, animFlags=0
    02-10 16:01:05.394: INFO/ActivityManager(63): Config changed: { scale=1.0 imsi=310/260 loc=ld_US touch=3 keys=2/1/2 nav=3/1 orien=1 layout=18}
    02-10 16:01:05.504: WARN/UsageStats(63): Something wrong here, didn't expect com.onesmartpuppy.puppytweet to be resumed
    02-10 16:01:05.704: ERROR/WindowManager(227): Activity com.onesmartpuppy.puppytweet.PuppyTweet has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43af9490 that was originally added here
    02-10 16:01:05.704: ERROR/WindowManager(227): android.view.WindowLeaked: Activity com.onesmartpuppy.puppytweet.PuppyTweet has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@43af9490 that was originally added here
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.view.ViewRoot.<init>(ViewRoot.java:227)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.Dialog.show(Dialog.java:239)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ProgressDialog.show(ProgressDialog.java:107)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ProgressDialog.show(ProgressDialog.java:90)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at com.onesmartpuppy.puppytweet.PuppyTweet.onCreate(PuppyTweet.java:39)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2417)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2470)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3573)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ActivityThread.access$2300(ActivityThread.java:119)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1825)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.os.Handler.dispatchMessage(Handler.java:99)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.os.Looper.loop(Looper.java:123)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at android.app.ActivityThread.main(ActivityThread.java:4310)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at java.lang.reflect.Method.invokeNative(Native Method)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at java.lang.reflect.Method.invoke(Method.java:521)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    02-10 16:01:05.704: ERROR/WindowManager(227):     at dalvik.system.NativeStart.main(Native Method)
    02-10 16:01:06.344: INFO/global(227): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
    02-10 16:01:06.624: DEBUG/dalvikvm(227): GC freed 6082 objects / 479568 bytes in 77ms
    02-10 16:01:07.374: DEBUG/dalvikvm(227): GC freed 11982 objects / 709808 bytes in 83ms
    02-10 16:01:07.394: INFO/global(227): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
    02-10 16:01:07.564: DEBUG/dalvikvm(227): GC freed 95 objects / 79880 bytes in 68ms
    02-10 16:01:07.704: DEBUG/dalvikvm(227): GC freed 8 objects / 38992 bytes in 65ms
    02-10 16:01:08.174: DEBUG/dalvikvm(63): GC freed 5407 objects / 257208 bytes in 174ms
    02-10 16:01:08.194: INFO/ARRAY(227): 20
    02-10 16:01:08.204: DEBUG/AndroidRuntime(227): Shutting down VM
    02-10 16:01:08.204: WARN/dalvikvm(227): threadid=3: thread exiting with uncaught exception (group=0x4001b188)
    02-10 16:01:08.204: ERROR/AndroidRuntime(227): Uncaught handler: thread main exiting due to uncaught exception
    02-10 16:01:08.214: ERROR/AndroidRuntime(227): java.lang.IllegalArgumentException: View not attached to window manager
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:200)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.view.Window$LocalWindowManager.removeView(Window.java:432)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.app.Dialog.dismissDialog(Dialog.java:280)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.app.Dialog.access$000(Dialog.java:73)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.app.Dialog$1.run(Dialog.java:109)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.app.Dialog.dismiss(Dialog.java:264)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at com.onesmartpuppy.puppytweet.PuppyTweet$1.handleMessage(PuppyTweet.java:104)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.os.Handler.dispatchMessage(Handler.java:99)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.os.Looper.loop(Looper.java:123)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at android.app.ActivityThread.main(ActivityThread.java:4310)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at java.lang.reflect.Method.invokeNative(Native Method)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at java.lang.reflect.Method.invoke(Method.java:521)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    02-10 16:01:08.214: ERROR/AndroidRuntime(227):     at dalvik.system.NativeStart.main(Native Method)
    02-10 16:01:08.244: INFO/Process(63): Sending signal. PID: 227 SIG: 3
    02-10 16:01:08.244: INFO/dalvikvm(227): threadid=7: reacting to signal 3
    02-10 16:01:08.274: ERROR/dalvikvm(227): Unable to open stack trace file '/data/anr/traces.txt': Permission denied
    02-10 16:01:08.754: DEBUG/dalvikvm(227): GC freed 5986 objects / 372656 bytes in 316ms
    02-10 16:01:09.829: INFO/ARRAY(227): 20
    02-10 16:01:09.955: INFO/Process(227): Sending signal. PID: 227 SIG: 9
    02-10 16:01:09.974: INFO/ActivityManager(63): Process com.onesmartpuppy.puppytweet (pid 227) has died.
    02-10 16:01:10.014: INFO/WindowManager(63): WIN DEATH: Window{43b653e0 com.onesmartpuppy.puppytweet/com.onesmartpuppy.puppytweet.PuppyTweet paused=false}
    02-10 16:01:10.014: INFO/WindowManager(63): WIN DEATH: Window{43c32b48 Please wait... paused=false}
    02-10 16:01:10.164: WARN/UsageStats(63): Unexpected resume of com.android.launcher while already resumed in com.onesmartpuppy.puppytweet
    02-10 16:01:10.314: WARN/InputManagerService(63): Got RemoteException sending setActive(false) notification to pid 227 uid 10023