前沿:好久没更博客了,手都快生了。不过但凡长时间的积累之后就会有精品,我希望我这一篇文章能帮助各位正在“坑里”的猿猿们。

产品:你给我调研一个手机连上无网WIFI 后能继续使用手机流量的 需求。WIFI不能自动跳转和改变,(WIFI和移动流量必须同时开启)。
程序员:?????纳尼??2333333~

初听到需求,我于是去啪啪啪的搜了一圈,
搜:wifi和移动流量能同时使用么?wifi连接后,能强行使用移动流量么?等等。。。答案也是千奇百怪。有的需要改开发板,有需要用 wireless-tools 方式驱动WIFI ,通过命令启动 WIFI 模块。也有需要使用wpa_supplicant 方式驱动WIFI .可想而知 ,都没有权限,不符合需求。


直到遇见了WIFIP2P,一切问题迎刃而解。


背景

  1. 使用场景以及连接原理简介

    wifip2p是一种点对点,一对多的 角色。通俗点 Android中 称之为WIFI直连,在IOS 中称之为 Airdrop(隔空投送),这种功能很强大,尤其是在智能家居,智能硬件领域。因为蓝牙的传输限制,无法满足更多的需求(比如视频数据的接收)。USB 可以满足这一点不假,但是有距离限制。而且也不是很方便。所以一般我们采用WIFI 连接。这种模式也可以。

  2. 查看WIFI网卡/手机网卡状态
    如果:这时候你既要连接wifi设备,又要需要请求网络处理数据,怎么办。如今的手机我们都知道只要wifi连接,便中断手机移动数据。这一点我也已经确实的验证过。
    运行 —> cmd —> adb shell —> netcfg
    通过查看 rmnet0 (手机网卡) 和 wlan0(WIFI连接)的状态 (DOWN 和 UP)。

  3. wifip2p作用
    这时候wifip2p 的优点就显示出来的。既可以满足通信要求,又可以不影响手机网络。岂不是很nice。通过wifip2p设备可以直接通过WiFi共享文件,图片等(类似蓝牙传输),实现点对点的连接,通信(要求两设备必须位于同一网段)。在Miracast应用场景中,一台支持P2P的智能手机可直接连接上一台支持P2P的智能电视,智能手机随后将自己的屏幕,或者媒体资源传送给电视机去显示或播放。
    显然,借助P2P技术,Wi-Fi设备之间的直接相连将极大拓展Wi-Fi技术的使用场景。

  4. 如何判断自己的设备是否支持wifip2p
    判断设备是否支持WiFi直连是通过
    PackageManager的hasSystemFeature (API)
    ps:
    getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT);


代码实战

官方文档:http://developer.android.com/intl/zh-tw/guide/topics/connectivity/wifip2p.html
官方Demo: http://download.csdn.net/detail/yichigo/5516627

具体步骤
- 设置应用程序权限
- 创建一个广播接收器
- 初始化对等点的搜索
- 检查设备WIFI 是否开启,
- 只有上面的一步打开,才能开始搜索对等点
- 搜索到对等点列表,拿到列表信息
- 建立一个对等点连接

1.首先把需要的权限都配置好

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

2.需要监听WIFIP2P的广播

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.text.TextUtils;
import android.util.Log;import java.util.ArrayList;
import java.util.List;public class DirectBroadcastReceiver extends BroadcastReceiver {private static final String TAG = "DirectBroadcastReceiver";private WifiP2pManager mWifiP2pManager;private WifiP2pManager.Channel mChannel;/**是一个自定义监听 回调接口**/private WifiDirectActionListener mWifiDirectActionListener;public DirectBroadcastReceiver(WifiP2pManager wifiP2pManager, WifiP2pManager.Channel channel, DirectActionListener directActionListener) {mWifiP2pManager = wifiP2pManager;mChannel = channel;mDirectActionListener = directActionListener;}public static IntentFilter getIntentFilter() {IntentFilter intentFilter = new IntentFilter();intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);return intentFilter;}@Overridepublic void onReceive(Context context, Intent intent) {Log.e(TAG, "接收到广播: " + intent.getAction());if (!TextUtils.isEmpty(intent.getAction())) {switch (intent.getAction()) {/**用于指示 Wifi P2P 是否可用**/case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION:int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {mWifiDirectActionListener.wifiP2pEnabled(true);} else {mWifiDirectActionListener.wifiP2pEnabled(false);List<WifiP2pDevice> wifiP2pDeviceList = new ArrayList<>();mWifiDirectActionListener.onPeersAvailable(wifiP2pDeviceList);}break;/**表明可用的对等点的列表发生了改变 **/case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION:mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {@Overridepublic void onPeersAvailable(WifiP2pDeviceList peers) {mWifiDirectActionListener.onPeersAvailable(peers.getDeviceList());}});break;/**表示Wi-Fi对等网络的连接状态发生了改变 **/case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION:NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {@Overridepublic void onConnectionInfoAvailable(WifiP2pInfo info) {if (info != null) {Log.i(TAG, "确实获取到WiFip2pinfo");//!!!这里很关键,只有真正的走到这里,才是真正的建立了P2P连接。拿到了准备建立Socket通道的必要信息。} else {Log.i(TAG, "WiFip2pinfo 为null");}mWifiDirectActionListener.onConnectionInfoAvailable(info);}});Log.i(TAG, "已连接P2P");} else {mWifiDirectActionListener.onDisconnection();Log.i(TAG, "与P2P设备已断开连接");}break;/**表示该设备的配置信息发生了改变**/case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:mWifiDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));break;default:break;}}}}

自定义回调监听

public interface WifiDirectActionListener extends WifiP2pManager.ChannelListener {void wifiP2pEnabled(boolean enabled);void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);void onDisconnection();void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice);void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList);}

3.初始化WIFIP2P的config,并且开始搜索
【!!!在我开发过程,我发现需要真正的搜索到列表,必须多台设备都处于搜索状态,否自不处于搜索的那个设备是不会出现在DeviceList中,可以尝试熄屏,后台状态。】

    private WifiP2pManager mWifiP2pManager;private WifiP2pManager.Channel mChannel;private WifiP2pDevice mWifiP2pDevice;private BroadcastReceiver broadcastReceiver;private boolean mWifiP2pEnabled = false;private List<WifiP2pDevice> mWifiP2pDeviceList;private void initConfig() {mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);broadcastReceiver = new DirectBroadcastReceiver(mWifiP2pManager, mChannel, this);registerReceiver(broadcastReceiver, DirectBroadcastReceiver.getIntentFilter());//如果需要P2P设备列表的话,可以在这里初始化一个集合mWifiP2pDeviceList = new ArrayList<>();}

接着开始搜索列表

   mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {showToast("Success");}@Overridepublic void onFailure(int reasonCode) {showToast("Failure");}});

如果写了Adapter 就可以直接看到列表有多少个 对等点。同样也可以直接在广播中打log

 case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION:?????break;

同时,我们可以获取到当前设备的一些基本信息。在广播

case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:mDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));break;
    @Overridepublic void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice) {Log.i(TAG, "DeviceName: " + wifiP2pDevice.deviceName);Log.i(TAG, "DeviceAddress: " + wifiP2pDevice.deviceAddress);Log.i(TAG, "Status: " + wifiP2pDevice.status);//注意这里的 wifiP2pDevice.status 并不是真正的连接状态,但是如果P2P连接成功,这里的状态一定是 wifiP2pDevice.status ==0 。后面总结会具体讲述}

先贴出一张API参数信息。

4.在接着就是连接P2P
注意:这里很值得说一说。我们调用manager中的connect方法,
①如果连接之前没有创建一个组,系统会自动创建一个组,并且随机分配谁是GroupOwner即谁是组长,
②创建一个组,谁创建谁就是组长。
③这也关系到谁是客户端谁是服务器,

为什么要重点提示谁是组长?因为这里有坑,就是组长只有接受数据的能力,非组长拥有发送数据的能力。并不是谁都可以随便发送和接收,因为Socket 建立需要IP,而WIFIP2P 连接后并不能获取到客户机的IP。只能获取到组长的IP 。也就是 wifiP2pInfo.groupOwnerAddress.getHostAddress()

PS: 一开始我也不知道问题出在那里,后来就查到大家都有这种问题。
https://bbs.csdn.net/topics/390780179/

最近在研究wifi direct
,主要是通过IWIFIP2PManager类来操作,但是我发现,当成功建立连接后,好像从ConnectInfo中(WIFIP2PInfo)中只能获取GroupOwner的IpAddress,并没有API可以提供其他Device的IpAdress。这个会导致上层应用无法获得对端Ip地址,而无法传递数据等。由于在不同的场景下,任何设备都有可能是GroupOwner,而我们除了GroupOwner的Ip
Address外,还希望能获取对端以及Group中所有成员的Ip Address,包括自己的Ip Address.

   private void connect() {WifiP2pConfig config = new WifiP2pConfig();if (config.deviceAddress != null && mWifiP2pDevice != null) {config.deviceAddress = mWifiP2pDevice.deviceAddress;config.wps.setup = WpsInfo.PBC;mWifiP2pManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {Log.e(TAG, "connect onSuccess");}@Overridepublic void onFailure(int reason) {Log.e(TAG, "connect fail");}});}}

主动创建组长

    private void createroup() {mWifiP2pManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {@Overridepublic void onSuccess() {Log.e(TAG, "createGroup onSuccess");showToast("onSuccess");}@Overridepublic void onFailure(int reason) {Log.e(TAG, "createGroup onFailure: " + reason);showToast("onFailure");}});}

同样,断开连接就是 移除组就可以了。

    private void disconnect() {mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {@Overridepublic void onFailure(int reasonCode) {Log.i(TAG, "disconnect onFailure:" + reasonCode);}@Overridepublic void onSuccess() {Log.i(TAG, "disconnect onSuccess");}});}

4.数据连接阶段,非组长(群主)代码
开启异步操作。

  new WifiClientTask(this, fileTransfer).execute(wifiP2pInfo.groupOwnerAddress.getHostAddress());
/**这里的 fileTransfer 就是需要传输的 Object 自定义个Bean 就好 ,重写 Serializable而wifiP2pInfo.groupOwnerAddress.getHostAddress() 就是组IP**/
public class WifiClientTask extends AsyncTask<String, Integer, Boolean> {private ProgressDialog progressDialog;private FileTransfer fileTransfer;private static final int PORT = 4786;private static final String TAG = "WifiClientTask";public WifiClientTask(Context context, FileTransfer fileTransfer) {this.fileTransfer = fileTransfer;progressDialog = new ProgressDialog(context);progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);progressDialog.setCancelable(false);progressDialog.setCanceledOnTouchOutside(false);progressDialog.setTitle("正在发送文件");progressDialog.setMax(100);}@Overrideprotected void onPreExecute() {progressDialog.show();}@Overrideprotected Boolean doInBackground(String... strings) {fileTransfer.setMd5(Md5Util.getMd5(new File(fileTransfer.getFilePath())));Log.i(TAG, "文件的MD5码值是:" + fileTransfer.getMd5());Socket socket = null;OutputStream outputStream = null;ObjectOutputStream objectOutputStream = null;InputStream inputStream = null;try {socket = new Socket();socket.bind(null);Log.i(TAG, "IP:" + strings[0] + "PORT:" + PORT);socket.connect((new InetSocketAddress(strings[0], PORT)), 10000);outputStream = socket.getOutputStream();objectOutputStream = new ObjectOutputStream(outputStream);objectOutputStream.writeObject(fileTransfer);inputStream = new FileInputStream(new File(fileTransfer.getFilePath()));long fileSize = fileTransfer.getFileLength();long total = 0;byte buf[] = new byte[512];int len;while ((len = inputStream.read(buf)) != -1) {outputStream.write(buf, 0, len);total += len;int progress = (int) ((total * 100) / fileSize);publishProgress(progress);Log.i(TAG, "文件发送进度:" + progress);}outputStream.close();objectOutputStream.close();inputStream.close();socket.close();outputStream = null;objectOutputStream = null;inputStream = null;socket = null;Log.i(TAG, "文件发送成功");return true;} catch (Exception e) {Log.i(TAG, "文件发送异常 Exception: " + e.getMessage());} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (objectOutputStream != null) {try {objectOutputStream.close();} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if (socket != null) {try {socket.close();} catch (Exception e) {e.printStackTrace();}}}return false;}@Overrideprotected void onProgressUpdate(Integer... values) {progressDialog.setProgress(values[0]);}@Overrideprotected void onPostExecute(Boolean aBoolean) {progressDialog.cancel();Log.i(TAG, "onPostExecute: " + aBoolean);}}

而Socket.accept 等待方 开启IntentService

public class WifiServerService extends IntentService {private static final String TAG = "WifiServerService";public interface OnProgressChangListener {//当传输进度发生变化时void onProgressChanged(FileTransfer fileTransfer, int progress);//当传输结束时void onTransferFinished(File file);}private ServerSocket serverSocket;private InputStream inputStream;private ObjectInputStream objectInputStream;private FileOutputStream fileOutputStream;private OnProgressChangListener progressChangListener;private static final int PORT = 4786;public class MyBinder extends Binder {public WifiServerService getService() {return WifiServerService.this;}}public WifiServerService() {super("WifiServerService");Log.i(TAG, "WifiServerService");}@Overridepublic void onCreate() {super.onCreate();Log.i(TAG, "onCreate");}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind");return new MyBinder();}@Overrideprotected void onHandleIntent(Intent intent) {Log.i(TAG, "onHandleIntent");clean();File file = null;try {serverSocket = new ServerSocket();serverSocket.setReuseAddress(true);serverSocket.bind(new InetSocketAddress(PORT));Socket client = serverSocket.accept();Log.i(TAG, "客户端IP地址 : " + client.getInetAddress().getHostAddress());inputStream = client.getInputStream();objectInputStream = new ObjectInputStream(inputStream);/**如果你写的是2个程序,尽管FileTransfer一样,但是也要注意包名,其实只要Socket 连接通,客户端IP 拿到,就达到了目标。**/FileTransfer fileTransfer = (FileTransfer) objectInputStream.readObject();Log.i(TAG, "待接收的文件: " + fileTransfer);String name = new File(fileTransfer.getFilePath()).getName();//将文件存储至指定位置file = new File(Environment.getExternalStorageDirectory() + "/" + name);fileOutputStream = new FileOutputStream(file);byte buf[] = new byte[512];int len;long total = 0;int progress;while ((len = inputStream.read(buf)) != -1) {fileOutputStream.write(buf, 0, len);total += len;progress = (int) ((total * 100) / fileTransfer.getFileLength());Log.i(TAG, "文件接收进度: " + progress);if (progressChangListener != null) {progressChangListener.onProgressChanged(fileTransfer, progress);}}serverSocket.close();inputStream.close();objectInputStream.close();fileOutputStream.close();serverSocket = null;inputStream = null;objectInputStream = null;fileOutputStream = null;Log.i(TAG, "文件接收成功,文件的MD5码是:" + Md5Util.getMd5(file));} catch (Exception e) {Log.i(TAG, "文件接收 Exception: " + e.getMessage());} finally {clean();if (progressChangListener != null) {progressChangListener.onTransferFinished(file);}//再次启动服务,等待客户端下次连接startService(new Intent(this, WifiServerService.class));}}@Overridepublic void onDestroy() {super.onDestroy();clean();}public void setProgressChangListener(OnProgressChangListener progressChangListener) {this.progressChangListener = progressChangListener;}private void clean() {if (serverSocket != null) {try {serverSocket.close();serverSocket = null;} catch (IOException e) {e.printStackTrace();}}if (inputStream != null) {try {inputStream.close();inputStream = null;} catch (IOException e) {e.printStackTrace();}}if (objectInputStream != null) {try {objectInputStream.close();objectInputStream = null;} catch (IOException e) {e.printStackTrace();}}if (fileOutputStream != null) {try {fileOutputStream.close();fileOutputStream = null;} catch (IOException e) {e.printStackTrace();}}}}

其实Demo 我也是从githup上拿到的。但是同样我也将我自己遇到的坑总结了一翻,彻底明白了WIFIP2P 。
https://github.com/leavesC/WifiP2P


总结【精华】

  1. WIFIP2P连接成功后,要注意,只有非群主才能向群主发送Socket建立,并能成功发送数据。
    ~~~~~
    原因:当成功建立连接后,从WIFIP2PInfo中只能获取GroupOwner的IpAddress,并没有API可以提供其他Device的IpAdress。这个会导致上层应用无法获得对端Ip地址,而无法传递数据等。由于在不同的场景下,任何设备都有可能是GroupOwner,而我们除了GroupOwner的Ip Address外,还希望能获取对端以及Group中所有成员的Ip Address,包括自己的Ip Address.
  2. WIFIP2P 建连后(connect方法),如果连接之前没有创建一个组,系统会自动创建一个组,并且随机分配谁是GroupOwner即谁是组长,这也关系到谁是客户端谁是服务器.
    ~~~~~
    问题:这有个坑,非常大的几率 他会一直锁定一个Device 为群主,不管是A 连接B ,还是B 连接 A, 还是A 连接C。所以一定要确定 wifiinfo 中
    wifiP2pInfo.groupFormed——–一定要为true ,这样wifiinfo才包含有用信息
    wifiP2pInfo.isGroupOwner——–一定要为false,是非群主,见1.才有可能发送信息。
    ~~~~~
    如何解决:API 也有方法提供
    调用 wifiP2pManager.createGroup(channel, new WifiP2pManager.ActionListener() {},在未连接p2p 之前,在你想要当做服务器的(AP)的机子上提前 createGroup,并在开始连接。就可以结局随机组长的问题。

  3. WifiP2pDevice 的意思是【本机设备信息】,所以千万不要误以为是获取到的是另外一台设备的设备信息。
    其中常用有:
    wifiP2pDevice.deviceName 本设备名字
    wifiP2pDevice.deviceAddress 本设备的MAC地址
    wifiP2pDevice.status 设备连接状态
    ~~~~~
    重点!!! 千万不要以为 wifiP2pDevice.status
    (0是连接 ,1是邀请中,3是未连接,但是可用,4是不可用)
    为0的时候就是连接了,问题在于:p2p连接了,status 一定为0,但是status 为0 ,p2p不一定真正的连接了。这种情况在连接【智能设备】的时候容易出现,我就在此被坑了。真正的wifip2p 连接成功,必须要 在
    WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION
    广播中获得 为true
    intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO).isConnected()
    并且通过
    mWifiP2pManager.requestConnectionInfo(?,?);的回调监听,拿到wifiinfo的实体 ,且不为空。 才算的上你真正的加入p2p组。

  4. 至此,wifip2p 连接问题 的问题点基本已经解决。真正连接后p2p 后就要建立Socket连接。一般是没有问题的,有问题也只有2点

    1.)文件路径没有获取到,我们通过intent 获取到的 一般是 Uri
    content://com.android.providers.media.documents/document/image%3A63
    而我们想要的是文件绝对路径
    /data/hw_init/version/region_comm/china/media/Pre-loaded/Pictures/01-04.jpg
    这样才能 通过 File file = new File(path); 文件。
    所以注意这一点路径转换过程 是否为空
    ~~
    2.)socket 服务器等待方 serverSocket.accept();
    其实也只是 要保证是否在等待。
    楼主使用的是Githup的Demo ,其中serverSocket.accept(); 是在intentservice 的
    onHandleIntent 中开启的,这个intentservice 的 开启有2种方式,startService 和
    bindService 一般我们喜欢使用bindService ,毕竟数据接收后需要处理,通知UI 线程。
    但是bingService 的生命周期 是不走 onHandleIntent. 而 startService 是走的。具体看我另外一篇博客对Service 和IntentService 的 解释。(下面是链接)
    https://blog.csdn.net/qq_31332467/article/details/82430638

  5. 在开发过程中发现,WIFIP2P连接,必须双向设备都处于discoverPeers状态中,如果一方不在该状态中,则另一方根本拿不到设备列表,拿不到就谈不了最基本的连接

后记

因为我连接的硬件是车机,车机开发板中有很多问题,可能对Android开发板做了修改,我这边就遇到2个问题:

1.一个车机是有WIFI ,但是却没有直连模块,问了供货商,他们说没改过。可是开了广播后,无论如何都拿不到广播,根本连onReceive 都没走。那就什么都不用谈了,列表都拿不到,还说什么。
2.换了一台车机(另一个供货商的),这个就很顺利的拿到了列表。果然供应商都是。。。。但是这个更坑,让我白高兴了一场。

顺利拿到了列表,也顺利连接上了,只是mWifiP2pManager.connect()中回调成功。我以为连接OK,就开始Socket建连,可无论如何都是提示 Connection refusal!
我怎么就不明白,难道开发商的车机觉得我的客户端IP 非法,给我拒绝了?
一直就认为是套接字的问题。后来才发现,其实根本就没连接上,关键在广播中的

 case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION:NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {@Overridepublic void onConnectionInfoAvailable(WifiP2pInfo info) {if (info != null) {/**!!!!只有真正的走到这里才是真正连接!!!!**/} else {Log.i(TAG, "WiFip2pinfo 为null");}mDirectActionListener.onConnectionInfoAvailable(info);}});Log.i(TAG, "已连接P2P");} else {mDirectActionListener.onDisconnection();Log.i(TAG, "与P2P设备已断开连接");}break;

然后在赋值WifiP2pInfo 的时候,更要注意:

 @Overridepublic void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) {  Log.i(TAG, "onConnectionInfoAvailable groupFormed: " + wifiP2pInfo.groupFormed);Log.i(TAG, "onConnectionInfoAvailable isGroupOwner: " + wifiP2pInfo.isGroupOwner);Log.i(TAG, "onConnectionInfoAvailable getHostAddress: " + wifiP2pInfo.groupOwnerAddress.getHostAddress());/**必须if条件成立才可以开启 AsyncTask**/if (wifiP2pInfo.groupFormed && !wifiP2pInfo.isGroupOwner) {Log.e(TAG, "F-Z-C-G");this.wifiP2pInfo = wifiP2pInfo;}}

本章完结

WifiDirect (WIFIP2P) 最全最详细,应用于智能硬件(智能家居,车机,无人机)等。相关推荐

  1. 【运筹学】线性规划 单纯形法 阶段总结 ( 初始基可行解 | 判定最优解 | 迭代 | 得到最优解 | 全流程详细解析 ) ★

    文章目录 一.线性规划示例 二.转化标准形式 三.查找初始基可行解 四.初始基可行解的最优解判定 五.第一次迭代 : 入基与出基变量选择 六.第一次迭代 : 方程组同解变换 七.第一次迭代 : 生成新 ...

  2. php获取js函数返回的值_最全最详细的PHP面试题(带有答案)

    这篇文章介绍的内容是关于最全最详细的PHP面试题(带有答案),有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 相关推荐: 八重樱:分享一波腾讯PHP面试题 八重樱:2019年PHP最新面 ...

  3. 超全超详细的HTTP状态码大全

    超全超详细的HTTP状态码大全 本部分余下的内容会详细地介绍 HTTP 1.1中的状态码.这些状态码被分为五大类: 100-199 用于指定客户端应相应的某些动作. 200-299 用于表示请求成功. ...

  4. 计算机工程博士参军,Gatech计算机工程博士专业排名最全信息详细分析

    原标题:Gatech计算机工程博士专业排名最全信息详细分析 佐治亚理工学院 简称 Georgia Tech,1885 年创校,是美国杰出的理工学院,排名仅次于麻省理工学院 和 加州理工学院.学院在校学 ...

  5. 世界各地 史上最全最详细无线通信频率分配表(内容含概wifi、2.4G、5G,绝对值得收藏)

    1.目前主流的无线WIFI网络设备802.11a/b/g/n/ac: 传统 802.11 1997年发布 两个原始数据率:1Mbps 和 2Mbps 跳频展频 (FHSS)或直接序列展布频谱(DSSS ...

  6. Java实现根据Word模板填充表格数据(poi方式),以及doc和docx转PDF,最全最详细版本,解决外部引用jar在linux上报ClassNotFound的问题。

    Java实现根据Word模板填充表格数据(poi方式),以及doc和docx转PDF,最全最详细版本,解决外部引用jar在linux上报ClassNotFound的问题. 适用场景: 1.固定格式的W ...

  7. 史上最全最详细多种手机主流操作系统详解

    史上最全最详细多种主流操作系统详解(经典,值得收藏) 2017-06-09 18:07 操作系统 一.手机操作系统 1 Android 谷歌安卓 这里写图片描述(https://img-blog.cs ...

  8. 最全最详细数据结构与算法视频-【附课件和源码】

    源码和课件下载方式在文末 什么是数据结构与算法 算法用来设计并实现一种用计算机来解决问题的方法.它满足下列性质: 输入:有零个或多个输入量 输出:产生至少一个输出量 确定性:算法的指令清晰.无歧义 有 ...

  9. linux命令行开头是sh,shell脚本语言的使用(超全超详细)

    1.shell的概述 shell 是一种脚本语言 脚本:本质是一个文件,文件里面存放的是 特定格式的指令,系统可以使用脚本解析器 翻译或解析 指令 并执行(它不需要编译) shell 既是应用程序 又 ...

最新文章

  1. 博客社会学图——使用python检索网页上的友情链接
  2. dotnet core调试docker下生成的dump文件
  3. Java——集合(Map集合的两种迭代)
  4. Chrome 开发工具指南——通过工作空间保存更改
  5. AI实战 | Tensorflow自定义数据集和迁移学习(附代码下载)
  6. ubuntu安装minisat_minisat 安装指南
  7. PostgreSQL学习手册(十一) 数据库管理
  8. java写入文件不覆盖写入_Java写入文件–用Java写入文件的4种方法
  9. 性能测试的那些事儿!
  10. [Linux]-Shell编程与规范
  11. jQuery Form Plugin (二) :使用AJAX提交Form表单
  12. 第一章 UCI数据集wine.data主成分分析PCA
  13. 未来教育计算机书,未来教育计算机二级
  14. 1026-压力传感器分类及原理集锦
  15. 4g网络什么时候淘汰_4g网络手机。什么时候淘汰
  16. Ubuntu20.04连接校园网WiFi
  17. 例题5-10 UVA 207 PGA Tour Prize Money PGA巡回赛的奖金
  18. java nanotime 转秒_[Java] System.nanoTime()返回结果nanoSeconds和seconds之间的转换
  19. linux中要怎么创建文件夹
  20. Java实现ES增删改查

热门文章

  1. 函授计算机网络工程,通信工程函授本科《计算机网络》试卷(A)答案0519.doc
  2. centos安装Redis详细教程
  3. 8强诞生!香港科大商学院-黑瞳科技2020【人工智能】百万奖金国际创业大赛第二轮评审圆满完成...
  4. rgb转hsv java_RGB图像转换成HSV图像
  5. 二八原理:你必须知悉的二八原理
  6. 乐优商城(填坑)——秒杀商品添加
  7. Java小游戏之捕鱼达人001.JavaGUI
  8. Casting out Primes: Bignum Arithmetic for Zero-Knowledge Proofs学习笔记
  9. 港科夜闻|香港科大研究团队突破性发现罕见肿瘤细胞「间谍」,揭示不为人知的癌细胞...
  10. TensorFlow中出现Incompatible shapes between op input and calculated input gradient