在workerthread结束之前调用onDestroy的Android服务

时间:2013-08-21 07:52:40

标签: android service ondestroy

我有一个服务,我用它来发送SOAP Webservice调用。一切都很完美,它永远不会崩溃,但我认为应该这样。

我的问题是,当我长时间运行查询(10-50秒)时,在我的workerthread完成之前调用onDestroy()(我调用stopSelfResult)。是不是在LogCat窗口中没有立即执行System.out.println /不同步(缓存)?

是通过QueryBase类启动服务的方式:

QueryBase someService  = new QueryBase(myActivity);
someService.execute(...);

我的QueryBase类

public class QueryBase {

private WeakReference<Activity> currentActivity = null;

private static class ResponseHandler extends Handler {
    private QueryBase mQueryBase;

    public ResponseHandler(QueryBase vQueryBase) {
        mQueryBase = vQueryBase;
    };

    public void handleMessage(Message message) {
        Bundle extras = message.getData();

        mQueryBase.handleResult(message.arg1,message.arg2,extras.getInt("FRAMEID"),extras.getString("RESPONSE"));
        mQueryBase=null;
    };
};

public QueryBase(Activity vActivity) {
    currentActivity = new WeakReference<Activity>(vActivity);
}

/***************************************************************************
 * Start the service
 **************************************************************************/
public boolean execute(Activity vActivity, int cmdID, int frameID, String serverAddress, int requestType, String request) {

    // Valid activity
    if (vActivity==null) return false;

    // Test to see if network is connected
    if (!isOnline(vActivity)) return false;

    Intent webService                           = new Intent(vActivity, WebService.class);
    final ResponseHandler responseHD        = new ResponseHandler(this);
    Messenger messenger                     = new Messenger(responseHD);

    webService.putExtra("QUERYRESULT_MESSENGER",messenger);
    webService.putExtra("CMDID", cmdID);
    webService.putExtra("FRAMEID",frameID);
    webService.putExtra("SERVER_ADDRESS",serverAddress);
    webService.putExtra("REQUEST_TYPE",requestType);
    webService.putExtra("REQUEST",request);

    vActivity.startService(webService);     

    return true;
}

/***************************************************************************
 * Is my Android connected?
 **************************************************************************/
private Boolean isOnline(Activity vActivity) {
    ConnectivityManager connMgr = (ConnectivityManager) vActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    if (networkInfo != null && networkInfo.isConnected()) return true;
    else return false;
}

/***************************************************************************
 * Get current Activity
 **************************************************************************/
public Activity getCurrentActivity() {
    Activity ac = currentActivity.get();
    if (ac!=null) {
        if ((ac.isFinishing()) || (ac.activityDestroyed)) {
            return null;
        };
    }
    return ac;
};

/***************************************************************************
 * XML result from webservice
 **************************************************************************/
public void handleResult(int resultCode, int cmdID, int frameID, String response) {
    System.out.println("DEFAULT HANDLER: ResultCode: " + resultCode);
};

}

我的WebService类

public class WebService extends Service {

public static final int WS_RT_BLOOSOAP  = 0;
public static final int WS_RT_RSS       = 1;

public static final int WS_RESULT_OK = 0;
public static final int WS_RESULT_UNABLE_TO_CONNECT = 2;
public static final int WS_RESULT_INVALID_REQUEST = 3;
public static final int WS_RESULT_UNKNOWN_ERROR = 999;

static private SparseBooleanArray workList=null;        // Only one job with the same frameID is allowed to run

@Override
public void onCreate() {
    System.out.println("#### WebService onCreate");
    if (workList==null) workList = new SparseBooleanArray();
}

@Override
public void onDestroy() {
    System.out.println("#### WebService onDestroy");
}

/***************************************************************************
 * Start working
 **************************************************************************/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    System.out.println("WebService Start ID=" + startId);

    final int currentID         = startId;
    final Intent currentIntent = intent;

    Runnable workerRunnable = new Runnable() {
        public void run() {
            System.out.println("WebService Thread Start - ID=" + currentID);

            int resultCode;

            Bundle responseExtras = new Bundle();

            resultCode = serverRequest(currentIntent,responseExtras);
            sendResponse(currentIntent,resultCode,responseExtras);

            System.out.println("WebService Thread End - ID=" + currentID);

            Bundle  extras = currentIntent.getExtras();
            if (extras != null) {
                int frameID = extras.getInt("FRAMEID");             
                System.out.println(">>>>>>> PUT FALSE " + frameID);                 
                workList.put(frameID, false);
            };

            stopSelfResult(currentID);
        }
    };

    if (intent!=null) {
        Bundle  extras = intent.getExtras();

        if (extras != null) {
            int frameID = extras.getInt("FRAMEID");

            Boolean found = workList.get(frameID,false);
            if (!found) {
                System.out.println(">>>>>>> PUT TRUE FRAMEID=" + frameID);                  
                workList.put(frameID, true);

                Thread workerThread = new Thread(workerRunnable);
                workerThread.start();
            } else {
                System.out.println(">>>>>>> Allready running FRAMEID=" + frameID);                  
            }
        };
    };

    return Service.START_STICKY;
};

/***************************************************************************
 * No binding
 **************************************************************************/
@Override
public IBinder onBind(Intent intent) {
    return null;
}

/***************************************************************************
 * Send webservice request and return result in responseExtras
 **************************************************************************/
private int serverRequest(Intent intent, Bundle responseExtras) {
  ...
};

/***************************************************************************
 * Send response back to service caller using Messenger.send()
 **************************************************************************/
private boolean sendResponse(Intent intent, int resultCode, Bundle responseExtras) {
  ...
};

2 个答案:

答案 0 :(得分:0)

不幸的是,它总会发生。实际上,默认情况下,android应用程序组件的生命周期与任何类型的工作线程都不同步。

因此,您可能需要手动检查服务的状态,例如,您可以使用一个布尔标志来指示服务是否正常工作。另一个方便的方法是使用IntentService而不是使用普通服务,它自己处理工作线程和生命周期功能。

public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService ");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        // This callback-method is called inside worker thread, 
        // so you can do some long-time network job here.
        SystemClock.sleep(30000); // 30 seconds
        // In this timing the service will be stopped automatically.
    }
}    

答案 1 :(得分:0)

如果您使用最新的stopSelfResult()致电startId,您的服务就会停止。因此,如果服务以startId = 1的意图开始,另一个意图使用startId = 2而第二个意图在第一个意图之前完成,则在完成startId = 1之前调用stopSelfResult(2)。如果使用最新的startId调用stopSelfResult()并且没有其他意图待处理,该服务会立即被销毁。

持有最新的startId。添加要在数组中处理的所有startIds(例如List<Integer> runningStartIds),并在完成处理后将其删除。在完成删除后,将当前startId与最新的startId进行比较,如果runningStartIds不为空,则执行调用stopSelfResult()。因此,当最后的startId处理完所有意图并且没有其他意图待处理时,你最终只会调用stopSelfResult()

应该有用,虽然我还没有发布一个例子。

.: EDIT :. Explenation: 无论您在后台做什么,下一个Intent都可以从onStartCommand()返回的速度尽快进入。

.: EDIT :. 不是改进(改进: 考虑到这一点,实际上你只需保留mLastStartId。只需跳过调用stopSelfResult(),直到完成的startId与mLastStartId匹配。)