开发者

Timer not shutting down when back button is pressed. Forceclose error on button press

OK all you super java/android guru's. I know your going to look at this and laugh, but I really need the help. Am a super newbie and have read every Google development doc (and many more) and just can't grasp the concept. Can learn a LOT more by seeing working code rather than a referral to something I already read and obviously didn't understand, so if someone can help me out, that would be wonderful.

Main Activity

 import java.util.Timer;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import android.app.Activity;
 import android.app.ProgressDialog;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.webkit.WebView;

 public class Quotes extends Activity implements OnClickListener {

 ProgressDialog dialog;
private WebView webview;
private Timer timer;

 @Override
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    WebView adsview = (WebView) findViewById(R.id.ads);
    adsview.getSettings().setJavaScriptEnabled(true);
    adsview.loadUrl("http://www.dgdevelco.com/quotes/androidad.html");

    SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

    String q = SP.getString("appViewType","http://www.dgdevelco.com/quotes/quotesandroidtxt.html");
    String c = SP.getString("appRefreshRate","20");

    webview = (WebView) findViewById(R.id.scroll);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.setWebViewClient(new QuotesWebView(this));
    webview.loadUrl(q);



    ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
    timer.scheduleAtFixedRate(new Runnable() {

        @Override
        public void run() {
            webview.reload();

            }

        }, 10, Long.parseLong(c),TimeUnit.SECONDS);




    findViewById(R.id.refresh).setOnClickListener(this);


 }

 @Override
 public void onPause(){
   timer.cancel(); 
   super.onPause();
 }

 @Override
 public void onResume(){
  webview.reload();
      super.onResume();
 }


 public void onClick(View v){
    switch(v.getId()){
    case R.id.refresh:
         webview.reload();
         break;
         }
    }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);

    MenuItem about = menu.getItem(0);
    about.setIntent(new Intent(this, About.class));

    MenuItem preferences = menu.getItem(1);
    preferences.setIntent(new Intent(this, Preferences.class));

    return true;

 }



 }   

CatLog

 07-05 17:28:51.001: DEBUG/AndroidRuntime(11446): Shutting down VM
 07-05 17:28:51.001: WARN/dalvikvm(11446): threadid=1: thread exiting with uncaught exception (group=0x40018560)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446): FATAL EXCEPTION: main
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446): java.lang.RuntimeException: Unable to pause activity {com.dge.quotes/com.dge.quotes.Quotes}: java.lang.NullPointerException
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2477)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2424)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:2404)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread.access$1700(ActivityThread.java:124)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:979)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.os.Handler.dispatchMessage(Handler.java:99)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.os.Looper.loop(Looper.java:123)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread.main(ActivityThread.java:3806)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at java.lang.reflect.Method.invokeNative(Native Method)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at java.lang.reflect.Method.invoke(Method.java:507)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at dalvik.system.NativeStart.main(Native Method)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446): Caused by: java.lang.NullPointerException
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at com.dge.quotes.Quotes.onPause(Quotes.java:72)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.Activity.performPause(Activity.java:3901)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1191)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2459)
 07-05 17:28:51.017: ERROR/AndroidRuntime(11446):     ... 12 more
 07-05 17:28:51.509: WARN/ActivityManager(1319): Activity pause timeout for HistoryRecord{40ba7e20 com.dge.quotes/.Quotes}

Any and all help would be greatly appreciated.

At this point I feel like a completely crazed woman who really needs to get this project done so my life can move forward. If anyo开发者_StackOverflow社区ne (ANYONE) has an answer to this, I would REALLY Appreciate it.


You have a private Timer called timer in the activity, however that seems not to have been initialized since you have another timer called timer within your activity. Your private Timer timer defined under the webview is null therefore you get the nullpointexception when onPause is called.

Remove the class from within the onCreate(), you might need to define Timer as a singlethreadscheduledexecutor.

timer = Executors.newSingleThreadScheduledExecutor();
timer.scheduleAtFixedRate(new Runnable() {

Your code with suggested answer:

import java.util.Timer;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import android.app.Activity;
 import android.app.ProgressDialog;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.webkit.WebView;

 public class Quotes extends Activity implements OnClickListener {

 ProgressDialog dialog;
private WebView webview;
private Timer timer;

 @Override
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    WebView adsview = (WebView) findViewById(R.id.ads);
    adsview.getSettings().setJavaScriptEnabled(true);
    adsview.loadUrl("http://www.dgdevelco.com/quotes/androidad.html");

    SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

    String q = SP.getString("appViewType","http://www.dgdevelco.com/quotes/quotesandroidtxt.html");
    String c = SP.getString("appRefreshRate","20");

    webview = (WebView) findViewById(R.id.scroll);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.setWebViewClient(new QuotesWebView(this));
    webview.loadUrl(q);



    timer = Executors.newSingleThreadScheduledExecutor();
    timer.scheduleAtFixedRate(new Runnable() {

        @Override
        public void run() {
            webview.reload();

            }

        }, 10, Long.parseLong(c),TimeUnit.SECONDS);




    findViewById(R.id.refresh).setOnClickListener(this);


 }

 @Override
 public void onPause(){
   timer.cancel(); 
   super.onPause();
 }

 @Override
 public void onResume(){
  webview.reload();
      super.onResume();
 }


 public void onClick(View v){
    switch(v.getId()){
    case R.id.refresh:
         webview.reload();
         break;
         }
    }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu, menu);

    MenuItem about = menu.getItem(0);
    about.setIntent(new Intent(this, About.class));

    MenuItem preferences = menu.getItem(1);
    preferences.setIntent(new Intent(this, Preferences.class));

    return true;

 }



 }   


You could try intercepting onBackPressed in your activity and then do a timer.cancel(). Something like

@Override
public void onBackPressed() {
    timer.cancel();
}


onStop() is the more reliable location to put timer.cancel() (or both places if you want to cover nearly every situation such as circumstances stated at the end here).

onPause() is not called in every situation, it is used when onResume() is reasonably likely to happen, such as when you proceed to another activity and then return. Note the indentation in the lifecycle outline. It may not be called when the back button is pressed.

EDIT 1: this is a pre-edit answer, so may not cover the force-close issue.

EDIT 2:

@Override
public void onStop(){
    super.onStop();
    try {
        timer.cancel();
    } catch (Exception ex) {
        Log.e("MY APP ERROR", ex.getMessage());
    }
}

I have always put the call to super first in these lifecycle methods. I'm not sure if it makes a difference. You'll likely want to set the try/catch statement as well, especially if you choose to include timer.cancel() in both onStop() AND onPause().

EDIT 3: About ready to concede defeat. I'm not that familiar with the quirks of ScheduledExecutorService, and since you've stated you're willing to rewrite, here's how I've accomplished the same things in my apps. Handler is an Android-specific implementation, so perhaps thats why I haven't had the same trouble you are having.

Handler timer;
Runnable runner;

@Override
onCreate(...) {
    ...

    //EDIT 4: (reading time from preferences)
    SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

    final int c = Integer.parseInt(SP.getString("appRefreshRate","20"));

    ...

    runner = new Runnable() {
        @Override
        public void run() {
            timer.postDelayed(runner, c * 1000);
            webview.reload();
        }
    };
    timer = new Handler();
    timer.postDelayed(runner, c * 1000);

    ...
}

@Override
public void onPause(){
    super.onPause();
    try {
        timer.removeCallbacks(runner);
    } catch (Exception ex) {
        Log.e("MY APP ERROR", ex.getMessage());
    }
}

@Override
public void onStop(){
    super.onStop();
    try {
        timer.removeCallbacks(runner);
    } catch (Exception ex) {
        Log.e("MY APP ERROR", ex.getMessage());
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜