2013-05-03 3 views
0

Я разрабатываю приложение, которое время от времени отслеживает местоположение пользователя (например, каждые 20 секунд) и каждую минуту отправляет эти места в веб-службы. Чтобы достичь этого, я создал структуру потребителя-производителя, где каждая задача представляет собой службу android, запущенную AlarmManagers/BroadcastReceivers. Приложение также имеет интерфейс, разработанный с помощью Phonegap и JQuery Mobile для выполнения дополнительных задач и отправки некоторых данных в службы (например, имя пользователя). Проблема возникает, когда служба, ответственная за сетевую связь, застревает в методе getInputStream() и выдает диалоговое окно Android Not Responseing. Я понимаю, что длительные операции не должны выполняться в потоке пользовательского интерфейса, но я не уверен, как решить эту проблему, учитывая мой подход, любую подсказку?Android не отвечает на запросы в службе

Ниже мое приложение манифеста и некоторый код:

<?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"); 
    }  
} 

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

BroadcastReceiver:

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; 
    } 
} 

ответ

0

Вы могли бы рассмотреть возможность использования IntentService вместо того, чтобы просто обычный Service, как ваша работа кажется относительно автономен. Это позаботится о том, чтобы делать вашу работу в отдельном потоке.

+0

Спасибо @kabuko. –

3

С reference doc на Android услуг:

Обратите внимание, что услуги, как и другие объекты приложения, работают в основном нить процесса их хостинга. Это означает, что если ваша служба собирается делать любой интенсивный процессор (например, воспроизведение в формате MP3) или блокировать (например, как сетевые), он должен создать свой собственный поток, в котором должны выполняться . Более подробную информацию об этом можно найти в Processes and Threads. Класс IntentService доступен в качестве стандарта реализации Службы, которая имеет свою собственную нить, где она планирует свою работу.

+0

Спасибо @Santa, я внес изменения, и теперь приложение работает нормально! –