寫在前面:
直接復(fù)制 1 的工具類和 5 的兩個(gè)類到項(xiàng)目中宏怔,就能使用坊谁,如果你不想看中間的過程的話。就是這么貼心的喔~
實(shí)現(xiàn)流程概括
首先矮嫉,我們要實(shí)現(xiàn)實(shí)時(shí)監(jiān)聽,肯定要用到廣播機(jī)制:Android系統(tǒng)在網(wǎng)絡(luò)狀態(tài)發(fā)生變化時(shí)會(huì)發(fā)送一條廣播牍疏,所以我們首先要做的就是寫一個(gè)廣播接收器蠢笋,接收這條廣播。
那接收之后呢鳞陨?
接收之后再通知所有的觀察者昨寞,網(wǎng)絡(luò)有變化了,這里就要用到觀察者模式了厦滤。(不知道觀察者模式也沒關(guān)系编矾,其實(shí)就和回調(diào)的機(jī)制差不多,不知道回調(diào)是什么的話......或許之后我會(huì)專門寫一篇馁害?)
over窄俏,就這么簡單。
1碘菜、工具類(準(zhǔn)備考試)
開始之前凹蜈,復(fù)制這幾個(gè)工具類到你的項(xiàng)目中,為后面的主要工作做準(zhǔn)備忍啸。
首先是一個(gè)枚舉仰坦,列舉的是幾種網(wǎng)絡(luò)狀態(tài)。
public enum NetworkType {
NETWORK_WIFI("WiFi"),
NETWORK_4G("4G"),
NETWORK_2G("2G"),
NETWORK_3G("3G"),
NETWORK_UNKNOWN("Unknown"),
NETWORK_NO("No network");
private String desc;
NetworkType(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return desc;
}
}
然后是一個(gè)網(wǎng)絡(luò)工具類计雌,用來返回網(wǎng)絡(luò)連接狀態(tài)的類型悄晃。
public class NetworkUtil {
private NetworkUtil() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
@RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
private static NetworkInfo getActiveNetworkInfo(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo();
}
/**
* 獲取當(dāng)前網(wǎng)絡(luò)類型
* 需添加權(quán)限 {@code <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>}
*/
@RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
public static NetworkType getNetworkType(Context context) {
NetworkType netType = NetworkType.NETWORK_NO;
NetworkInfo info = getActiveNetworkInfo(context);
if (info != null && info.isAvailable()) {
if (info.getType() == ConnectivityManager.TYPE_WIFI) {
netType = NetworkType.NETWORK_WIFI;
} else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
switch (info.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
netType = NetworkType.NETWORK_3G;
break;
case TelephonyManager.NETWORK_TYPE_LTE:
case TelephonyManager.NETWORK_TYPE_IWLAN:
netType = NetworkType.NETWORK_4G;
break;
case TelephonyManager.NETWORK_TYPE_GSM:
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
netType = NetworkType.NETWORK_2G;
break;
default:
String subtypeName = info.getSubtypeName();
if (subtypeName.equalsIgnoreCase("TD-SCDMA")
|| subtypeName.equalsIgnoreCase("WCDMA")
|| subtypeName.equalsIgnoreCase("CDMA2000")) {
netType = NetworkType.NETWORK_3G;
} else {
netType = NetworkType.NETWORK_UNKNOWN;
}
break;
}
} else {
netType = NetworkType.NETWORK_UNKNOWN;
}
}
return netType;
}
}
最后,最重要的一點(diǎn):
到manifast中添加訪問網(wǎng)絡(luò)狀態(tài)的權(quán)限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
2凿滤、監(jiān)聽廣播(劃重點(diǎn)妈橄,很可能考喔)
我們使用動(dòng)態(tài)注冊的方式,所以首先新建一個(gè) class 翁脆,命名為 NetStateChangeReceiver 眷蚓,使其繼承自 BroadcastReceiver ,這樣一個(gè)廣播接收器就建好了反番。
public class NetStateChangeReceiver extends BroadcastReceiver{
當(dāng)然沙热,現(xiàn)在我們的接收器還不能接收任何東西,所以接下來罢缸,我們寫一個(gè)方法篙贸,告訴接收器接收網(wǎng)絡(luò)變化的廣播。
public static void registerReceiver(Context context){
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver( InstanceHolder.INSTANCE,intentFilter);
}
IntentFilter 是一個(gè)過濾器枫疆,我們給他添加一個(gè)值為 "android.net.conn.CONNECTIVITY_CHANGE"
的action爵川,表示過濾的是網(wǎng)絡(luò)改變廣播。
當(dāng)調(diào)用 registerReceiver() 時(shí)养铸,將 NetStateChangeReceiver 的實(shí)例和 IntentFilter 的實(shí)例都傳了進(jìn)去雁芙,這樣 NetStateChangeReceiver 就會(huì)收到所有值為 "android.net.conn.CONNECTIVITY_CHANGE"
的廣播,也就實(shí)現(xiàn)了監(jiān)聽網(wǎng)絡(luò)變化的功能钞螟。
有注冊當(dāng)然也得有注銷啦兔甘,在 unregisterReceiver() 方法中傳入之前注冊的廣播接收器實(shí)例,這個(gè)實(shí)例就注銷掉了鳞滨。
public static void unRegisterReceiver(Context context){
context.unregisterReceiver(InstanceHolder.INSTANCE);
}
現(xiàn)在洞焙,每當(dāng)網(wǎng)絡(luò)變化時(shí),onReceive() 方法就會(huì)自動(dòng)被調(diào)用了拯啦,于是我們就可以重寫 onReceive() 方法澡匪,做點(diǎn)想♂做的事。
@Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())){
NetworkType networkType = NetworkUtil.getNetworkType(context);
// do something
}
}
在這里褒链,我們拿到了網(wǎng)絡(luò)連接類型 networkType唁情,然后你就可以拿著這個(gè)狀態(tài)做你想做的事啦。
至此甫匹,網(wǎng)絡(luò)監(jiān)聽算是實(shí)現(xiàn)了甸鸟。
3、觀察者(重難點(diǎn)兵迅,必考題)
(方便起見抢韭,我這里只觀察網(wǎng)絡(luò)的連接和斷開兩個(gè)變化)
講到觀察者,首先當(dāng)然要?jiǎng)?chuàng)建觀察者啦恍箭,新建一個(gè)接口文件 NetStateChangeObserver 刻恭,接口中有這兩個(gè)方法,一個(gè)是網(wǎng)絡(luò)連接扯夭,一個(gè)是網(wǎng)絡(luò)斷開鳍贾。
void onNetDisconnected();
void onNetConnected(NetworkType networkType);
類似注冊注銷接收器那樣,我們也需要添加移除觀察者交洗。其實(shí)就是用一個(gè) List 存放每個(gè) observer 贾漏,添加 observer 時(shí),就 add 到 List 里面藕筋,移除 observer 時(shí)纵散,就從 List 中刪掉對應(yīng)的 observer。
private List<NetStateChangeObserver> mObservers = new ArrayList<>();
public static void registerObserver(NetStateChangeObserver observer){
if (!InstanceHolder.INSTANCE.mObservers.contains(observer)){
InstanceHolder.INSTANCE.mObservers.add(observer);
}
}
public static void unRegisterObserver(NetStateChangeObserver observer){
InstanceHolder.INSTANCE.mObservers.remove(observer);
}
終于到最后一步了隐圾,現(xiàn)在來寫通知所有 observer 的方法伍掀。
把上面 onReceive() 方法中的 do something 改成通知所有 observer 。
NetworkType networkType = NetworkUtil.getNetworkType(context);
// do something
notifyObservers(networkType);
notifyObservers() 方法如下暇藏,類型變成無網(wǎng)絡(luò)時(shí)就調(diào)用觀察者接口中的 onNetDisconnected() 方法蜜笤,for 循環(huán)通知到每一個(gè)觀察者。類型為有網(wǎng)絡(luò)時(shí)同理盐碱,略把兔。
private void notifyObservers(NetworkType networkType){
if (networkType == NetworkType.NETWORK_NO){
for (NetStateChangeObserver observer : mObservers){
observer.onNetDisconnected();
}
}else {
for (NetStateChangeObserver observer : mObservers){
observer.onNetConnected(networkType);
}
}
}
至此沪伙,觀察者也算是實(shí)現(xiàn)了。
4县好、怎么在activity中使用(試卷一定要填姓名班級)
我們需要讓 activity 實(shí)現(xiàn) NetStateChangeObserver 接口围橡,然后在 onCreate 中注冊廣播接收,在 onDestroy 中注銷接收器缕贡。這樣就能接收到網(wǎng)絡(luò)變化的廣播了翁授。
然后我們在 onResume 中添加觀察者,在 onPause 中移除觀察者晾咪。這樣就是當(dāng)前activity成了一名觀察者收擦。
最后重寫 NetStateChangeObserver 接口中的 onNetDisconnected 和 onNetConnected 方法,做一些你需要的事情谍倦,當(dāng)有廣播時(shí)塞赂,這兩個(gè)方法中對應(yīng)的方法就會(huì)自動(dòng)被調(diào)用。
下面直接放出activity的代碼昼蛀,一看就懂减途,簡單粗暴。
public class MainActivity extends AppCompatActivity implements NetStateChangeObserver {
@Override
public void onNetDisconnected() {
// do sth
}
@Override
public void onNetConnected(NetworkType networkType) {
// do sth
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
NetStateChangeReceiver.registerReceiver(this);
}
@Override
protected void onDestroy() {
NetStateChangeReceiver.unRegisterReceiver(this);
super.onDestroy();
}
@Override
protected void onResume() {
super.onResume( );
NetStateChangeReceiver.registerObserver(this);
}
@Override
protected void onPause() {
super.onPause( );
NetStateChangeReceiver.unRegisterObserver(this);
}
}
5曹洽、完整代碼(檢查交卷鳍置,走人)
(上面講解部分省去了無關(guān)代碼,所以請復(fù)制下面完整的)
工具類完整代碼:
// 已經(jīng)貼在最前面了送淆。
NetStateChangeReceiver 類完整代碼:
public class NetStateChangeReceiver extends BroadcastReceiver{
private NetworkType mType = NetworkUtil.getNetworkType(MyApplication.getContext());
private static class InstanceHolder{
private static final NetStateChangeReceiver INSTANCE = new NetStateChangeReceiver();
}
private List<NetStateChangeObserver> mObservers = new ArrayList<>();
@Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())){
NetworkType networkType = NetworkUtil.getNetworkType(context);
notifyObservers(networkType);
}
}
public static void registerReceiver(Context context){
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver( InstanceHolder.INSTANCE,intentFilter);
}
public static void unRegisterReceiver(Context context){
context.unregisterReceiver( InstanceHolder.INSTANCE);
}
public static void registerObserver(NetStateChangeObserver observer){
if (observer == null) {
return;
}
if (!InstanceHolder.INSTANCE.mObservers.contains(observer)){
InstanceHolder.INSTANCE.mObservers.add(observer);
}
}
public static void unRegisterObserver(NetStateChangeObserver observer){
if (observer == null) {
return;
}
if (InstanceHolder.INSTANCE.mObservers == null) {
return;
}
InstanceHolder.INSTANCE.mObservers.remove(observer);
}
private void notifyObservers(NetworkType networkType){
if (mType == networkType) {
return;
}
mType = networkType;
if (networkType == NetworkType.NETWORK_NO){
for (NetStateChangeObserver observer : mObservers){
observer.onNetDisconnected();
}
}else {
for (NetStateChangeObserver observer : mObservers){
observer.onNetConnected(networkType);
}
}
}
}
NetStateChangeObserver 接口完整代碼:
public interface NetStateChangeObserver {
void onNetDisconnected();
void onNetConnected(NetworkType networkType);
}