Андроид: ошибка при вращения, горизонтального на вертикальной плоскости


Я играю с android, и я создаю простое приложение twitter, чтобы проверить то, что я узнал до сих пор. Но я столкнулся с проблемой, которую не понимаю. Я создал поток для получения твитов, никаких проблем там не было, но затем добавил ProgressDialog, чтобы показать, когда этот поток был запущен. Это вызвало очень необычное поведение. Если пользователь поворачивается из вертикальной ориентации, в горизонтальную ориентацию, программа ведет себя так, как ожидалось, никаких проблем, но если он затем поворачивается обратно, программа крушения говорят, что окно протекло.

Проблема возникает только при переключении горизонтальной компоновки на вертикальную. Я знаю о проблемах, связанных с попыткой поворота во время работы диалогового окна, но я убедился, что диалоговое окно завершило работу и закрылось перед вращением, и оно все равно аварийно завершится. Вот мой код:

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


  }
}

Вот LogCat, откуда он вылетает:

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
1 7

1 ответ:

Исключение WindowLeaked в журнале обычно происходит, когда у вас есть какая-то асинхронная задача, которая завершается после того, как начавшееся действие было уничтожено.

Когда вы поворачиваете экран, действие воссоздается. В соответствии с Android docs, Вы должны сохранить любое состояние экземпляра в методе onPause, в том числе убедиться, что любые асинхронные задачи остановлены. Вы можете воссоздать в методе onCreate, используя сохраненный пакет.