用户登录
用户注册

分享至

Android即时网络监听(注解实现)

  • 作者: 你倦了对么
  • 来源: 51数据库
  • 2021-07-28

在Android开发中,免不了和网络打交道,而网络监听是必不可少的,本文采用动态注册广播和注解实现即时网络监听。

最终实现的效果:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        NetworkManager.getDefault().register(this);
    }

    @Network
    public void network(NetType type) {
        switch (type) {
            case AUTO:
                Toast.makeText(this, "当前网络已连接", Toast.LENGTH_LONG).show();
                break;
            case WIFI:
                Toast.makeText(this, "当前为WIFI网络", Toast.LENGTH_LONG).show();
                break;
            case MOBILE:
                Toast.makeText(this, "当前为移动数据网络", Toast.LENGTH_LONG).show();
                break;
            case UNKNOWN:
                Toast.makeText(this, "当前无网络连接", Toast.LENGTH_LONG).show();
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        NetworkManager.getDefault().unregister(this);
    }

开始之前,先添加必要的权限。

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

1、自定义注解@Network,该注解作用于公有方法上,注解参数为枚举NetType。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Network {

    NetType netType() default NetType.AUTO;
}

枚举类:

public enum NetType {
    AUTO,        //有网络
    WIFI,        //WiFi网络
    MOBILE,      //移动网络
    UNKNOWN,     //没有网络
}

2、定义一个java bean类,该类代表了Activity或者Fragment。因为只有页面才可以监听网络状态,其他类监听是无意义的。用来管理标识了@Network注解方法的信息,包括参数类型、网络类型、以及需要执行的方法。

public class MethodManager {

    //参数类型
    private Class<?> type;
    //网络类型
    private NetType mNetType;
    //需要执行的方法
    private Method mMethod;

    public MethodManager(Class<?> type, NetType netType, Method method) {
        this.type = type;
        mNetType = netType;
        mMethod = method;
    }

    public Class<?> getType() {
        return type;
    }

    public void setType(Class<?> type) {
        this.type = type;
    }

    public NetType getNetType() {
        return mNetType;
    }

    public void setNetType(NetType netType) {
        mNetType = netType;
    }

    public Method getMethod() {
        return mMethod;
    }

    public void setMethod(Method method) {
        mMethod = method;
    }
}

3、定义NetworkManager唯一接口类,用于页面注册网络监听和取消监听,广播注册采用动态注册(静态注册会失效),为此需要设计成单例,供外部使用。

public class NetworkManager {

    private static volatile NetworkManager instance;
    private NetStateReceiver mReceiver;
    private Application mApplication;

    private NetworkManager() {
        mReceiver = new NetStateReceiver();
    }

    public static NetworkManager getDefault() {
        if (instance == null) {
            synchronized (NetworkManager.class) {
                if (instance == null) {
                    instance = new NetworkManager();
                }
            }
        }
        return instance;
    }

    public Application getApplication() {
        return mApplication;
    }

    //初始化
    public void init(Application application) {
        this.mApplication = application;
    }

    //注册
    public void register(Object register) {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Constant.ANDROID_NET_CHANGE_ACTION);
        mApplication.registerReceiver(mReceiver, filter);
        mReceiver.register(register);
    }

    //注销
    public void unregister(Object register) {
        mReceiver.unregister(register);
    }
}

4、定义广播接受者NetStateReceiver,用于接收网络状态改变的广播,由于用到了反射,需要java反射基础知识。在注册监听的时候,用一个HashMap来保存注册了该广播的Activity或者Fragment实例。键key为Activity或者Fragment,value为标识了@Network注解的所有公有方法。在反射执行的时候,需要判断方法参数类型有且只能有一个,并且类型为NetType枚举类型。当页面关闭或者其他不需要监听的时候,就需要将注入的实例释放和注销广播。详细代码如下:

public class NetStateReceiver extends BroadcastReceiver {

    private NetType netType;

    private HashMap<Object, List<MethodManager>> networkList;

    public NetStateReceiver() {
        netType = NetType.UNKNOWN;
        networkList = new HashMap<>();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent == null || intent.getAction() == null) {
            return;
        }
        if (intent.getAction().equalsIgnoreCase(Constant.ANDROID_NET_CHANGE_ACTION)) {
            netType = NetworkUtils.getNetWorkType();
            //通知分发消息
            post(netType);
        }
    }

    private void post(NetType netType) {
        Set<Object> sets = networkList.keySet();
        for (Object set : sets) {
            List<MethodManager> methodList = networkList.get(set);
            if (methodList != null) {
                for (MethodManager methodManager : methodList) {
                    //方法参数类型校验
                    if (methodManager.getType().isAssignableFrom(netType.getClass())) {
                        switch (methodManager.getNetType()) {
                            case AUTO:
                                invoke(methodManager, set, netType);
                                break;
                            case WIFI:
                                if (netType == NetType.WIFI || netType == NetType.UNKNOWN) {
                                    invoke(methodManager, set, netType);
                                }
                                break;
                            case MOBILE:
                                if (netType == NetType.MOBILE || netType == NetType.UNKNOWN) {
                                    invoke(methodManager, set, netType);
                                }
                                break;
                            case UNKNOWN:
                                if (netType == NetType.UNKNOWN) {
                                    invoke(methodManager, set, netType);
                                }
                                break;
                        }
                    }
                }
            }
        }
    }

    private void invoke(MethodManager methodManager, Object object, NetType type) {
        try {
            methodManager.getMethod().invoke(object, type);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //注册监听 ==  key:Activity、Fragment,value: 方法集合
    public void register(Object register) {
        List<MethodManager> methodList = findAnnotationMethod(register);
        networkList.put(register, methodList);
    }

    private List<MethodManager> findAnnotationMethod(Object register) {
        List<MethodManager> methodList = new ArrayList<>();
        Class<?> clazz = register.getClass();
        //获取当前类中所有公有方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            //获取方法上的注解
            Network network = method.getAnnotation(Network.class);
            if (network == null)
                continue;
            //方法参数校验 ==> 参数只能有一个
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != 1) {
                throw new RuntimeException(method.getName() + "parameter can only have one");
            }
            MethodManager methodManager = new MethodManager(parameterTypes[0], network.netType(), method);
            methodList.add(methodManager);
        }
        return methodList;
    }

    public void unregister(Object register) {
        if (networkList != null) {
            NetworkManager.getDefault().getApplication().unregisterReceiver(this);
            networkList.remove(register);
            networkList.clear();
        }
    }
}

最后附上两个工具类:

public class Constant {

    public static final String ANDROID_NET_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
}
public class NetworkUtils {

    /**
     * 判断网络是否可用
     */
    public static boolean isNetworkAvailable() {
        ConnectivityManager manager = (ConnectivityManager) NetworkManager.getDefault().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager == null) {
            return false;
        } else {
            NetworkInfo networkInfo = manager.getActiveNetworkInfo();
            if (networkInfo != null)
                return networkInfo.isAvailable();
        }
        return false;
    }

    /**
     * 获取网络类型
     */
    public static NetType getNetWorkType() {
        ConnectivityManager manager = (ConnectivityManager) NetworkManager.getDefault().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager != null) {
            NetworkInfo networkInfo = manager.getActiveNetworkInfo();
            if (networkInfo != null) {
                switch (networkInfo.getType()) {
                    case ConnectivityManager.TYPE_MOBILE:
                        return NetType.MOBILE;
                    case ConnectivityManager.TYPE_WIFI:
                        return NetType.WIFI;
                }
                if (!networkInfo.isConnected()) {
                    return NetType.UNKNOWN;
                }
            }
        }
        return NetType.UNKNOWN;
    }
}

至此本文结束。

软件
前端设计
程序设计
Java相关