Android AsyncTask 每 x 分钟执行一次

Android AsyncTask execute every x minutes

我有一个 AsyncTask 什么 ping 一些服务器,我也创建了一个定时器但是当我尝试执行时我有一个错误

02-25 02:13:42.645  22313-22313/info.senyk.ustat E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: info.senyk.ustat, PID: 22313
java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
        at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:579)
        at android.os.AsyncTask.execute(AsyncTask.java:535)
        at info.senyk.ustat.StatsActivity$PingTimer.run(StatsActivity.java:190)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:155)
        at android.app.ActivityThread.main(ActivityThread.java:5696)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

我的Activity

public class StatsActivity extends ActionBarActivity {

View mDecorView;

String Login = "0";
String PWD = "0";
String Hostname = "0";
String Port = "0";

String PingResult= "";


PingAsync pingasync;
Ping ping = new Ping();


TextView InfoPing;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_stats);

    mDecorView = getWindow().getDecorView();

    Login = getIntent().getExtras().getString("Login");
    PWD = getIntent().getExtras().getString("PWD");
    Hostname = getIntent().getExtras().getString("Hostname");
    Port = getIntent().getExtras().getString("Port");

    TextView InfoServerId = (TextView) findViewById(R.id.textViewServerId);
    InfoServerId.setText(Login + ":" + PWD + "@" + Hostname + ":" + Port);

    InfoPing = (TextView) findViewById(R.id.textViewPing);

    pingasync = new PingAsync();
    pingasync.execute();

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_stats, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        mDecorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}

public void click(View view) {
    PingTimer pingTimer = new PingTimer();
    pingTimer.startTimer();

}


class PingAsync extends AsyncTask<String, Void, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        InfoPing.setText("Ping ...");
    }

    @Override
    protected String doInBackground(String... params) {

        PingResult = ping.ping(Hostname);

        return PingResult;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        InfoPing.setText(result);

    }

}


public class PingTimer extends ActionBarActivity {

    Timer timer;
    TimerTask timerTask;

    final Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stats);
    }

    @Override
    protected void onResume() {
        super.onResume();
        startTimer();
    }

    public void startTimer() {
        timer = new Timer();


        initializeTimerTask();
        timer.schedule(timerTask, 5000, 10000);
    }

    public void stoptimertask(View v) {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    public void initializeTimerTask() {

        timerTask = new TimerTask() {
            public void run() {
                handler.post(new Runnable() {
                    public void run() {

                        pingasync.execute();


                    }
                });
            }
        };
    }
}

据我所知,AsyncTask 已经执行,但如果我使用

InfoPing.setText(ping.ping(主机名));

改为

pingasync.execute();

我的 Activity 冻结执行 ping.ping(主机名)

有什么解决办法吗?

根据文档,AsyncTasks 只能执行一次。尝试在您的定时器运行中重新初始化它。

public void initializeTimerTask() {
    timerTask = new TimerTask() {
        public void run() {
            handler.post(new Runnable() {
                public void run() {
                    new PingAsyncTask().execute();
                }
            });
        }
    };
}

Threading rules:

There are a few threading rules that must be followed for this class to work properly:

The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN. The task instance must be created on the UI thread. execute(Params...) must be invoked on the UI thread. Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually. The task can be executed only once (an exception will be thrown if a second execution is attempted.)

http://developer.android.com/reference/android/os/AsyncTask.html

此外,在这种情况下使用处理程序比使用 TimerTask() 更好。

从您的LogCat,我们可以知道您的PingAsync()将在您的应用首次打开时执行:

java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)

所以不要在onCreate()方法中调用execute(),要在事件开始时调用,比如按一个Button。但是我们必须在这里初始化它:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_stats);
    // initializing AsyncTask into an Object
    pingasync = new PingAsync();