1

我有一个用于发送 SOAP Webservice 调用的服务。一切都运行良好,它永远不会崩溃,但我认为它应该。

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

这是如何通过 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);
};

}

我的网络服务类

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) {
  ...
};
4

2 回答 2

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.
    }
}    
于 2013-08-21T08:13:53.200 回答
0

如果您stopSelfResult()使用最新的startId. 因此,如果服务以 startId=1 的意图和 startId=2 的另一个意图启动,并且第二个意图在第一个意图stopSelfResult(2)之前完成,则您在 startId=1 完成之前调用。如果您stopSelfResult()使用最新的 startId 调用并且没有其他意图待处理,则服务会立即销毁。

持有最新的 startId。将您希望处理的所有 startId 添加到一个数组中(例如List<Integer> runningStartIds),并在您完成处理后将其删除。完成删除后,将当前的startId与最新的比较,如果runningStartIds不为空则不调用。stopSelfResult()因此,当所有意图都已处理并且没有更多意图待处理时,您最终将stopSelfResult()只调用最新的 startId。

应该工作,虽然我没有发布一个例子。

。:编辑:。解释:无论您在后台做什么,下一个Intent可能会在您返回时尽快出现。onStartCommand()

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

于 2013-08-21T14:32:11.040 回答