1

私はAndroidアプリに取り組んでおり、30秒ごとに背景を更新したいと思っています。

私はタイマーを使用しました、そしてそれは働きます、しかし一度だけ!2回目にアプリがクラッシュします。

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;

コードはこのように機能します。私はそれについて1つだけ質問があります:それは長いコードですか?つまり; すべてのボイドのためにパフォーマンスに影響しますか?それを短くすることはできますか?

4

1 に答える 1

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は(メインUIスレッドではなく)新しいスレッドで実行されているようです。UIスレッドのUIで機能するコードを実行する必要があります。次のように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();
  }
}

ハンドラーとタイマーの詳細については、この記事を参照してください。

于 2012-05-09T21:57:36.440 に答える