将数据从服务发送到其他 Activity 的 BroadcastReceiver (Xamarin Android)
Send Data from a Service to BroadcastReceiver of other Activity (Xamarin Android)
我在将 Location
从服务发送到自定义 BroadcastReceiver 时遇到问题。
这是我的BroadcastReceiver.cs
[BroadcastReceiver]
class MyBroadcastReceiver : BroadcastReceiver
{
public static readonly string GRID_STARTED = "GRID_STARTED";
public event EventHandler<OnLocationChangedEventArgs> mOnLocationChanged;
private Location location;
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
Toast.MakeText(context, "Grid Started", ToastLength.Short).Show();
//location = JsonConvert.DeserializeObject<Location>(intent.GetStringExtra("location"));
//mOnLocationChanged.Invoke(this, new OnLocationChangedEventArgs(location));
}
}
}
如果我取消注释上面代码中的两行,我的应用程序会突然停止。我无法告诉您错误是什么,因为在开发 Xamarin 应用程序时,调试因内部错误而停止(我在 Xamarin 论坛上阅读过相关内容,但没时间处理)。
这是我在服务中所做的:
private void BroadcastStarted(Location location)
{
Intent BroadcastIntent = new Intent(this, typeof(MyBroadcastReceiver));
BroadcastIntent.PutExtra("location",JsonConvert.SerializeObject(location));
BroadcastIntent.SetAction(MyBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
}
我正在使用 Newtonsoft.Json 发送对象。
任何帮助将不胜感激。
更新:
好的,不知何故我设法揭示了错误:
Unable to find a constructor to use for type
Android.Location.Location. A class should either have a default
constructor,one constructor with arguments or a constructor marked
with JsonConstructor attribute.
更新:
整个服务代码:
using Newtonsoft.Json;
namespace GoogleMaps
{
public class OnLocationChangedEventArgs
{
Location location;
public Location Location
{
get { return location; }
set { location = value; }
}
public OnLocationChangedEventArgs(Location location)
{
this.location = location;
}
}
[Service]
class MyService : Service
{
private LocationManager locationManager = null;
public MyService()
{
}
private class MyLocationListener : Java.Lang.Object,ILocationListener
{
Location mLastLocation;
public event EventHandler<OnLocationChangedEventArgs> onLoc;
public MyLocationListener(String provider)
{
mLastLocation = new Location(provider);
}
public void OnLocationChanged(Location location)
{
try
{
mLastLocation.Set(location);
onLoc.Invoke(this, new OnLocationChangedEventArgs(mLastLocation));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void OnProviderDisabled(string provider)
{
}
public void OnProviderEnabled(string provider)
{
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
}
}
private MyLocationListener locationListener = new MyLocationListener("network");
public override IBinder OnBind(Intent intent)
{
return null;
}
private void BroadcastStarted(Location location)
{
Intent BroadcastIntent = new Intent(this, typeof(MyBroadcastReceiver));
BroadcastIntent.PutExtra("location",JsonConvert.SerializeObject(location));
BroadcastIntent.SetAction(MyBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
return StartCommandResult.Sticky;
}
public override void OnCreate()
{
try
{
base.OnCreate();
InitializeLocationManager();
locationManager.RequestLocationUpdates(LocationManager.NetworkProvider, 0, 0, locationListener);
locationListener.onLoc += MyService_onLoc;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void MyService_onLoc(object sender, OnLocationChangedEventArgs e)
{
BroadcastStarted(e.Location);
}
public override void OnDestroy()
{
base.OnDestroy();
locationManager.RemoveUpdates(locationListener);
}
private void InitializeLocationManager()
{
if (locationManager == null)
{
locationManager = (LocationManager)GetSystemService(LocationService);
}
}
}
}
更新:
这是我在第 6 条评论中所说的:
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
try
{
Toast.MakeText(context, "Grid Started", ToastLength.Short).Show();
a = new LatLng(intent.GetDoubleExtra("latitude",0),intent.GetDoubleExtra("longitude",0));
mOnLocationChanged.Invoke(this, new OnLatLngChangedEventArgs(a)); // NULL EXCEPTION LINE
}
catch (Exception ex)
{
Toast.MakeText(context, ex.Message, ToastLength.Short).Show();
}
}
}
为什么事件处理程序 mOnLocationChanged 等于 null?
服务部分:
private void BroadcastStarted(Location location)
{
Intent BroadcastIntent = new Intent(this, typeof(MyBroadcastReceiver));
BroadcastIntent.PutExtra("latitude",location.Latitude);
BroadcastIntent.PutExtra("longitude", location.Longitude);
BroadcastIntent.SetAction(MyBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
}
将数据(不是 object)从 Service(使用 SendBroadcast)发送到 BroadcastReceiver(在 MainActivity 中):
Android-java Gist here.(100% 工作和测试代码)。
C#等效服务Class代码:
(请参阅要点中的导入语句以了解所需的 namespaces/classes)
[Service]
public class BackgroundService : Service {
private static LocationReceiver mTickReceiver;
public BackgroundService()
{
}
public override IBinder OnBind(Intent arg0)
{
return null;
}
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
return StartCommandResult.Sticky;
}
public override Void OnCreate()
{
registerReceiver();
}
public override Void OnDestroy()
{
UnregisterReceiver(mTickReceiver);
mTickReceiver = null;
}
private void registerReceiver()
{
mTickReceiver= new LocationReceiver();
IntentFilter filter = new IntentFilter(Android.Content.Intent.ActionTimeTick); // this will broadcast Intent every minute
RegisterReceiver(mTickReceiver, filter);
}
// you can write this class in separate cs file
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionTimeTick })]
public class LocationReceiver : BroadcastReceiver
{
public override Void OnReceive(Context context, Intent intent)
{
// sample data, you should get your location here,
// one way is to implement location logic in this class
double SampleLatitude=52.01566;
double SampleLongitude=65.00487;
// assuming above coordinates are from some location manager code
Intent i=new Intent();
i.SetAction("LocationData");
i.PutExtra("Latitude",SampleLatitude);
i.PutExtra("Longitude",SampleLongitude);
// PREPARE BROADCAST FOR MAINACTIVITY
SendBroadcast(i); // this broadcast will be received by mainactivity
}
}
}
C#等价的MainActivityClass代码:
(请参阅要点中的导入语句以了解所需的 namespaces/classes)
public class MainActivity : AppCompatActivity {
protected override Void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(R.layout.activity_main);
Intent i=new Intent(this, typeof(BackgroundService));
StartService(i);
IntentFilter filter = new IntentFilter("LocationData");
RegisterReceiver(new MyBroadcastReceiver(),filter);
}
// public static variables of MainActivty can be accessed and manipulated in this class
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "LocationData" })]
class MyBroadcastReceiver : BroadcastReceiver
{
public override Void OnReceive(Context context, Intent intent)
{
// GET BROADCAST FROM RECEIVER IN THE BACKGROUND SERVICE CLASS
if (intent.GetAction() == "LocationData")
{
double lat=intent.GetDoubleExtra("Latitude",0);
double lng=intent.GetDoubleExtra("Longitude",1);
String LocationDataFromService=lat+","+lng;
// REPLACE this with console.writeline
Log.d("LocationDataFromService",LocationDataFromService);
}
}
}
}
在 AndroidManifest.xml
中声明服务为:
<service android:name=".BackgroundService">
</service>
它可能仍然会抛出一些错误。希望这有帮助。
您也可以在 MyBroadcastReceiver.cs
中实现接口。我认为这样更简单。
代码如下:
MyBroadcastReceiver.cs
[BroadcastReceiver]
class MyBroadcastReceiver : BroadcastReceiver
{
public interface LocationDataInterface
{
void OnLocationChanged(LatLng point);
}
public static readonly string GRID_STARTED = "GRID_STARTED";
private LocationDataInterface mInterface;
private LatLng a;
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
try
{
// data you got from background service
a = new LatLng(intent.GetDoubleExtra("latitude",0), intent.GetDoubleExtra("longitude",0));
mInterface = (LocationDataInterface)context;
mInterface.OnLocationChanged(a);
}
catch (Exception ex)
{
Toast.MakeText(context, ex.Message, ToastLength.Short).Show();
}
}
}
}
MainActivity.cs
public class MainActivity : Activity, MyBroadcastReceiver.LocationDataInterface
{
...
public void OnLocationChanged(LatLng point)
{
// textview where you want to show location data
locationText.Text += point.Latitude + "," + point.Longitude;
// things that you want to do with location point
}
}
如果此方法有任何问题,请随时发表评论。
我在将 Location
从服务发送到自定义 BroadcastReceiver 时遇到问题。
这是我的BroadcastReceiver.cs
[BroadcastReceiver]
class MyBroadcastReceiver : BroadcastReceiver
{
public static readonly string GRID_STARTED = "GRID_STARTED";
public event EventHandler<OnLocationChangedEventArgs> mOnLocationChanged;
private Location location;
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
Toast.MakeText(context, "Grid Started", ToastLength.Short).Show();
//location = JsonConvert.DeserializeObject<Location>(intent.GetStringExtra("location"));
//mOnLocationChanged.Invoke(this, new OnLocationChangedEventArgs(location));
}
}
}
如果我取消注释上面代码中的两行,我的应用程序会突然停止。我无法告诉您错误是什么,因为在开发 Xamarin 应用程序时,调试因内部错误而停止(我在 Xamarin 论坛上阅读过相关内容,但没时间处理)。
这是我在服务中所做的:
private void BroadcastStarted(Location location)
{
Intent BroadcastIntent = new Intent(this, typeof(MyBroadcastReceiver));
BroadcastIntent.PutExtra("location",JsonConvert.SerializeObject(location));
BroadcastIntent.SetAction(MyBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
}
我正在使用 Newtonsoft.Json 发送对象。 任何帮助将不胜感激。
更新:
好的,不知何故我设法揭示了错误:
Unable to find a constructor to use for type Android.Location.Location. A class should either have a default constructor,one constructor with arguments or a constructor marked with JsonConstructor attribute.
更新:
整个服务代码:
using Newtonsoft.Json;
namespace GoogleMaps
{
public class OnLocationChangedEventArgs
{
Location location;
public Location Location
{
get { return location; }
set { location = value; }
}
public OnLocationChangedEventArgs(Location location)
{
this.location = location;
}
}
[Service]
class MyService : Service
{
private LocationManager locationManager = null;
public MyService()
{
}
private class MyLocationListener : Java.Lang.Object,ILocationListener
{
Location mLastLocation;
public event EventHandler<OnLocationChangedEventArgs> onLoc;
public MyLocationListener(String provider)
{
mLastLocation = new Location(provider);
}
public void OnLocationChanged(Location location)
{
try
{
mLastLocation.Set(location);
onLoc.Invoke(this, new OnLocationChangedEventArgs(mLastLocation));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public void OnProviderDisabled(string provider)
{
}
public void OnProviderEnabled(string provider)
{
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
}
}
private MyLocationListener locationListener = new MyLocationListener("network");
public override IBinder OnBind(Intent intent)
{
return null;
}
private void BroadcastStarted(Location location)
{
Intent BroadcastIntent = new Intent(this, typeof(MyBroadcastReceiver));
BroadcastIntent.PutExtra("location",JsonConvert.SerializeObject(location));
BroadcastIntent.SetAction(MyBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
return StartCommandResult.Sticky;
}
public override void OnCreate()
{
try
{
base.OnCreate();
InitializeLocationManager();
locationManager.RequestLocationUpdates(LocationManager.NetworkProvider, 0, 0, locationListener);
locationListener.onLoc += MyService_onLoc;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void MyService_onLoc(object sender, OnLocationChangedEventArgs e)
{
BroadcastStarted(e.Location);
}
public override void OnDestroy()
{
base.OnDestroy();
locationManager.RemoveUpdates(locationListener);
}
private void InitializeLocationManager()
{
if (locationManager == null)
{
locationManager = (LocationManager)GetSystemService(LocationService);
}
}
}
}
更新:
这是我在第 6 条评论中所说的:
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
try
{
Toast.MakeText(context, "Grid Started", ToastLength.Short).Show();
a = new LatLng(intent.GetDoubleExtra("latitude",0),intent.GetDoubleExtra("longitude",0));
mOnLocationChanged.Invoke(this, new OnLatLngChangedEventArgs(a)); // NULL EXCEPTION LINE
}
catch (Exception ex)
{
Toast.MakeText(context, ex.Message, ToastLength.Short).Show();
}
}
}
为什么事件处理程序 mOnLocationChanged 等于 null? 服务部分:
private void BroadcastStarted(Location location)
{
Intent BroadcastIntent = new Intent(this, typeof(MyBroadcastReceiver));
BroadcastIntent.PutExtra("latitude",location.Latitude);
BroadcastIntent.PutExtra("longitude", location.Longitude);
BroadcastIntent.SetAction(MyBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
}
将数据(不是 object)从 Service(使用 SendBroadcast)发送到 BroadcastReceiver(在 MainActivity 中):
Android-java Gist here.(100% 工作和测试代码)。
C#等效服务Class代码:
(请参阅要点中的导入语句以了解所需的 namespaces/classes)
[Service]
public class BackgroundService : Service {
private static LocationReceiver mTickReceiver;
public BackgroundService()
{
}
public override IBinder OnBind(Intent arg0)
{
return null;
}
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
return StartCommandResult.Sticky;
}
public override Void OnCreate()
{
registerReceiver();
}
public override Void OnDestroy()
{
UnregisterReceiver(mTickReceiver);
mTickReceiver = null;
}
private void registerReceiver()
{
mTickReceiver= new LocationReceiver();
IntentFilter filter = new IntentFilter(Android.Content.Intent.ActionTimeTick); // this will broadcast Intent every minute
RegisterReceiver(mTickReceiver, filter);
}
// you can write this class in separate cs file
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionTimeTick })]
public class LocationReceiver : BroadcastReceiver
{
public override Void OnReceive(Context context, Intent intent)
{
// sample data, you should get your location here,
// one way is to implement location logic in this class
double SampleLatitude=52.01566;
double SampleLongitude=65.00487;
// assuming above coordinates are from some location manager code
Intent i=new Intent();
i.SetAction("LocationData");
i.PutExtra("Latitude",SampleLatitude);
i.PutExtra("Longitude",SampleLongitude);
// PREPARE BROADCAST FOR MAINACTIVITY
SendBroadcast(i); // this broadcast will be received by mainactivity
}
}
}
C#等价的MainActivityClass代码:
(请参阅要点中的导入语句以了解所需的 namespaces/classes)
public class MainActivity : AppCompatActivity {
protected override Void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(R.layout.activity_main);
Intent i=new Intent(this, typeof(BackgroundService));
StartService(i);
IntentFilter filter = new IntentFilter("LocationData");
RegisterReceiver(new MyBroadcastReceiver(),filter);
}
// public static variables of MainActivty can be accessed and manipulated in this class
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "LocationData" })]
class MyBroadcastReceiver : BroadcastReceiver
{
public override Void OnReceive(Context context, Intent intent)
{
// GET BROADCAST FROM RECEIVER IN THE BACKGROUND SERVICE CLASS
if (intent.GetAction() == "LocationData")
{
double lat=intent.GetDoubleExtra("Latitude",0);
double lng=intent.GetDoubleExtra("Longitude",1);
String LocationDataFromService=lat+","+lng;
// REPLACE this with console.writeline
Log.d("LocationDataFromService",LocationDataFromService);
}
}
}
}
在 AndroidManifest.xml
中声明服务为:
<service android:name=".BackgroundService">
</service>
它可能仍然会抛出一些错误。希望这有帮助。
您也可以在 MyBroadcastReceiver.cs
中实现接口。我认为这样更简单。
代码如下:
MyBroadcastReceiver.cs
[BroadcastReceiver]
class MyBroadcastReceiver : BroadcastReceiver
{
public interface LocationDataInterface
{
void OnLocationChanged(LatLng point);
}
public static readonly string GRID_STARTED = "GRID_STARTED";
private LocationDataInterface mInterface;
private LatLng a;
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
try
{
// data you got from background service
a = new LatLng(intent.GetDoubleExtra("latitude",0), intent.GetDoubleExtra("longitude",0));
mInterface = (LocationDataInterface)context;
mInterface.OnLocationChanged(a);
}
catch (Exception ex)
{
Toast.MakeText(context, ex.Message, ToastLength.Short).Show();
}
}
}
}
MainActivity.cs
public class MainActivity : Activity, MyBroadcastReceiver.LocationDataInterface
{
...
public void OnLocationChanged(LatLng point)
{
// textview where you want to show location data
locationText.Text += point.Latitude + "," + point.Longitude;
// things that you want to do with location point
}
}
如果此方法有任何问题,请随时发表评论。