Xamarin.Android开发实践(七)

简介: 原文:Xamarin.Android开发实践(七) Xamarin.Android广播接收器与绑定服务 一、前言 学习了前面的活动与服务后,你会发现服务对于活动而言似乎就是透明的,相反活动对于服务也是透明的,所以我们还需要一中机制能够将服务和活动之间架起一座桥梁,通过本节的学习,你将会学到广播与绑定服务,这两种方式恰恰是解决上面问题的关键。

原文:Xamarin.Android开发实践(七)

Xamarin.Android广播接收器与绑定服务

一、前言

学习了前面的活动与服务后,你会发现服务对于活动而言似乎就是透明的,相反活动对于服务也是透明的,所以我们还需要一中机制能够将服务和活动之间架起一座桥梁,通过本节的学习,你将会学到广播与绑定服务,这两种方式恰恰是解决上面问题的关键。

 

二、简单的广播接收器

实现一个最简单的广播接收器需要继承BroadcastReceiver类,并且还要实现OnReceive方法,我们可以在项目中新建一个MainReceiver类,然后写入如下代码:

1     public class MainReceiver : BroadcastReceiver
2  { 3 public override void OnReceive(Context context, Intent intent) 4  { 5 6  } 7 }

 上面其实已经实现了一个简单的广播接收器,并且可以使用。我们还需要注册广播接收器,否则广播接收器就无法接收广播,所以我们需要在MainActivity.cs中注册这个广播接收器。当然为了能够接近现实,我们需要在OnResume中注册,在OnPause中注销。

首先我们在OnResume中注册

1         protected override void OnResume()
2  { 3 base.OnResume(); 4 receiver = new MainReceiver(); 5 RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver")); 6 }

 接着我们在OnPause中注销

1         protected override void OnPause()
2  { 3 base.OnPause(); 4  UnregisterReceiver(receiver); 5 }

 全部代码如下所示

 1     [Activity(Label = "BroadcastStudy", MainLauncher = true, Icon = "@drawable/icon")]  2 public class MainActivity : Activity  3  {  4 private MainReceiver receiver;  5  6 protected override void OnCreate(Bundle bundle)  7  {  8 base.OnCreate(bundle);  9  SetContentView(Resource.Layout.Main); 10  } 11 12 protected override void OnResume() 13  { 14 base.OnResume(); 15 receiver = new MainReceiver(); 16 RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver")); 17  } 18 19 protected override void OnPause() 20  { 21 base.OnPause(); 22  UnregisterReceiver(receiver); 23  } 24 }

 注册好了广播接收器,我们还需要一个能够发送广播的地方,既然我们说了这节重点解决的是服务与活动的通信,那么我们就实现一个服务来发送广播。为了能够贴近现实,我们的服务中将会新建一个线程,让这个线程发送一个广播给这个广播接收器。

 1     [Service]
 2     public class MainService : Service  3  {  4 public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)  5  {  6 new Thread(() =>  7  {  8 Thread.Sleep(1000);  9 var sintent = new Intent("xamarin-cn.main.receiver"); 10 sintent.PutExtra("_str", "来自服务"); 11  SendBroadcast(sintent); 12  }).Start(); 13 return StartCommandResult.Sticky; 14  } 15 16 public override IBinder OnBind(Intent intent) 17  { 18 return null; 19  } 20 }

这里我们通过意图传递了一个参数,而在服务中发送广播的方法是SendBroadcast。其实我们可以看到在创建意图的时候传入了一个字符串,而这个字符串必须与注册广播接收器时指定的字符串一致,否则对应的广播接收器是无法接收到这个广播的,下面我们修改广播接收器的OnReceive方法,以便获取传递过来的字符串并显示。

1         public override void OnReceive(Context context, Intent intent)
2  { 3 string str = intent.GetStringExtra("_str"); 4 new Handler().Post(() => 5  { 6  Toast.MakeText(Application.Context, str, ToastLength.Long).Show(); 7  }); 8 }

其中我们通过意图的GetXXXX方法获取传递过来的参数,然后创建了一个Handler对象并使用Toast发送了一个提示,这里使用Handler是为了与UI线程同步。因为前面讲过只用UI线程才能够访问控件等等对象,而这里并没有RunOnUiThread方法,所以我们需要使用Handler对象的Post方法来实现。

 

最后有了服务还不行,我们还需要开启这个服务。当然我们依然还是要在OnResume中开启,在OnPause中暂停。

 1         protected override void OnResume()
 2  {  3 base.OnResume();  4 receiver = new MainReceiver();  5 RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));  6 StartService(new Intent(this, typeof(MainService)));  7  }  8  9 protected override void OnPause() 10  { 11 base.OnPause(); 12  UnregisterReceiver(receiver); 13 StopService(new Intent(this, typeof(MainService))); 14 }

最后我们运行之后的结果如下所示

 

三、服务向活动发送消息

上面的例子我们仅仅只是打通了服务与广播接收器的通信,而我们今天的主题是服务与活动的双向通信,但是为了能够循序渐进学习,所以我们先学习了服务与广播接收器怎么通信,而这节我们将学习广播接收器如何与活动通信。

 

因为c#并没有java的部分语言的特性,所以我们没法直接通过匿名的方法创建一个继承自BroadcastReceiver类的实例,所以我们需要先创建一个继承自BroadcastReceiver的具体类,然后在其中定义活动需要响应的方法的委托(Action或者Func),这样我们可以在实例化这个具体类的同时将活动中的方法赋给广播接收器,这样广播接收器在OnReceive中就可以调用活动中的方法了,自然而言就打通了广播接收器与活动的通信。当然还有其他的方法,希望读者可以在留言中留下,以便更多的人进行学习。

首先修改MainReceiver类:

 1     public class MainReceiver : BroadcastReceiver
 2  {  3 public Action<string> Alert;  4  5 public override void OnReceive(Context context, Intent intent)  6  {  7 string str = intent.GetStringExtra("_str");  8 if (Alert != null)  9  { 10  Alert(str); 11  } 12  } 13 }

在这里我们定义了一个委托(Action<string>  Alert)以便活动可以重写,同时还修改了OnReceive中的代码,从而使用活动的方法来显示提示,有了接口之后,我们就可以回到活动中进行重写了。因为广播被实例化的步骤是在OnResume中,所以我们这里直接给出这个方法中的代码(这里我们使用了一个TextView控件tv读者可以需要自行添加下)。

 1         protected override void OnResume()
 2  {  3 base.OnResume();  4 receiver = new MainReceiver()  5  {  6 Alert = (s) =>  7  {  8 RunOnUiThread(() =>  9  { 10 tv.Text = s; 11  }); 12  } 13  }; 14 RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver")); 15 StartService(new Intent(this, typeof(MainService))); 16 }

现在我们就打通了广播接收器与活动的桥梁,如果有多个方法也是一样的道理,我们现 在运行程序可以发现一切正常,下面笔者还要介绍另一种使用接口的方法,首先我们需要一个接口去规定活动需要实现哪些方法,然后在初始化广播接收器的同时将 活动的实例赋广播接收器的对应接口变量。下面我们将上面的例子改写,先定义个含有Alert的接口。

1     public interface IMainInterface
2  { 3 void Alert(string s); 4 }

然后让活动实现该接口

    public class MainActivity : Activity, IMainInterface
    {
        private MainReceiver receiver;
        private TextView tv; public void Alert(string s) { RunOnUiThread(() => { tv.Text = s; }); }

接着我们修改广播接收器,公开一个该接收的属性,一遍在广播接收器被初始化的时候可以复制。

 1     public class MainReceiver : BroadcastReceiver
 2  {  3 public IMainInterface mainInterface;  4  5 public override void OnReceive(Context context, Intent intent)  6  {  7 string str = intent.GetStringExtra("_str");  8 if (mainInterface != null)  9  { 10  mainInterface.Alert(str); 11  } 12  } 13 }

回到MainActivity中修改OnResume方法。

 1         protected override void OnResume()
 2  {  3 base.OnResume();  4 receiver = new MainReceiver()  5  {  6 mainInterface = this  7  };  8 RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));  9 StartService(new Intent(this, typeof(MainService))); 10 }

最后效果一样的,读者可以根据实际的情况选择。毕竟他们各自都有或多或少的缺点。

 

四、绑定服务

其实绑定服务就是将服务中的功能公开给活动,只有这样活动才能调用服务中的方法。而这一过程需要经过一个绑定。首先我们需要一个继承自Binder的类,这样才能将服务通过接口传递给活动。以下为继承自Binder的类,其中我们需要在初始化时将服务传入,然后公开一个方法将服务的实例返回。

 1     public class MainBinder : Binder
 2  {  3  MainService mainService;  4  5 public MainBinder(MainService ms)  6  {  7 mainService = ms;  8  }  9 10 public MainService GetService() 11  { 12 return mainService; 13  } 14 }

接下来我们打开MainService文件,实现OnBind方法,并将上面类返回。

 1     [Service]
 2     public class MainService : Service  3  {  4 public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)  5  {  6 return StartCommandResult.Sticky;  7  }  8  9 public override IBinder OnBind(Intent intent) 10  { 11 return new MainBinder(this); 12  } 13 }

到此为止,服务这边已经做好了准备。既然是绑定自然不能通过简单的StartService方法开启,因为我们还需要OnBind返回的接口,否则活动无法与服务沟通。这就需要在活动中通过BindService方法进行绑定,但是该方法还需要一个实现了IserviceConnection接口的类,因为通过BindService方法进行绑定的操作是异步的,也就意味着不会阻塞当前调用该方法的线程,而是在服务成功开启并并且OnBind方法返回接口后会回调IserviceConnection中的方法,我们可以看下该接口的方法。

1     public interface IServiceConnection : IJavaObject, IDisposable
2  { 3 void OnServiceConnected(ComponentName name, IBinder service); 4 void OnServiceDisconnected(ComponentName name); 5 }

关于接口的方法,大致的解释如下:

OnServiceConnected:当服务中的OnBind方法返回接口后将回调该方法,并且通过service参数将OnBind返回的值传递给这个方法。

OnServiceDisconnected:当服务被关闭或者主动断开连接后回调该方法,如果我们利用这个方法重新恢复连接,或者发出异常并关闭对应的活动。

 

下面我们实现该接口

 1     public class MainServiceConnection : Java.Lang.Object , IServiceConnection
 2  {  3 public void OnServiceConnected(ComponentName name, Android.OS.IBinder service)  4  {  5  6  }  7  8 public void OnServiceDisconnected(ComponentName name)  9  { 10 11  } 12 }

 

这里我们没有实现任何代码,该类与活动还没有关联起来,所以我们需要在活动中新建一个公开的变量去保存服务的接口。

1     [Activity(Label = "BroadcastStudy", MainLauncher = true, Icon = "@drawable/icon")] 2 public class MainActivity : Activity 3  { 4 private TextView tv; 5 public MainBinder mainBinder;

接着我们就可以实现MainServiceConnection类了。

 1     public class MainServiceConnection : Java.Lang.Object , IServiceConnection
 2  {  3  MainActivity mainActivity;  4 public MainServiceConnection(MainActivity ma)  5  {  6 mainActivity = ma;  7  }  8  9 public void OnServiceConnected(ComponentName name, Android.OS.IBinder service) 10  { 11 mainActivity.mainBinder = (MainBinder)service; 12  } 13 14 public void OnServiceDisconnected(ComponentName name) 15  { 16 mainActivity.mainBinder = null; 17  } 18 }

最后我们在活动中就可以进行绑定了。


 1     [Activity(Label = "BroadcastStudy", MainLauncher = true, Icon = "@drawable/icon")]  2 public class MainActivity : Activity  3  {  4 private IServiceConnection serviceConnection;  5 private TextView tv;  6 public MainBinder mainBinder;  7  8  9 protected override void OnCreate(Bundle bundle) 10  { 11 base.OnCreate(bundle); 12  SetContentView(Resource.Layout.Main); 13 tv = FindViewById<TextView>(Resource.Id.textView1); 14  } 15 16 protected override void OnResume() 17  { 18 base.OnResume(); 19 serviceConnection = new MainServiceConnection(this); 20 BindService(new Intent(this, typeof(MainService)), serviceConnection, Bind.AutoCreate); 21  } 22 23 protected override void OnPause() 24  { 25 base.OnPause(); 26  UnbindService(serviceConnection); 27  } 28 }

通过上面的步骤我们还不能看到实际的效果,下面我们需要在服务中实现一个简单的方法,只是返回一段字符串。

1         public string GetString()
2  { 3 return "来自服务"; 4 }

然后在Main.axml中拖放一个按钮,并在活动中进行绑定。

 1         protected override void OnCreate(Bundle bundle)
 2  {  3 base.OnCreate(bundle);  4  SetContentView(Resource.Layout.Main);  5 Button btn = FindViewById<Button>(Resource.Id.button1);  6 btn.Click += (e, s) =>  7  {  8 if (mainBinder != null)  9  { 10 string str = mainBinder.GetService().GetString(); 11 Toast.MakeText(this, str, ToastLength.Long).Show(); 12  } 13  }; 14 }

这样我们就完成了活动调用服务中的方法,但是现实开发中。如果是耗时的任务。都是活动调用服务公开的方法后立即返回,然后服务在完成之后通过广播将处理的结果返回给活动,整个过程都是异步的。

目录
相关文章
|
4月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
65 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
1月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
179 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
1月前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
56 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
2月前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
111 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
24天前
|
安全 Android开发 iOS开发
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。
|
2月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
43 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
3月前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
85 19
|
3月前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
110 14
|
3月前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 4
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 5
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
  • 6
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 8
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 9
    Android实战经验之Kotlin中快速实现MVI架构
  • 10
    即时通讯安全篇(一):正确地理解和使用Android端加密算法