1.WiFi 直连中收到 WIFI_P2P_STATE_CHANGED_ACTION 广播时,更改直连状态,根据状态不同执行相应操作。如果 WiFi 未开启,要跳到设置界面去设置,本来想如果设置返回还要判断执行,所以放到 onResum 方法里执行,但这样有问题,这个界面还可能跳到其它界面,状态可能没改变,而且 onResume 比广播接收者要调用的方法执行的更早,所以 onResume 里用到的 isWifiP2pEnabled 并不是最新的。所以后来放在更改状态之后执行,这样只要更改状态就执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public void setIsWifiP2pEnabled( boolean isWifiP2pEnabled) { this .isWifiP2pEnabled = isWifiP2pEnabled; // 状态变化了,调用这个方法 testAndDiscover(); } // 看WiFi功能是否开启,若开启,去发现设备 private void testAndDiscover() { if (!isWifiP2pEnabled) { AlertDialog.Builder builder = new Builder( this ); builder.setTitle( "提示" ) .setMessage( "请先确认您的设备支持WiFi直连功能。如果支持,请先在设置中开启WiFi" ) .setPositiveButton( "去设置" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startActivity( new Intent(Settings.ACTION_WIRELESS_SETTINGS)); } }) .setNegativeButton( "不弄了" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }).show(); } else { // 如果wifi直连功能支持并已开启 WifiDirectUtil.discoverPeers(DeviceListActivity. this , manager, channel); } } |
2.广播接收者里收到的 WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 这个广播是更新自己的状态
1
2
3
4
5
|
if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { // 更新自己的设备状态 activity.updateThisDevice((WifiP2pDevice) intent .getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)); } |
1
2
3
4
5
6
|
public void updateThisDevice(WifiP2pDevice device) { TextView myName = (TextView) findViewById(R.id.my_name); TextView myStatus = (TextView) findViewById(R.id.my_status); myName.setText(device.deviceName); myStatus.setText(Util.getDeviceStatus(device.status)); } |
其中 device.status 是int型值,所以要转变为对应文字,这样看着有意义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public static String getDeviceStatus( int deviceStatus) { switch (deviceStatus) { case WifiP2pDevice.AVAILABLE: return "Available" ; case WifiP2pDevice.INVITED: return "Invited" ; case WifiP2pDevice.CONNECTED: return "Connected" ; case WifiP2pDevice.FAILED: return "Failed" ; case WifiP2pDevice.UNAVAILABLE: return "Unavailable" ; default : return "Unknown" ; } } |
3.原来 discoverPeers,requestPeers 之类的方法都是放在Activity里,但如果作为一个库供其它程序调用的话要把这些方法提取出来放到一个工具类里。比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/** * 去发现设备 * @param context * @param manager * @param channel */ public static void discoverPeers( final Context context, WifiP2pManager manager, Channel channel) { Log.i(TAG, "discoverPeers" ); manager.discoverPeers(channel, new ActionListener() { @Override public void onSuccess() { // 成功后,会收到对应广播 } @Override public void onFailure( int reason) { Toast.makeText(context, "搜索设备失败,错误代码:" + reason, Toast.LENGTH_SHORT).show(); } }); } /** * 更新自己这台设备的状态 * @param activity * @param device */ public static void updateThisDevice(Activity activity, WifiP2pDevice device) { Log.i(TAG, "updateThisDevice" ); TextView myName = (TextView) activity.findViewById(R.id.my_name); TextView myStatus = (TextView) activity.findViewById(R.id.my_status); myName.setText(device.deviceName); myStatus.setText(getDeviceStatus(device.status)); } |
1
2
3
4
5
6
7
8
9
10
11
|
@Override public void onPeersAvailable(WifiP2pDeviceList peerList) { // peers 就是适配器中用到的那个设备列表集合 peers.clear(); peers.addAll(peerList.getDeviceList()); notifyDataSetChanged(); // 刷新适配器 if (peers.size() == 0 ) { return ; } } |
但现在将 PeerListListener 和适配器分离,所以考虑得到最新的列表后去通过方法调用去更改适配器中内容,然后再刷新,所以要在适配器类中添加一个方法,去设置它自己的那个 List 集合,但用户开始不知道一定要有这方法,所以写一个接口
1
2
3
4
5
6
7
8
|
public interface BaseDeviceAdapter { /** * 更新适配器中的设备列表那个List集合。并刷新适配器内容 * @param peers */ public void updateDeviceList(List<WifiP2pDevice> peers); } |
这样自己写的 DeviceAdapter 实现接口,重写这个方法
1
2
3
4
5
6
|
// 更新peers并刷新适配器 @Override public void updateDeviceList(List<WifiP2pDevice> peers) { this .peers = peers; notifyDataSetChanged(); } |
在工具类里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/** * 查找设备 * @param manager * @param channel * @param adapter 要更新内容的适配器,类型是自己定义的那个接口 */ public static void requestPeers(WifiP2pManager manager, Channel channel, final BaseDeviceAdapter adapter) { Log.i(TAG, "requestPeers" ); manager.requestPeers(channel, new PeerListListener() { @Override public void onPeersAvailable(WifiP2pDeviceList peerList) { List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>(); peers.clear(); peers.addAll(peerList.getDeviceList()); // 更新适配器中内容。利用参数传递的那个接口调用 adapter.updateDeviceList(peers); if (peers.size() == 0 ) { return ; } } }); } |
4.连接一台设备,知道的是WifiP2pDevice,WifiP2pManager 真正去 connect 需要的 WifiP2pConfig 信息通过 WifiP2pDevice 来设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public static void connect( final Context context, WifiP2pManager manager, Channel channel, WifiP2pDevice device) { WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; config.wps.setup = WpsInfo.PBC; manager.connect(channel, config, new ActionListener() { @Override public void onSuccess() { // WiFiDirectBroadcastReceiver will notify us. Ignore for now. } @Override public void onFailure( int reason) { Toast.makeText(context, "连接失败,请重试" , Toast.LENGTH_SHORT).show(); } }); } |
5.广播接收者收到这个广播 WIFI_P2P_CONNECTION_CHANGED_ACTION 表示连接状态改变了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
if (manager == null ) { return ; } NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (networkInfo.isConnected()) { // 成功连接上 Log.i(TAG, "收到广播:连接成功" ); WifiDirectUtil.requestConnectionInfo(manager, channel); } else { // 不管哪一方主动断开连接,这里都会收到广播,在这里去重置数据 // 比如清空一些数据,或者重新 discoverPeers 显示到界面上 activity.resetData(); } // 在Activity中,如果直连断了,重新查找设备 public void resetData() { WifiDirectUtil.discoverPeers(DeviceListActivity. this , manager, channel); } |
1
2
3
4
|
public void clearPeers() { peers.clear(); notifyDataSetChanged(); } |
在 onDestory 中断开连接,如果原来是连接的,断开成功,如果原来就是断开的,断开失败,反正没影响。