Android网络连接状态改变的事件

61

我正在制作一个应用程序,用户会频繁地通过专门的上传服务上传信息和文件到我的服务器。这是通过新线程完成的。

我从这个帖子中了解到:

检测Android上是否有可用的互联网连接

可以相对容易地检查是否有互联网连接。您也可以获取SocketTimeoutExceptions以检测Internet连接问题。所有这些都很好,让我可以轻松地在连接由于某种原因而无法工作时缓存我的上传。

但我的问题是,我如何知道何时重新尝试上传?当网络连接恢复时是否会触发事件?还是我必须创建一个休眠线程,然后每30秒检查一次互联网连接状态?

任何想法都将不胜感激!

4个回答

126

非常久远的帖子,但我想分享我的接收器。

不需要触及清单或其他无聊的资源:)

使用方法

你的活动:

/*
 * You need to implement NetworkStateReceiverListener.
 * This interface is described inside the NewtworkStateReceiver class
 */
public class MyActivity implements NetworkStateReceiverListener {
    /* ... */
    private NetworkStateReceiver networkStateReceiver;
}

在您的活动中:实例化接收器

public void onCreate(Bundle savedInstanceState) {
    /* ... */
    networkStateReceiver = new NetworkStateReceiver();
    networkStateReceiver.addListener(this);
    this.registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
}

public void onDestroy() {
    super.onDestroy();
    networkStateReceiver.removeListener(this);
    this.unregisterReceiver(networkStateReceiver);
}

在您的活动中:实现必需的方法

@Override
public void networkAvailable() {
    Log.d("tommydevall", "I'm in, baby!");
    /* TODO: Your connection-oriented stuff here */
}

@Override
public void networkUnavailable() {
    Log.d("tommydevall", "I'm dancing with myself");
    /* TODO: Your disconnection-oriented stuff here */        
}

接收器

只需将其复制并粘贴到您的项目中作为NetworkStateReceiver.java

public class NetworkStateReceiver extends BroadcastReceiver {

    protected Set<NetworkStateReceiverListener> listeners;
    protected Boolean connected;

    public NetworkStateReceiver() {
        listeners = new HashSet<NetworkStateReceiverListener>();
        connected = null;
    }

    public void onReceive(Context context, Intent intent) {
        if(intent == null || intent.getExtras() == null)
            return;

        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = manager.getActiveNetworkInfo();

        if(ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
            connected = true;
        } else if(intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,Boolean.FALSE)) {
            connected = false;
        }

        notifyStateToAll();
    }

    private void notifyStateToAll() {
        for(NetworkStateReceiverListener listener : listeners)
            notifyState(listener);
    }

    private void notifyState(NetworkStateReceiverListener listener) {
        if(connected == null || listener == null)
            return;

        if(connected == true)
            listener.networkAvailable();
        else
            listener.networkUnavailable();
    }

    public void addListener(NetworkStateReceiverListener l) {
        listeners.add(l);
        notifyState(l);
    }

    public void removeListener(NetworkStateReceiverListener l) {
        listeners.remove(l);
    }

    public interface NetworkStateReceiverListener {
        public void networkAvailable();
        public void networkUnavailable();
    }
}

享受;)


搞定了。这与Android 5不识别ConnectivityManager.EXTRA_NO_CONNECTIVITY有关 - https://dev59.com/qF0b5IYBdhLWcg3wCtXY - Simon
7
在Activity的onDestroy()方法中,你也应该调用unregisterReceiver(networkStateReceiver);来取消注册广播接收器吗? - ban-geoengineering
4
请勿忘将相应的权限添加到清单文件中: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - Ayaz Alifov
2
你从未注销接收器,这会保留对活动的硬引用。在透视图中存在很多泄漏。 - njzk2
1
这似乎在我的情况下不起作用。很抱歉。:( - Neon Warge
显示剩余3条评论

30

如果你只是想在连接状态发生变化时做一些简单的事情,那么有一个更简单的解决方案。

在你的活动中,创建一个广播接收器:

private BroadcastReceiver networkStateReceiver=new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = manager.getActiveNetworkInfo();
        doSomethingOnNetworkChange(ni);
    }
};

然后在 onResumeonPause 中进行注册:

@Override
public void onResume() {
    super.onResume();
    registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
}

@Override
public void onPause() {
    unregisterReceiver(networkStateReceiver);
    super.onPause();
}

1
谢谢。您能否请解释一下您的解决方案与在清单中注册的广播接收器使用之间的区别? - JCarlosR
3
如果在清单文件中声明了它,那么每次连接状态改变时,它都会在整个应用程序范围内触发。 如果使用在这里看到的在活动中定义的接收器,它只会在你的活动运行时触发。 - Xmister
从最好的答案来看,这里有些人不知道接收器在性能方面的代价很高。 - Zhar

14

我不太确定Tommaso的广播接收器在做什么,但对我来说它不起作用,这是我的实现。它只在可用/不可用连接之间的更改时通知。

此外,我在onResume()中注册它,在onPause()中取消注册。否则,它与上面的相同。

public class NetworkStateReceiver extends BroadcastReceiver {

    private ConnectivityManager mManager;
    private List<NetworkStateReceiverListener> mListeners;
    private boolean mConnected;

    public NetworkStateReceiver(Context context) {
        mListeners = new ArrayList<NetworkStateReceiverListener>();
        mManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        checkStateChanged();
    }

    public void onReceive(Context context, Intent intent) {
        if (intent == null || intent.getExtras() == null)
            return;

        if (checkStateChanged()) notifyStateToAll();
    }

    private boolean checkStateChanged() {
        boolean prev = mConnected;
        NetworkInfo activeNetwork = mManager.getActiveNetworkInfo();
        mConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
        return prev != mConnected;
    }

    private void notifyStateToAll() {
        for (NetworkStateReceiverListener listener : mListeners) {
            notifyState(listener);
        }
    }

    private void notifyState(NetworkStateReceiverListener listener) {
        if (listener != null) {
            if (mConnected) listener.onNetworkAvailable();
            else listener.onNetworkUnavailable();
        }
    }

    public void addListener(NetworkStateReceiverListener l) {
        mListeners.add(l);
        notifyState(l);
    }

    public void removeListener(NetworkStateReceiverListener l) {
        mListeners.remove(l);
    }

    public interface NetworkStateReceiverListener {
        public void onNetworkAvailable();

        public void onNetworkUnavailable();
    }
}

恕我直言,我尝试了您的解决方案,但发现Tommaso的效果更好。 - JDOaktown
2
它如何更好地工作?只是好奇在尝试这些解决方案之前。 - Nicolas

11

Android Nougat & O (API 24+) - 网络状态

对@darnmason答案(构造函数)做了更改以在API 24+上运行。

public NetworkStateReceiver(Context context) {
    mListeners =  new ArrayList<>();
    mManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    context.registerReceiver(NetworkStateReceiver.this, intentFilter);

    checkStateChanged();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接