葡京娱乐注册android 5.0 以上监听网络转移

gen_server

前言#

世家吓,大概有一个多月份无更新博客了,我是为什么去矣呢?很显著,程序员当然如果加班……这无异涂鸦及大家大快朵颐一下初品类的一些经验。

监听网络转移在出被凡经常利用的,例如我们断网有一些团结的唤醒,或者根据不同之大网改一些加载策略,例如wifi看视频,非wifi则会来一个提醒,还有无限个别更恶心的偷摸的当后台受您生各种安装包,是谁我哪怕不一一列举了。

每当5.0以前,我们都是广播BroadcastReceiver,注册及网络生成有关的播放,然后判断是接连要断开,这种做法充分有利于,但是随着安卓底版本迭代,在权力上更加小心,广播的法子尽管显得不太优雅。

于个如,之前便是将个要命喇叭,在马路上各种喊,就象是逛地摊,各种商品的吆喝声混在共,需要您自己去辨别哪些是你想要之信息,而且又显得挺不安全,万一卖的货品较隐私吗,大家还是挺低调之人头。

故而当安卓5.0上述算对网的监听进行了优化,那就是是透过Callback回调的法,这种支付模式是不是怪常用?例如监听下充斥进度,我独自待三个回调:下载成功,下载失败,下载的快慢变化,这种回调方式对强,耦合性低,非常有利于,和播放相比,就恍如我们是一个订购了劳务,需要之东西自动上门,very
good。

废话铺垫了这样多,下面就是是一个实战demo。

概要
  通用服务器行为
描述

正文#

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        // 请注意这里会有一个版本适配bug,所以请在这里添加非空判断
        if (connectivityManager != null) {
            connectivityManager.requestNetwork(new NetworkRequest.Builder().build(), new ConnectivityManager.NetworkCallback() {

                /**
                 * 网络可用的回调
                 * */
                @Override
                public void onAvailable(Network network) {
                    super.onAvailable(network);
                    Log.e("lzp", "onAvailable");
                }

                /**
                 * 网络丢失的回调
                 * */
                @Override
                public void onLost(Network network) {
                    super.onLost(network);
                    Log.e("lzp", "onLost");
                }

                /**
                 * 当建立网络连接时,回调连接的属性
                 * */
                @Override
                public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
                    super.onLinkPropertiesChanged(network, linkProperties);
                    Log.e("lzp", "onLinkPropertiesChanged");
                }

                /**
                 *  按照官方的字面意思是,当我们的网络的某个能力发生了变化回调,那么也就是说可能会回调多次
                 *
                 *  之后在仔细的研究
                 * */
                @Override
                public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
                    super.onCapabilitiesChanged(network, networkCapabilities);
                    Log.e("lzp", "onCapabilitiesChanged");
                }

                /**
                 * 在网络失去连接的时候回调,但是如果是一个生硬的断开,他可能不回调
                 * */
                @Override
                public void onLosing(Network network, int maxMsToLive) {
                    super.onLosing(network, maxMsToLive);
                    Log.e("lzp", "onLosing");
                }

                /**
                 * 按照官方注释的解释,是指如果在超时时间内都没有找到可用的网络时进行回调
                 * */
                @Override
                public void onUnavailable() {
                    super.onUnavailable();
                    Log.e("lzp", "onUnavailable");
                }

            });
        }
    }
}

}

就就算是今日的凡事代码了,上面已闹了响应的注解,但是还是不够便利我们解,接下去就仔细的研究一下:

1、首先我们开辟app,此时网络是连接的状态:

image

同等打开demo,我们顿时就拿走了onAvailable的回调,意思就是是网时可用,这同样点于广播强多了,因为我们都开行还要单独处理同涂鸦,而通过回调的计,可以及时获得时底状态。

2、然后我们手动关闭网络:

image

哟?没有onLosing的回调,只见到了onLost,说明我们手动关闭网络连接是一个雅粗的行,就比如官注释上写的,如果是一个平板的断开,他或许不回调。

3、最后我们还连网络:

image

这次的回调就比较多矣,首先是onAvailable,显示网络可用,然后是onCapabilitiesChanged,说这网络的连天能力产生了第一次于变动,估计是连接着拿,再然后是onLinkPropertiesChanged,说明连接的属性都生了变通,此时应有抱了ip地址等信息,最后还要回调了onCapabilitiesChanged,那么当是网络快及可用之状态。

  行为模块实现服务器的客户端-服务器涉及。一个通用的服务器进程使这模块将贯彻均等组正式的接口功能,包括跟和错误报告功能。它呢抱OTP进程监控树。了解又多信息参考OTP设计条件。

总结#

自家从不学出onLosing和onUnavailable的面貌,至少说明他俩的面世的概率现在已不强了,我们曾经由此注释简单了解了她们的现象,这里虽非做透研讨了。

经过刚才之实验,我们得出了转结论:

1、要惦记监听网络的总是和断开,应该在onAvailable和onLost中,他们肯定会成对出现。

2、其他的几乎单回调使用状况会少一点,并且onCapabilitiesChanged会回调多次,所以采取她时我们如果慎重,避免重新的操作,但是好包最后一浅回调,网络的接连一定是连续成之。

OK,从之小小的别,我们看到了安卓于渐渐转移得更好,使用起来重新简洁又优雅,这吗加大了某些素质没有的厂商想尽办法后台干点坏事的一言一行。

今日就是顶这里,有啊问题大家齐留言讨论~

  gen_server假定所有特定部分在一个回调模块,它导出的一律组预定义的功力。行为函数和回调函数的关联得以证实如下:

补充#

1、记得申请权限:
<uses-permission
android:name=”android.permission.CHANGE_NETWORK_STATE” />
<uses-permission android:name=”android.permission.WRITE_SETTINGS”
/>
尤其是WRITE_SETTINGS,这个需要手动申请,千万别忘了。

  gen_server module Callback module
  —————– —————
  gen_server:start_link —–> Module:init/1

  gen_server:call
  gen_server:multi_call —–> Module:handle_call/3

  gen_server:cast
  gen_server:abcast     —–> Module:handle_cast/2

  -               —–> Module:handle_info/2

  -               —–> Module:terminate/2

  -               —–> Module:code_change/3

  如果一个回调函数失败或返回一个荒谬的价,gen_server将见面停。

  gen_server处理体系信息,它们记录在sys。sys模块可就此来调节gen_server。

  请注意,gen_server并无自动地破获退出信号,这个得旗帜鲜明地当回调模块启动。

  除非其他发说明,如果指定的gen_server不有或者叫来荒唐参数,该模块所有函数会失败。

  如果一个回调函数指定”hibernate”而非是超时值,该gen_server进程会跻身休眠。这或者是行之有效之,如果服务器预计闲置可怜丰富一段时间。不过这职能应该小心用,使用休眠意味着至少发生些许单污染源收集(休眠以迅速唤起),不是若想做的业务里面,每次调用一个忙碌的服务器。

导出

start_link(Module, Args, Options) -> Result
start_link(ServerName, Module, Args, Options) -> Result
  Types:
    ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
      Name = atom()
      GlobalName = ViaName = term()
    Module = atom()
    Args = term()
    Options = [Option]
      Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
      Dbgs = [Dbg]
        Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
      SOpts = [term()]
    Result = {ok,Pid} | ignore | {error,Error}
      Pid = pid()
      Error = {already_started,Pid} | term()

  创建一个gen_server进程作为监控树的均等有。函数应该直接或者间接地于supervisor调用。它用保证gen_server在旁地方吃链接到supervisor。

  gen_server进程调用Module:init/1进行初始化。为保证同步启动过程,start_link/3,4直到Module:init/1执行到位才能够回去。

  如果ServerName={local,Name},gen_server使用register/2被登记为本土的Name。如果ServerName={global,GlobalName},gen_server使用global:register_name/2被登记也大局的GlobalName。如果无提供Name,gen_server不会被登记。如果ServerName={via,Module,ViaName},gen_server将会为此Module代表的注册表注册。Module回调应该导出函数register_name/2,
unregister_name/1, whereis_name/1 和
send/2,它们表现得像global模块对应的函数。因此,{via,global,GlobalName}是一个行之有效地引用。

  Module是回调模块的名。

  Args是任意term,作为参数传递给Module:init/1。

  如果选择是{timeout,Time},gen_server被允许花费Time毫秒初始化,或者它以给停止,并且启动函数返回{error,timeout}。
  如果选择是{debug,Dbgs},对于Dbgs里的每个条目,对应之sys函数将会见于调用。参见sys。
  如果选择是{spawn_opt,SOpts},SOpts将为当做挑选列表传递给spawn_opt内建函数,它让用来产生gen_server。

  如果gen_server被成功开创和初始化,函数返回{ok,Pid},其中Pid是gen_server的进程号。如果就是以指定ServerName的经过,函数返回{error,{already_started,Pid}},其中,Pid是好进程的进程号。

  如果Module:init因为Reason失败,函数返回{error,Reason}。如果Module:init/1返回{stop,Reason}
或 ignore,进程被停并且函数会独家返回{error,Reason} 或 ignore。

start(Module, Args, Options) -> Result
start(ServerName, Module, Args, Options) -> Result
  Types:
    同 start_link/3,4。

  创建一个单独的gen_server进程,也就是,gen_server不是监控树的一致有的还要没有监控进程。

  参看start_link/3,4摸底参数和返回值的叙说。

call(ServerRef, Request) -> Reply
call(ServerRef, Request, Timeout) -> Reply
  Types:
    ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
      Node = atom()
      GlobalName = ViaName = term()
    Request = term()
    Timeout = int()>0 | infinity
    Reply = term()

  通过发送请求于引用名吧ServerRef的gen_server进行共同调用,直到回复达或出过。gen_server将调用Module:handle_call/3处理要。

  ServerRef可以是:

  • 进程号;
  • Name,gen_server被地方注册的号;
  • {Name,Node},gen_server在另外节点被本地注册;
  • {global,GlobalName},gen_server被全局注册;
  • {via,Module,ViaName},gen_server通过代表的过程注册表注册;

  Request是一个任意term,它当其中的参数传递给Module:handle_call/3。

  Timeout是一个过量零的平头,它指定多少毫秒等待每个回复,原子infinity会无限期的等待。默认值是5000。如果在指定时间外没有接收回复,函数会调用失败。如果调用者捕获失败而延续运行,服务器就晚些回复,它以以外时候到随后进入调用者的音队列。对这个,调用者必须备这种气象,并且不保留任何杂质信息,它们是简单个要素元组作为第一单元素。

  返回值Reply被定义在Module:handle_call/3的回值里。

  调用可能会见因为几乎种植原因失败,包括超时和于调用前以及调用过程遭到gen_server死掉。

  于调用内当连接到客户端,如果服务器死掉,有时会消耗退出消息,这个过时的行就当OTP
R12B/Erlang 5.6遭到移除。

multi_call(Name, Request) -> Result
multi_call(Nodes, Name, Request) -> Result
multi_call(Nodes, Name, Request, Timeout) -> Result
  Types:
    Nodes = [Node]
      Node = atom()
    Name = atom()
    Request = term()
    Timeout = int()>=0 | infinity
    Result = {Replies,BadNodes}
      Replies = [{Node,Reply}]
        Reply = term()
      BadNodes = [Node]

  对富有在指定节点上于当地注册也Name的gen_server进行同步调用,通过第一不行发送请求到每个节点,然后等待回复。这些gen_server进程将会调用Module:handle_call/3处理要。

  函数返回元组{Replies,BadNodes},其中,Replies是{Node,Reply}的列表,BadNodes是无存在节点的列表,或gen_server
Name不有或者无过来。

  Nodes是呼吁让发送到的节点名称列表。默认值是受享有都知道的节点列表[node()|nodes()]。

  Name是每个gen_server被当地注册之称呼。

  Request是一个任意term,它看作中的参数传递给Module:handle_call/3。

  Timeout是一个超过零的整数,它指定多少毫秒等待每个回复,原子infinity会无限期的等候。默认值是infinity。如果在指定时间外节点没有吸收回复,该节点被投入到BadNodes。
当以节点Node来自gen_server回复Reply到达,{Node,Reply}被在到Replies。Reply被定义在Module:handle_call/3的归值里。

  为避免随后的回(在过之后)污染调用者的音讯队列,一个中等人经过被用来举行实际的调用。当她到达一个停下的历程,迟到的东山再起将未会见为保留。

cast(ServerRef, Request) -> ok
  Types:
  ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
    Node = atom()
    GlobalName = ViaName = term()
  Request = term()

  发送一个异步请求到引用名ServerRef的gen_server,然后随即回ok,如果目标节点还是gen_server不设有,忽小消息。gen_server将调用Module:handle_cast/2处理要。

  参看call/2,3,了解ServerRef的描述。

  Request是一个任意term,它看作中的参数传递给Module_cast/2。

abcast(Name, Request) -> abcast
abcast(Nodes, Name, Request) -> abcast
  Types:
    Nodes = [Node]
      Node = atom()
    Name = atom()
    Request = term()

  发送一个异步请求被在指定节点被当地注册为Name的gen_server。函数立即回去并且忽略不有的节点,或gen_server
Name不存在。gen_server将调用Module:handle_cast/2处理要。

  参看 multi_call/2,3,4,了解参数描述。

reply(Client, Reply) -> Result
  Types:
    Reply = term()
    Result = term()

  当回复没有概念在Module:handle_call/3的回值里,该函数可以被gen_server用来显式地发送过来给一个调用
call/2,3 或 multi_call/2,3,4底客户端。

  Client必须是提供于回调函数的From参数。Reply是一个任意term,它将作为call/2,3
或 multi_call/2,3,4之回来值为恢复到客户端。

  返回Result没有受越来越定义,并且该总是吃忽视。

enter_loop(Module, Options, State)
enter_loop(Module, Options, State, ServerName)
enter_loop(Module, Options, State, Timeout)
enter_loop(Module, Options, State, ServerName, Timeout)
  Types:
    Module = atom()
    Options = [Option]
      Option = {debug,Dbgs}
        Dbgs = [Dbg]
          Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
    State = term()
    ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
      Name = atom()
      GlobalName = ViaName = term()
    Timeout = int() | infinity

  使一个已经是的过程进入一个gen_server。不回去,反而是调用进程将上gen_server的收纳循环,并成一个gen_server进程。这个历程要以proc_lib的开行函数被启动。用户也该过程的旁初始化负责,包括为其注册一个名。

  这个函数非常有因此,当得一个一发扑朔迷离的初始化过程,而无是gen_server行为提供的。

  Module,Option
和ServerName与调用gen_server:start[_link]/3,4富有相同之义。然而,如果ServerName被指定,进程必须以拖欠函数被调用前相应地吃登记。

  State和Timeout与Module:init/1的返回值有着相同之含义。回调模块Module也未需要导出一个init/1套数。

  失败:如果调用进程未被一个proc_lib函数启动,或者只要它们不根据ServerName注册。

回调函数

Module:init(Args) -> Result
  Types:
    Args = term()
    Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate} | {stop,Reason} | ignore
      State = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  无论何时一个gen_server使用gen_server:start/3,4 或
gen_server:start_link/3,4吃启动,该函数被一个初历程调用去初始化。

  Args是供于启动函数的参数。

  如果初始化成功,函数应该归{ok,State}, {ok,State,Timeout} 或
{ok,State,hibernate},其中,State是gen_server的其中状态。

  如果一个平头超时值被提供,一个逾期将发生,除非在Timeout毫秒内接收一个求或信息。一个超时被timeout原子标识,它应被handle_info/2回调函数处理。infinity可以叫用来无限期地等候,这是默认值。

  如果hibernate被指定要未是一个超时值,进程将进入休眠当等待下一样长长的信息到达时(调用proc_lib:hibernate/3)。

  如果当初始化期间出现谬误,函数返回{stop,Reason},其中,Reason是其他term,或ignore。

Module:handle_call(Request, From, State) -> Result
  Types:
    Request = term()
    From = {pid(),Tag}
    State = term()
    Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout} | {reply,Reply,NewState,hibernate}
      | {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate}
      | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
      Reply = term()
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  无论何时使用gen_server:call/2,3 或
gen_server:multi_call/2,3,4,gen_server接收请求发送,该函数被调用处理要。

  Request是提供于call或multi_call的参数。

  From是一个元组{Pid,Tag},其中,Pid是客户端的进程号,Tag是一个唯一标志。

  State是gen_server的内状态。

  如果函数返回{reply,Reply,NewState}, {reply,Reply,NewState,Timeout}
或 {reply,Reply,NewState,hibernate},Reply将吃还原给From作为call/2,3 或
multi_call/2,3,4的归值。然后gen_server继续执行,可能更新中状态NewState。参看Module:init/1了解Timeout和hibernate的讲述。

  如果函数返回{noreply,NewState}, {noreply,NewState,Timeout} 或
{noreply,NewState,hibernate},gen_server将就此NewState继续执行。任何对From的恢复必须显式使用gen_server:reply/2。

  如果函数返回{stop,Reason,Reply,NewState},Reply将卷土重来给From。如果函数返回{stop,Reason,NewState},任何对From的回升必须显式使用gen_server:reply/2。然后,函数将调用Module:terminate(Reason,NewState),随后停下。

Module:handle_cast(Request, State) -> Result
  Types:
    Request = term()
    State = term()
    Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  无论何时,gen_server接收一个伸手发送使用gen_server:cast/2 或
gen_server:abcast/2,3,该函数被调用处理要。

  参见Module:handle_call/3了解参数与可能回到回值的讲述。

Module:handle_info(Info, State) -> Result
  Types:
    Info = timeout | term()
    State = term()
    Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = normal | term()

  该函数被gen_server调用,当超时出或者接收及其他消息一经不是并还是异步请求(或者系统信息)。

  Info是原子timeout,当超时发出,或是已接受的信息。

Module:terminate(Reason, State)
  Types:
    Reason = normal | shutdown | {shutdown,term()} | term()
    State = term()    

  该函数被gen_server调用,当它们准备停止。它应同Module:init/1相反,并召开必要之清理。当其回到时,gen_server由于Reason终止。返回值为忽视。

  Reason是一个term,指出已原因,State是gen_server的内部状态。

  Reason取决于gen_server终止的原委。如果以另外一个回调函数已经回一个停元组{stop,..},Reason将会晤生指定的价值在挺元组。如果是由黄,Reason是误原因。

  如果gen_server是监控树的一模一样组成部分,并且于监控者有序终止,该函数将受调用,使用Reason=shutdown,如果以以下状态:

  • gen_server已经设置也洗脱信号;
  • 同时,被定义在监控者的子规范的关策略是一个整数价,而休是brutal_kill。

  即使gen_server不是监控者的一致部分,如果接来自父亲进程的’EXIT’消息,函数将让调用。Reason将跟’EXIT’音无异于。

  否则,gen_server将立即终止。

  注意,除了normal,shutdown,或{shutdown,Term}的其余原因,gen_server被设定终止由于一个误,并且动用error_logger:format/2报告一个左。

Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}
  Types:
    OldVsn = Vsn | {down, Vsn}
      Vsn = term()
    State = NewState = term()
    Extra = term()
    Reason = term()

  该函数被gen_server调用,当她于本升级/降级应该更新自己的其中状态,也就是说,当令{update,Module,Change,…}在appup文件被叫于来,其中Change={advanced,Extra}。参看OTP设计原则查看更多信息。

  在提升之状况下,OldVsn就是Vsn;在降的状态下,OldVsn就是{down,Vsn}。Vsn被回调模块Module的一直版的vsn属性定义。如果没有如此的特性定义,版本就是BEAM文件之校验和。

  State是gen_server的中状态。

  Extra来自升级指令的{advanced,Extra}部分,被形容传递。

  如果成功,函数应该归给更新的里状态。

  如果函数返回{error,Reason},正在进展的升级换代将见面失败,并且回滚到老版本。

Module:format_status(Opt, [PDict, State]) -> Status
  Types:
    Opt = normal | terminate
    PDict = [{Key, Value}]
    State = term()
    Status = term()

  请留心,该回调可挑选,所以回调模块不待导出它,这个回调模块提供一个默认实现,该函数返回回调模块状态。

  该函数被gen_server进程调用:

  • sys:get_status/1,2叫调用获取gen_server状态。这种情景,Opt为装置成normal。
  • gem_server异常终止,生成错误日志。这种景象,Opt给装成terminate。

  该函数是行之有效之,对于这些情形定制gen_server的格式和展现。一个回调模块希望定制sys:get_status/1,2底回到值,和其当住错误日志的状态展现,导出一个format_status/2实例,返回描述gen_server时状态的term。

  PDict是gen_server的过程字典的手上值。

  State是gen_server的内部状态。

  函数应该回到Status,定制当前状态的细节以及gen_server的状态的term。在Status格式上没外限制,但是于sys:get_status/1,2状态,对于Status建议之格式是[{data,
[{“State”,
Term}]}],其中,Term提供gen_server相关的细节。遵循这些建议不是须的,但是这么做用使回调模块的状态及sys:get_status/1,2的返回值一致。

  该函数的一个用法是归紧凑的轮换状态表示来避免来了那个之状态项打印在日记里。