将数据从服务发送到其他 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
      }      
}

如果此方法有任何问题,请随时发表评论。