#java #android #service
#java #Android #Обслуживание
Вопрос:
Я собираю тестовый сборщик данных о местоположении и решил использовать intentservice для получения местоположения, чтобы пользователь мог продолжать заполнять форму в пользовательском интерфейсе.
Этот тестовый класс не реализует форму. Я просто хочу заставить службу работать и заставить ее возвращать местоположение как часть этого теста.
Я проверял Интернет и решил использовать обработчик и сообщение для передачи объекта location обратно.
Проблема в том, что я получаю сообщение об ошибке «отправка сообщения обработчику в мертвом потоке». Я знаю, что сообщение должно быть самоочевидным, но я не вижу, что не так с моим кодом.
Мой основной и единственный код действия приведен ниже
package com.pengilley.locationmanagertest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class LocationManagerTestService extends Activity{
EditText locationField;
Button askLocation;
Location location;
private final static String TAG = "LocationManagerTestService";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
locationField = (EditText)findViewById(R.id.locationtext);
askLocation = (Button)findViewById(R.id.button);
askLocation.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View view) {
getLocation(getApplicationContext());
};
});
}
private void getLocation(Context context){
Intent intent = new Intent(context, LocationTest.class);
startService(intent);
Log.d(TAG,"getLocation: service request sent");
}
final Handler handler = new Handler(){
public void handleMessage(Message msg){
Log.d(TAG,"handleMessage start");
//receive the message from our intentservice
Bundle bundle = msg.getData();
location = (Location)bundle.getParcelable("location");
CharSequence charseq = "Latitude: " location.getLatitude() " Longitude: " location.getLongitude();
locationField.setText(charseq);
}
};
}
Мой класс IntentService находится здесь
package com.pengilley.locationmanagertest;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class LocationTest extends IntentService{
LocationListener locationListener;
Location lastKnownLocation;
Location goodLocation;
LocationManager locationManager;
boolean gpsEnabled;
boolean networkEnabled;
float distanceBetween;
private final static String TAG = "LocationTest";
private final float MAX_DISTANCE_BETWEEN_LOCATIONS = 20;
public static boolean LOCATION_AVAILABLE = false;
private String fieldVal;
private final Handler handler = new Handler();
public LocationTest(){
super("Location test");
}
public void setLocationManager(Context context){
Log.d(TAG,"setLocationManager start");
//setup locationlistener
locationListener = new LocationListener(){
@Override
public void onLocationChanged(Location location) {
Log.d(TAG,"onLocationChanged start");
// TODO Auto-generated method stub
//update check this location against last know location.
//If both locations are close to each other we can stop listening and pass the new location to lResult
lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
//if no location from gps try network
if(lastKnownLocation==null){
lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
if(lastKnownLocation==null){
//use current location
goodLocation = location;
}else{
//check accuracy of current location
distanceBetween = location.distanceTo(lastKnownLocation);
if(distanceBetween <= MAX_DISTANCE_BETWEEN_LOCATIONS){
//good location
goodLocation = location;
}else if(lastKnownLocation.hasAccuracy()){
goodLocation = lastKnownLocation;
}
}
Log.d(TAG,"onLocationChanged: " goodLocation.toString());
//put result into handler
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putParcelable("location", goodLocation);
message.setData(bundle);
handler.sendMessage(message);
Log.d(TAG,"onLocationChanged: messag sent");
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
};
//get location manager
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//check if network and gps are enabled
gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
//request location for providers which are enabled
if(gpsEnabled){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,locationListener);
};
if(networkEnabled){
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
}
public String getFieldVal(){
return fieldVal;
}
@Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
Log.d(TAG,"onHandleIntent start");
setLocationManager(this);
}
}
Ответ №1:
Я решил использовать intentservice для получения местоположения, чтобы пользователь мог продолжать заполнять форму в пользовательском интерфейсе.
Это не очень хорошая идея. IntentService
завершается, когда onHandleIntent()
завершается, и больше никакой работы не требуется. Ваша текущая реализация пропускает память как решето — вы никогда не удаляете свой запрос на обновления, и каждый вызов IntentService
будет регистрировать новый LocationListener
.
Проблема в том, что я получаю сообщение об ошибке «отправка сообщения обработчику в мертвом потоке». Я знаю, что сообщение должно быть самоочевидным, но я не вижу, что не так с моим кодом.
onHandleIntent()
выполняется в фоновом потоке, поток, который давно закончился к тому времени, когда вы пытаетесь его использовать. Кроме того, поскольку вы никогда не удосуживались реализовать handleMessage()
на Handler
, Message
никуда не денется, и уж точно не к activity.
Комментарии:
1. Всем привет. Я не понимаю, почему у моего intentservice будет более одного вызова, если он запускается только при нажатии моей кнопки, которую я нажимаю один раз. Разве onHandleIntent () не отключился бы только после того, как местоположение было найдено? или я должен вручную закрыть его? У меня есть событие handMessage в моей основной деятельности, не там ли будет получено мое сообщение?
2. @Stephen: «Я не понимаю, почему мой intentservice должен иметь более одного вызова, если он запускается только при нажатии моей кнопки, которую я нажимаю один раз». — вы нажимаете ее один раз. Ваши пользователи могут, а могут и нет. Ваши пользователи могут нажимать на него пять раз подряд, и вы ничего не делаете, чтобы остановить их. «Разве onHandleIntent() не отключился бы только после того, как местоположение было найдено? » — нет. «У меня есть событие handMessage в моей основной деятельности, не там ли будет получено мое сообщение?» — нет, потому что это не то место, где находится ваше
Handler
.3. Спасибо за ваши ответы, CommonsWare. Я должен объяснить, что это тестовое приложение является чисто тестом для запуска intentservice. В моем фактическом опубликованном приложении у меня не будет кнопки для запуска службы определения местоположения. Что я не смог понять с помощью обработчиков, так это то, что если мой обработчик используется и создается в одном потоке, как он взаимодействует с другим потоком? Я думал, что в этом и заключается смысл обработчиков… Должен ли я создать отдельный класс, который расширяет обработчик, и тогда и мой основной поток, и мой intentservice смогут получить к нему доступ?
4. @Stephen: «В моем фактически опубликованном приложении у меня не будет кнопки для запуска службы определения местоположения». — а, ладно. «Должен ли я создать отдельный класс, который расширяет обработчик, и тогда и мой основной поток, и мой intentservice смогут получить к нему доступ?» —
Handler
должен быть создан экземпляр и доступен любому классу, которому нужны данные. Если вы пытаетесь доставить aMessage
вActivity
, наличие aHandler
в aService
бессмысленно. Вам понадобитсяHandler
вActivity
и передатьMessenger
вService
. github.com/commonsguy/cw-android/tree/master/Service/Downloader5. Привет, общедоступное программное обеспечение. Спасибо за