【发布时间】:2014-05-31 08:59:48
【问题描述】:
我有一项读取 GPS 纬度和经度的服务。我想从服务的locationlistener 的onLocationChanged 更新活动。
我怎样才能实现它?我一直在阅读Service Bound,但看起来它只是让活动调用服务中的方法,而不是服务调用活动中的 textView。难道绑定服务是不可能实现的吗?
【问题讨论】:
标签: android service android-activity textview
我有一项读取 GPS 纬度和经度的服务。我想从服务的locationlistener 的onLocationChanged 更新活动。
我怎样才能实现它?我一直在阅读Service Bound,但看起来它只是让活动调用服务中的方法,而不是服务调用活动中的 textView。难道绑定服务是不可能实现的吗?
【问题讨论】:
标签: android service android-activity textview
您应该使用 Service 中的 LocalBroadcastManager 类将 Intent 发送回 Activity。
例如,包含单个TextView 的Activity 可以像这样设置BroadcastReceiver:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = (TextView) findViewById(R.id.main_activity_text_view);
LocalBroadcastManager.getInstance(this).registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
double latitude = intent.getDoubleExtra(LocationBroadcastService.EXTRA_LATITUDE, 0);
double longitude = intent.getDoubleExtra(LocationBroadcastService.EXTRA_LONGITUDE, 0);
textView.setText("Lat: " + latitude + ", Lng: " + longitude);
}
}, new IntentFilter(LocationBroadcastService.ACTION_LOCATION_BROADCAST)
);
}
@Override
protected void onResume() {
super.onResume();
startService(new Intent(this, LocationBroadcastService.class));
}
@Override
protected void onPause() {
super.onPause();
stopService(new Intent(this, LocationBroadcastService.class));
}
}
一个基本的Service可以广播所有位置变化如下:
public class LocationBroadcastService extends Service {
public static final String
ACTION_LOCATION_BROADCAST = LocationBroadcastService.class.getName() + "LocationBroadcast",
EXTRA_LATITUDE = "extra_latitude",
EXTRA_LONGITUDE = "extra_longitude";
private static final int
MIN_TIME = 2000,
MIN_DISTANCE = 1;
@Override
public void onCreate() {
super.onCreate();
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
sendBroadcastMessage(locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE,
new LocationListener() {
@Override
public void onLocationChanged(Location location) {
sendBroadcastMessage(location);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
);
}
private void sendBroadcastMessage(Location location) {
if (location != null) {
Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
intent.putExtra(EXTRA_LATITUDE, location.getLatitude());
intent.putExtra(EXTRA_LONGITUDE, location.getLongitude());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
【讨论】:
是什么阻止您(在您的服务中)声明这样的方法:
public void setTextViewToModify(TextView tv);
在您将 TextView 的引用提供给您的 Service 之后,它可以像访问任何其他对象一样访问它。
另一方面,我不建议这种解决方案,因为这种方式真的很容易造成内存泄漏。此外,TextView 不应离开 Activity 的上下文,因为它是 Activity 的一部分。即使在 Activity 被销毁后,引用仍会保留在 Service 中,我想您可以想象如果 Service 接触到死的 TextView 会发生什么。
您应该从您的服务广播更新,并使用LocalBroadcastRecever 在您的活动中获取这些更新。这样,TextView 将由负责该操作的人更新,即 Activity 本身。
如果您不喜欢 LocalBroadcatReceiver 的概念,您可以尝试任何事件总线解决方案。它更易于使用,您可以传递任何类型的对象。您不必使它们可编组(Serializable/Parcelable)。
【讨论】: