Xamarin.Android广播接收器与绑定服务
一、前言
学习了前面的活动与服务后,你会发现服务对于活动而言似乎就是透明的,相反活动对于服务也是透明的,所以我们还需要一中机制能够将服务和活动之间架起一座桥梁,通过本节的学习,你将会学到广播与绑定服务,这两种方式恰恰是解决上面问题的关键。
二、简单的广播接收器
实现一个最简单的广播接收器需要继承BroadcastReceiver类,并且还要实现OnReceive方法,我们可以在项目中新建一个MainReceiver类,然后写入如下代码:
public class MainReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{ }
}
上面其实已经实现了一个简单的广播接收器,并且可以使用。我们还需要注册广播接收器,否则广播接收器就无法接收广播,所以我们需要在MainActivity.cs中注册这个广播接收器。当然为了能够接近现实,我们需要在OnResume中注册,在OnPause中注销。
首先我们在OnResume中注册
protected override void OnResume()
{
base.OnResume();
receiver = new MainReceiver();
RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));
}
接着我们在OnPause中注销
protected override void OnPause()
{
base.OnPause();
UnregisterReceiver(receiver);
}
全部代码如下所示
[Activity(Label = "BroadcastStudy", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
private MainReceiver receiver; protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
} protected override void OnResume()
{
base.OnResume();
receiver = new MainReceiver();
RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));
} protected override void OnPause()
{
base.OnPause();
UnregisterReceiver(receiver);
}
}
注册好了广播接收器,我们还需要一个能够发送广播的地方,既然我们说了这节重点解决的是服务与活动的通信,那么我们就实现一个服务来发送广播。为了能够贴近现实,我们的服务中将会新建一个线程,让这个线程发送一个广播给这个广播接收器。
[Service]
public class MainService : Service
{
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
new Thread(() =>
{
Thread.Sleep();
var sintent = new Intent("xamarin-cn.main.receiver");
sintent.PutExtra("_str", "来自服务");
SendBroadcast(sintent);
}).Start();
return StartCommandResult.Sticky;
} public override IBinder OnBind(Intent intent)
{
return null;
}
}
这里我们通过意图传递了一个参数,而在服务中发送广播的方法是SendBroadcast。其实我们可以看到在创建意图的时候传入了一个字符串,而这个字符串必须与注册广播接收器时指定的字符串一致,否则对应的广播接收器是无法接收到这个广播的,下面我们修改广播接收器的OnReceive方法,以便获取传递过来的字符串并显示。
public override void OnReceive(Context context, Intent intent)
{
string str = intent.GetStringExtra("_str");
new Handler().Post(() =>
{
Toast.MakeText(Application.Context, str, ToastLength.Long).Show();
});
}
其中我们通过意图的GetXXXX方法获取传递过来的参数,然后创建了一个Handler对象并使用Toast发送了一个提示,这里使用Handler是为了与UI线程同步。因为前面讲过只用UI线程才能够访问控件等等对象,而这里并没有RunOnUiThread方法,所以我们需要使用Handler对象的Post方法来实现。
最后有了服务还不行,我们还需要开启这个服务。当然我们依然还是要在OnResume中开启,在OnPause中暂停。
protected override void OnResume()
{
base.OnResume();
receiver = new MainReceiver();
RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));
StartService(new Intent(this, typeof(MainService)));
} protected override void OnPause()
{
base.OnPause();
UnregisterReceiver(receiver);
StopService(new Intent(this, typeof(MainService)));
}
最后我们运行之后的结果如下所示
三、服务向活动发送消息
上面的例子我们仅仅只是打通了服务与广播接收器的通信,而我们今天的主题是服务与活动的双向通信,但是为了能够循序渐进学习,所以我们先学习了服务与广播接收器怎么通信,而这节我们将学习广播接收器如何与活动通信。
因为c#并没有java的部分语言的特性,所以我们没法直接通过匿名的方法创建一个继承自BroadcastReceiver类的实例,所以我们需要先创建一个继承自BroadcastReceiver的具体类,然后在其中定义活动需要响应的方法的委托(Action或者Func),这样我们可以在实例化这个具体类的同时将活动中的方法赋给广播接收器,这样广播接收器在OnReceive中就可以调用活动中的方法了,自然而言就打通了广播接收器与活动的通信。当然还有其他的方法,希望读者可以在留言中留下,以便更多的人进行学习。
首先修改MainReceiver类:
public class MainReceiver : BroadcastReceiver
{
public Action<string> Alert; public override void OnReceive(Context context, Intent intent)
{
string str = intent.GetStringExtra("_str");
if (Alert != null)
{
Alert(str);
}
}
}
在这里我们定义了一个委托(Action<string> Alert)以便活动可以重写,同时还修改了OnReceive中的代码,从而使用活动的方法来显示提示,有了接口之后,我们就可以回到活动中进行重写了。因为广播被实例化的步骤是在OnResume中,所以我们这里直接给出这个方法中的代码(这里我们使用了一个TextView控件tv读者可以需要自行添加下)。
protected override void OnResume()
{
base.OnResume();
receiver = new MainReceiver()
{
Alert = (s) =>
{
RunOnUiThread(() =>
{
tv.Text = s;
});
}
};
RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));
StartService(new Intent(this, typeof(MainService)));
}
现在我们就打通了广播接收器与活动的桥梁,如果有多个方法也是一样的道理,我们现在运行程序可以发现一切正常,下面笔者还要介绍另一种使用接口的方法,首先我们需要一个接口去规定活动需要实现哪些方法,然后在初始化广播接收器的同时将活动的实例赋广播接收器的对应接口变量。下面我们将上面的例子改写,先定义个含有Alert的接口。
public interface IMainInterface
{
void Alert(string s);
}
然后让活动实现该接口
public class MainActivity : Activity, IMainInterface
{
private MainReceiver receiver;
private TextView tv; public void Alert(string s)
{
RunOnUiThread(() =>
{
tv.Text = s;
});
}
接着我们修改广播接收器,公开一个该接收的属性,一遍在广播接收器被初始化的时候可以复制。
public class MainReceiver : BroadcastReceiver
{
public IMainInterface mainInterface; public override void OnReceive(Context context, Intent intent)
{
string str = intent.GetStringExtra("_str");
if (mainInterface != null)
{
mainInterface.Alert(str);
}
}
}
回到MainActivity中修改OnResume方法。
protected override void OnResume()
{
base.OnResume();
receiver = new MainReceiver()
{
mainInterface = this
};
RegisterReceiver(receiver, new IntentFilter("xamarin-cn.main.receiver"));
StartService(new Intent(this, typeof(MainService)));
}
最后效果一样的,读者可以根据实际的情况选择。毕竟他们各自都有或多或少的缺点。
四、绑定服务
其实绑定服务就是将服务中的功能公开给活动,只有这样活动才能调用服务中的方法。而这一过程需要经过一个绑定。首先我们需要一个继承自Binder的类,这样才能将服务通过接口传递给活动。以下为继承自Binder的类,其中我们需要在初始化时将服务传入,然后公开一个方法将服务的实例返回。
public class MainBinder : Binder
{
MainService mainService; public MainBinder(MainService ms)
{
mainService = ms;
} public MainService GetService()
{
return mainService;
}
}
接下来我们打开MainService文件,实现OnBind方法,并将上面类返回。
[Service]
public class MainService : Service
{
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
return StartCommandResult.Sticky;
} public override IBinder OnBind(Intent intent)
{
return new MainBinder(this);
}
}
到此为止,服务这边已经做好了准备。既然是绑定自然不能通过简单的StartService方法开启,因为我们还需要OnBind返回的接口,否则活动无法与服务沟通。这就需要在活动中通过BindService方法进行绑定,但是该方法还需要一个实现了IserviceConnection接口的类,因为通过BindService方法进行绑定的操作是异步的,也就意味着不会阻塞当前调用该方法的线程,而是在服务成功开启并并且OnBind方法返回接口后会回调IserviceConnection中的方法,我们可以看下该接口的方法。
public interface IServiceConnection : IJavaObject, IDisposable
{
void OnServiceConnected(ComponentName name, IBinder service);
void OnServiceDisconnected(ComponentName name);
}
关于接口的方法,大致的解释如下:
OnServiceConnected:当服务中的OnBind方法返回接口后将回调该方法,并且通过service参数将OnBind返回的值传递给这个方法。
OnServiceDisconnected:当服务被关闭或者主动断开连接后回调该方法,如果我们利用这个方法重新恢复连接,或者发出异常并关闭对应的活动。
下面我们实现该接口
public class MainServiceConnection : Java.Lang.Object , IServiceConnection
{
public void OnServiceConnected(ComponentName name, Android.OS.IBinder service)
{ } public void OnServiceDisconnected(ComponentName name)
{ }
}
这里我们没有实现任何代码,该类与活动还没有关联起来,所以我们需要在活动中新建一个公开的变量去保存服务的接口。
[Activity(Label = "BroadcastStudy", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
private TextView tv;
public MainBinder mainBinder;
接着我们就可以实现MainServiceConnection类了。
public class MainServiceConnection : Java.Lang.Object , IServiceConnection
{
MainActivity mainActivity;
public MainServiceConnection(MainActivity ma)
{
mainActivity = ma;
} public void OnServiceConnected(ComponentName name, Android.OS.IBinder service)
{
mainActivity.mainBinder = (MainBinder)service;
} public void OnServiceDisconnected(ComponentName name)
{
mainActivity.mainBinder = null;
}
}
最后我们在活动中就可以进行绑定了。
[Activity(Label = "BroadcastStudy", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
private IServiceConnection serviceConnection;
private TextView tv;
public MainBinder mainBinder; protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
tv = FindViewById<TextView>(Resource.Id.textView1);
} protected override void OnResume()
{
base.OnResume();
serviceConnection = new MainServiceConnection(this);
BindService(new Intent(this, typeof(MainService)), serviceConnection, Bind.AutoCreate);
} protected override void OnPause()
{
base.OnPause();
UnbindService(serviceConnection);
}
}
通过上面的步骤我们还不能看到实际的效果,下面我们需要在服务中实现一个简单的方法,只是返回一段字符串。
public string GetString()
{
return "来自服务";
}
然后在Main.axml中拖放一个按钮,并在活动中进行绑定。
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
Button btn = FindViewById<Button>(Resource.Id.button1);
btn.Click += (e, s) =>
{
if (mainBinder != null)
{
string str = mainBinder.GetService().GetString();
Toast.MakeText(this, str, ToastLength.Long).Show();
}
};
}
这样我们就完成了活动调用服务中的方法,但是现实开发中。如果是耗时的任务。都是活动调用服务公开的方法后立即返回,然后服务在完成之后通过广播将处理的结果返回给活动,整个过程都是异步的。
Xamarin.Android广播接收器与绑定服务的更多相关文章
- android广播接收器
Android程序创建广播接收器继承BroadcastReceiver Android广播接收器需要在AndroidManifest.xml文件中声明: <recevie android:nam ...
- Android应用中创建绑定服务使得用户可以与服务交互
原文:http://android.eoe.cn/topic/android_sdk 一个绑定的服务是客户服务器接口上的一个服务器.一个绑定的服务允许组件(如:活动)来绑定一个服务,传送请求,接收响应 ...
- Android广播接收器Broadcast Receiver-android学习之旅(十二)
首先继承BroadcastReceiver类,并在manifest中注册 public class MyReceiver extends BroadcastReceiver { public MyRe ...
- Android广播接收器和Activity间传递数据
Activity向广播接收器传递数据很简单,只需要在发送广播前将数据put进Intent中就行了. 广播接收器怎么向Activity传送数据?这里要用到接口,通过在广播接收器里定义一个接口,然后让接收 ...
- Android广播接收器里弹出对话框
不多说,直接上车... public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(fina ...
- android广播接收器BroadcastReceiver
首先看一下什么是 BroadcastReceiver BroadcastReceiver:直译是"广播接收者",所以它的作用是用来接收发送过来的广播的. 那我们有必要知道:什么是广 ...
- Android广播接收器BroadcastRceiver
一.使用BroadcastRceiver 1.创建BroadcastRceiver(MyRceiver),重写OnReceiver: public void onReceive(Context con ...
- (八)Android广播接收器BroadcastReceiver
一.使用Broadcast Reciver 1.右击java文件夹,new->other->Broadcast Receiver后会在AndroidManifest.xml文件中生成一个r ...
- Xamarin.Android开发实践(七)
Xamarin.Android广播接收器与绑定服务 一.前言 学习了前面的活动与服务后,你会发现服务对于活动而言似乎就是透明的,相反活动对于服务也是透明的,所以我们还需要一中机制能够将服务和活动之间架 ...
随机推荐
- iOS开发系列--打造自己的“美图秀秀”
--绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz ...
- IE10、IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题
你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的,唯独到了IE10.11这些高版本浏览器就不行了?好吧,这个问题码农连续2天内遇到了2次.那么,我们 ...
- sonn_game网站开发01:写在最前面
之前做的个人博客项目,日向博客现在已经进入后期完善阶段了.是时候开始打造一个新坑了. 然而改造个什么坑呢?构思了好几天,想了好多方案,都觉得没啥动手欲望.因为,我想做的是那种,自己能用得上,而且有一定 ...
- 让 windows 下的命令行程序 cmd.exe 用起来更顺手
在 Windows 下使用 Larave 框架做开发,从 Composer 到 artisan 总是避免不了和 cmd.exe 打交道,系统默认的命令行界面却是不怎么好看,且每行显示的字符数是做了限制 ...
- 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
- 如何将VCSA添加到微软域控环境,并且实现微软域账号登陆vCenter
v:* { } o:* { } w:* { } .shape { } p.msonormal,li.msonormal,div.msonormal { margin: 0cm; margin-bott ...
- 前端MVC学习总结(一)——MVC概要与angular概要、模板与数据绑定
一.前端MVC概要 1.1.库与框架的区别 框架是一个软件的半成品,在全局范围内给了大的约束.库是工具,在单点上给我们提供功能.框架是依赖库的.AngularJS是框架而jQuery则是库. 1.2. ...
- 深入学习HBase架构原理
HBase定义 HBase 是一个高可靠.高性能.面向列.可伸缩的分布式存储系统,利用Hbase技术可在廉价PC Server上搭建 大规模结构化存储集群. HBase 是Google Bigtabl ...
- centos6.5 nginx-1.8.0和ftp搭建图片服务器
一.Nginx的安装步骤 1.Nginx安装环境: gcc: 安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc:yum install gcc-c+ ...