我正在开发一个应用程序,该应用程序应不时跟踪用户位置(例如每 20 秒),并在每分钟将这些位置发送到 Web 服务。为此,我创建了一个生产者消费者结构,其中每个任务都是一个由 AlarmManagers/BroadcastReceivers 启动的 android 服务。该应用程序还有一个使用 Phonegap 和 JQuery Mobile 开发的 UI,用于执行辅助任务并将一些数据发送到服务(例如用户名)。当负责网络通信的服务陷入 getInputStream() 方法并引发 Android Not Responding 对话框时,就会出现问题。我知道不应该在 UI 线程中执行冗长的操作,但我不确定如何根据我的方法解决这个问题,有什么线索吗?
下面是我的应用清单和一些代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.fcl"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:configChanges="orientation|keyboardHidden"
android:allowBackup="false">
<activity
android:name="com.android.fcl.MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.android.fcl.GPSLoggerService"
android:label="@string/gps_logger_service">
</service>
<service
android:name="com.android.fcl.GPSHttpService"
android:label="@string/gps_http_service">
</service>
<receiver android:name="com.android.fcl.GPSLoggerReceiver" />
<receiver android:name="com.android.fcl.GPSHttpReceiver" />
</application>
</manifest>
Javascript:
function goToPage() {
window.ServiceControl.startService();
$.mobile.changePage('address.html', {transition: 'flip'});
$.mobile.hidePageLoadingMsg();
}
活动:
public class MainActivity extends DroidGap {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init();
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
ServiceControl service = ServiceControl.getInstance();
service.setActivity(this);
service.setView(appView);
appView.addJavascriptInterface(service, "ServiceControl");
ServiceStorage serviceStorage = ServiceStorage.getInstance();
serviceStorage.createDatabase(this);
super.loadUrl("file:///android_asset/www/login.html");
}
}
服务控制.java:
public class ServiceControl {
private AlarmManager gpsAlarmManager;
private PendingIntent gpsPendingIntent;
private AlarmManager httpAlarmManager;
private PendingIntent httpPendingIntent;
public void startService() {
if (this.activity != null) {
Intent gpsIntent = new Intent(this.activity, GPSLoggerReceiver.class);
Intent httpIntent = new Intent(this.activity, GPSHttpReceiver.class);
if (this.gpsAlarmManager == null) {
gpsAlarmManager = (AlarmManager) activity.getSystemService(Service.ALARM_SERVICE);
gpsPendingIntent = PendingIntent.getBroadcast(activity, 0, gpsIntent, 0);
gpsAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), GPS_MIN_TIME, gpsPendingIntent);
}
if (this.httpAlarmManager == null) {
httpAlarmManager = (AlarmManager) activity.getSystemService(Service.ALARM_SERVICE);
httpPendingIntent = PendingIntent.getBroadcast(activity, 0, httpIntent, 0);
httpAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), HTTP_MIN_TIME, httpPendingIntent);
}
}
}
广播接收器:
public class GPSHttpReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, GPSHttpService.class);
context.startService(service);
}
}
服务:
public class GPSHttpService extends Service {
private PowerManager pm = null;
private PowerManager.WakeLock wl = null;
private HttpURLConnection httpConnection = null;
private synchronized void setWakeLock() {
ServiceControl serviceControl = ServiceControl.getInstance();
DroidGap activity = serviceControl.getActivity();
pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
wl.acquire();
}
private String sendPostMessage(String message) {
byte [] buffer = null;
String response = null;
URL url = null;
DataOutputStream outputStream = null;
InputStreamReader inputStream = null;
buffer = message.getBytes();
try {
url = new URL(URI);
httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setDoOutput(true);
httpConnection.setDoInput(true);
httpConnection.setInstanceFollowRedirects(false);
httpConnection.setRequestMethod(FCLString.POST_REQUEST_METHOD);
httpConnection.setRequestProperty(FCLString.CONTENT_TYPE_PROPERTY, FCLString.CONTENT_TYPE_APP_JSON);
httpConnection.setRequestProperty(FCLString.CHARSET_PROPERTY, FCLString.UTF8_FORMAT);
httpConnection.setConnectTimeout(CONN_TIMEOUT);
httpConnection.setRequestProperty(FCLString.CONTENT_LENGTH_PROPERTY, String.valueOf(buffer.length));
httpConnection.setUseCaches(false);
outputStream = new DataOutputStream(httpConnection.getOutputStream());
outputStream.write(buffer);
outputStream.flush();
outputStream.close();
inputStream = new InputStreamReader(httpConnection.getInputStream());
response = GPSMessage.readResponseStream(inputStream);
} catch (MalformedURLException e) {
Log.d(TAG, FCLString.MALFORMED_URL);
} catch (IOException e) {
Log.d(TAG, FCLString.IO_EXCEPTION);
Log.d(TAG, e.getMessage());
} finally {
if (httpConnection != null) {
httpConnection.disconnect();
}
}
return response;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
ServiceStorage serviceStorage = ServiceStorage.getInstance();
JSONObject json= null;
String message = null;
String response = null;
boolean status = false;
super.onStartCommand(intent, flags, startId);
setWakeLock();
json = serviceStorage.getRecords();
if ((json != null) && (json.length() > 0)) {
message = GPSMessage.prepareMessage(json);
if (message != null) {
if (hasInternetConnection()) {
response = sendPostMessage(message);
status = GPSMessage.evaluateResponse(response);
if (status) {
serviceStorage.removeRecords(json);
}
}
}
}
this.stopSelf();
return Service.START_NOT_STICKY;
}
}