2012-05-09 3 views
1

Я работаю над Android-приложением, и я хочу обновлять фон каждые 30 секунд.Ошибка приложения во время второго таймера

Я использовал таймер, и он работает, но только один раз! Во второй раз приложение падает.

public Timer mTimer = null;  

public void loadColor() 
    { 
     setContentView(R.layout.color); 

     cur_scr = (LinearLayout) findViewById(R.id.colorScreen); 
    } 

    public void onClick(View v) throws InterruptedException 
    { 
     int id = v.getId(); 

     switch (id) 
     { 
       case R.id.nextColor: 
        loadColor(); 

        mTimer = new Timer(); 

        mTimer.scheduleAtFixedRate(new TimerTask() 
        { 
         public void run() 
         { 
         Random gen = new Random(); 
         cur_scr.setBackgroundColor(Color.argb(255, gen.nextInt(256), gen.nextInt(256), gen.nextInt(256))); 
         } 
        }, 0, 2000); 

        break; 
     } 
    } 

LogCat:

05-10 15:46:12.325: W/dalvikvm(346): threadid=9: thread exiting with uncaught exception (group=0x40015560) 
05-10 15:46:12.344: E/AndroidRuntime(346): FATAL EXCEPTION: Timer-0 
05-10 15:46:12.344: E/AndroidRuntime(346): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.ViewRoot.checkThread(ViewRoot.java:2932) 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.ViewRoot.invalidateChild(ViewRoot.java:642) 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:668) 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511) 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.View.invalidate(View.java:5279) 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.View.setBackgroundDrawable(View.java:7626) 
05-10 15:46:12.344: E/AndroidRuntime(346): at android.view.View.setBackgroundColor(View.java:7516) 
05-10 15:46:12.344: E/AndroidRuntime(346): at com.haxad0x.tools.Core$1.run(Core.java:162) 
05-10 15:46:12.344: E/AndroidRuntime(346): at java.util.Timer$TimerImpl.run(Timer.java:284) 
05-10 15:46:14.194: D/AndroidRuntime(346): Shutting down VM 
05-10 15:46:14.194: W/dalvikvm(346): threadid=1: thread exiting with uncaught exception (group=0x40015560) 
05-10 15:46:14.194: I/Process(346): Sending signal. PID: 346 SIG: 9 

Пожалуйста, помогите мне! Спасибо, парни!


 case R.id.nextColor: 
      loadColor(); 

      mTimer = new Timer(); 

      mTimer.scheduleAtFixedRate(new TimerTask() 
      { 
       public void run() 
       { 
        runOnUiThread(new Runnable() 
        { 
         public void run() { 
         Random gen = new Random(); 
         cur_scr.setBackgroundColor(Color.argb(255, gen.nextInt(256), gen.nextInt(256), gen.nextInt(256))); 
         } 
        }); 
       } 
      }, 0, 2000); 

      break; 

код работает следующим образом. У меня есть только один вопрос: это длинный код? Я имею в виду; это влияет на производительность из-за всех пустот и я могу сократить его?

+0

и сообщение об ошибке, которое оно дает вам в журнале cat ...? Также вы не должны пытаться вызвать findViewById() каждые 30 секунд. Это относительно дорогой метод, назовите его один раз во время вашего onCreate() и просто сохраните ссылку, которую вы получите, и вызовите .setBackgroundcolor() столько раз, сколько вы хотите по этой ссылке. – FoamyGuy

+0

Вы действительно просто использовали мое решение, заработали его, разместите его как свой код сейчас, не проголосуйте за мой пост или не отметьте его, а затем спросите, как его улучшить, когда я четко написал, как улучшить его в своем посте? –

ответ

1

Скорее всего, ваш таймер по-прежнему находится вокруг после того, как ваша деятельность была уничтожена, и ваш вид больше не существует (вызывая отказ findViewById), и вы видите другое представление.

Что нужно сделать, это остановить таймер в onDestroy для активности.

Создать переменный таймер в качестве переменного уровня класса, возможно, mTimer .. Так что вы бы

public class YourActivity extends Activity { 
    private Timer mTimer = null; 

    public void onCreate(Bundle state) { 
    //setContentView 
    mTimer = new Timer(); 
    mTimer.scheduleAtFixedRate(new TimerTask() 
    { 
     public void run() 
     { 
     Random gen = new Random(); 
     cur_scr = (LinearLayout) findViewById(R.id.colorScreen); 
     cur_scr.setBackgroundColor(Color.argb(255, gen.nextInt(256), gen.nextInt(256), gen.nextInt(256))); 
     } 
    }, 0, 30000); 
    } 

    public void onDestroy() { 
    mTimer.cancel(); 
    } 
} 

- Обновление - Хотя я все еще согласен, вы должны сделать вышеуказанные изменения, это выглядит как TimerTask запускается в новом потоке (а не в основном потоке пользовательского интерфейса). Вам нужно запустить любой код, который работает с пользовательским интерфейсом в потоке пользовательского интерфейса. Используйте Activity.runOnUiThread так:

mTimer.scheduleAtFixedRate(new TimerTask() 
{ 
     public void run() 
     { 
     Random gen = new Random(); 
     runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       //actually you should probably put a try catch around the code below so it doesn't crash your app if somehow the view isn't found any longer.. It should work as long as you remove the timer task on onDestroy but to be safe i would put a try catch in. 
       cur_scr = (LinearLayout) findViewById(R.id.colorScreen); 
       cur_scr.setBackgroundColor(Color.argb(255, gen.nextInt(256), gen.nextInt(256), gen.nextInt(256))); 
      } 
     }); 

     } 
} 

Существует еще один способ, который, вероятно, проще сделать это с помощью обработчика.

Это, как я хотел бы сделать это:

public class YourActivity extends Activity { 
    private static final int BG_CHANGE_INTERVAL = 30 * 1000; 
    private Handler mHandler = null; 
    private Runnable mUpdateBgRunnable = new Runnable() { 
    Random gen = new Random(); 
    @Override 
    public void run() { 
     cur_scr = (LinearLayout) findViewById(R.id.colorScreen); 
     cur_scr.setBackgroundColor(Color.argb(255, gen.nextInt(256), gen.nextInt(256), gen.nextInt(256))); 
     updateBg(); 
    } 

    } 
    public void onCreate(Bundle state) { 
    //setContentView 
    mHandler = new Handler(); 
    updateBg(); 
    } 

    private void updateBg() { 
    mHandler.removeCallbacks(mUpdateBgRunnable); 
    mHandler.postDelayed(mUpdateBgRunnable, BG_CHANGE_INTERVAL); 
    } 

    public void onDestroy() { 
    mTimer.cancel(); 
    } 
} 

Смотрите эту article для получения дополнительной информации об обработчиках против таймеров.

+0

Эй, ребята! Я добавил findViewById() в событие onCreate(). Я также попробовал предложение Мэтта Вулфа, но он продолжает терпеть крах. Я не могу отправить logcat, потому что осталось -700 символов? Как я могу опубликовать его? Благодаря! –

+0

можете ли вы разместить больше своего кода? –

+0

это рушится каждый раз независимо от того, что или просто время от времени? Если он всегда сбой, вы, вероятно, получаете classcastexception, что означает, что вид, который вы просматриваете, не соответствует типу ... Нам, по крайней мере, нужно увидеть трассировку стека ошибки, чтобы получить представление. –

Смежные вопросы