Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android官方開發文檔Training系列課程中文版:連接無線設備之通過WIFI創建P2P連接

Android官方開發文檔Training系列課程中文版:連接無線設備之通過WIFI創建P2P連接

編輯:關於Android編程

原文地址:http://android.xsoftlab.net/training/connect-devices-wirelessly/wifi-direct.html

Wi-Fi peer-to-peer (P2P) APIs可以使程序與附近的設備進行直接通訊,Android的Wi-Fi P2P框架由Wi-Fi Direct?提供技術支持。WI-FI P2P技術可以使程序快速的檢索附近的設備並與之建立連接。其覆蓋范圍超過藍牙的覆蓋范圍。

這節課會學習如何通過WI-FI P2P技術搜索附近的設備並與之建立連接。

設置應用權限

如果要使用WI-FI P2P技術,需要在程序的清單文件中添加CHANGE\_WIFI\_STATE, ACCESS\_WIFI\_STATE, INTERNET三項權限。Wi-Fi P2P並不需要互聯網連接,但是它需要使用標准的Java Socket通訊技術,所以需要使用INTERNET權限:


    
    
    ...

設置廣播接收器及P2P管理員

使用WI-FI P2P技術,需要監聽廣播意圖,廣播意圖會通知程序某些事件的發生。所以在程序中需要添加IntentFilter,並設置其監聽以下行為:

WIFI\_P2P\_STATE\_CHANGED\_ACTION

監聽Wi-Fi P2P是否可用

WIFI\_P2P\_PEERS\_CHANGED\_ACTION

監聽WI-FI P2P列表的變化

WIFI\_P2P\_CONNECTION\_CHANGED\_ACTION

監聽Wi-Fi P2P的連接狀態

WIFI\_P2P\_THIS\_DEVICE\_CHANGED\_ACTION

監聽設備的配置變化
private final IntentFilter intentFilter = new IntentFilter();
...
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //  Indicates a change in the Wi-Fi P2P status.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
    // Indicates a change in the list of available peers.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
    // Indicates the state of Wi-Fi P2P connectivity has changed.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
    // Indicates this device's details have changed.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
    ...
}

在onCreate()方法的末尾,需要獲取WifiP2pManager的實例,然後調用它的initialize()方法。這個方法會返回一個WifiP2pManager.Channel的對象,它用於使程序應用層與Wi-Fi P2P框架建立連接。

@Override
Channel mChannel;
public void onCreate(Bundle savedInstanceState) {
    ....
    mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mManager.initialize(this, getMainLooper(), null);
}

接下來創建一個新的BroadcastReceiver類,它用於監聽系統的Wi-Fi P2P的狀態變化,在onReceive()方法中,需要添加一些基本的判斷條件來處理每種P2P的狀態並處理:

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
            // Determine if Wifi P2P mode is enabled or not, alert
            // the Activity.
            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                activity.setIsWifiP2pEnabled(true);
            } else {
                activity.setIsWifiP2pEnabled(false);
            }
        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
            // The peer list has changed!  We should probably do something about
            // that.
        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            // Connection state changed!  We should probably do something about
            // that.
        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
            DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
                    .findFragmentById(R.id.frag_list);
            fragment.updateThisDevice((http://blog.csdn.net/sahadev_/article/details/WifiP2pDevice) intent.getParcelableExtra(
                    WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
        }
    }

最後,將廣播接收器與意圖過濾器添加到上下文中,並需要在Activity暫停的時候注銷這個廣播接收器。放置這些代碼的最佳位置就是onResume()方法與onPause()方法。

    /** register the BroadcastReceiver with the intent values to be matched */
    @Override
    public void onResume() {
        super.onResume();
        receiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
        registerReceiver(receiver, intentFilter);
    }
    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

初始化端點搜索

如果開始要使用Wi-Fi P2P來搜索附近的設備,需要調用discoverPeers()方法。這個方法要求傳入以下參數:

在初始化P2P管理員時獲得的WifiP2pManager.Channel對象。 WifiP2pManager.ActionListener的實現,它用於監聽搜索的成功與否。
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
        @Override
        public void onSuccess() {
            // Code for when the discovery initiation is successful goes here.
            // No services have actually been discovered yet, so this method
            // can often be left blank.  Code for peer discovery goes in the
            // onReceive method, detailed below.
        }
        @Override
        public void onFailure(int reasonCode) {
            // Code for when the discovery initiation fails goes here.
            // Alert the user that something went wrong.
        }
});

要記住,這裡只是初始化了端點搜索。discoverPeers()方法啟動搜索進程後會立即返回。如果端點搜索進程成功初始化,那麼系統會自動調用初始化時設置的回調方法。另外,端點搜索功能會一直保持在活動狀態,直到連接初始化完成或者P2P組建立連接。

獲取端點列表

接下來需要獲得並處理端點列表。首先需要實現WifiP2pManager.PeerListListener接口,它提供了WI-FI P2P所搜索到的端點信息。下面的代碼演示了這個過程:

    private List peers = new ArrayList();
    ...
    private PeerListListener peerListListener = new PeerListListener() {
        @Override
        public void onPeersAvailable(http://blog.csdn.net/sahadev_/article/details/WifiP2pDeviceList peerList) {
            // Out with the old, in with the new.
            peers.clear();
            peers.addAll(peerList.getDeviceList());
            // If an AdapterView is backed by this data, notify it
            // of the change.  For instance, if you have a ListView of available
            // peers, trigger an update.
            ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
            if (peers.size() == 0) {
                Log.d(WiFiDirectActivity.TAG, "No devices found");
                return;
            }
        }
    }

現在需要修改廣播接收器的onReceive()方法,在收到WIFI\_P2P\_STATE\_CHANGED\_ACTION行為時調用requestPeers()方法。在這之前需要將監聽器的實例傳入到廣播接收器中,常規的方式是在廣播接收器的構造方法中將這個監聽器傳進來。、

public void onReceive(Context context, Intent intent) {
    ...
    else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
        // Request available peers from the wifi p2p manager. This is an
        // asynchronous call and the calling activity is notified with a
        // callback on PeerListListener.onPeersAvailable()
        if (mManager != null) {
            mManager.requestPeers(mChannel, peerListListener);
        }
        Log.d(WiFiDirectActivity.TAG, "P2P peers changed");
    }...
}

現在,WIFI\_P2P\_STATE\_CHANGED\_ACTION的行為將會觸發端點列表的更新。

連接到端點

為了可以連接到端點,需要創建一個新的WifiP2pConfig對象,然後將http://blog.csdn.net/sahadev_/article/details/WifiP2pDevice中的數據拷貝進這個對象中。http://blog.csdn.net/sahadev_/article/details/WifiP2pDevice代表的將要連接的設備。然後調用connect()方法。

    @Override
    public void connect() {
        // Picking the first device found on the network.
        http://blog.csdn.net/sahadev_/article/details/WifiP2pDevice device = peers.get(0);
        WifiP2pConfig config = new WifiP2pConfig();
        config.deviceAddress = device.deviceAddress;
        config.wps.setup = WpsInfo.PBC;
        mManager.connect(mChannel, config, new ActionListener() {
            @Override
            public void onSuccess() {
                // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
            }
            @Override
            public void onFailure(int reason) {
                Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

上述代碼中的WifiP2pManager.ActionListener接口只有在初始化成功或者失敗的情況下才會調用。如果要監聽連接狀態的變化,需要實現WifiP2pManager.ConnectionInfoListener接口,它的方法onConnectionInfoAvailable()會在連接狀態發生變化的時候回調。在多台設備連接一台設備的情況下(比如多人互動的游戲或者聊天類的APP),其中一台設備會被指定為”group owner”。

    @Override
    public void onConnectionInfoAvailable(final WifiP2pInfo info) {
        // InetAddress from WifiP2pInfo struct.
        InetAddress groupOwnerAddress = info.groupOwnerAddress.getHostAddress());
        // After the group negotiation, we can determine the group owner.
        if (info.groupFormed && info.isGroupOwner) {
            // Do whatever tasks are specific to the group owner.
            // One common case is creating a server thread and accepting
            // incoming connections.
        } else if (info.groupFormed) {
            // The other device acts as the client. In this case,
            // you'll want to create a client thread that connects to the group
            // owner.
        }
    }

現在回到廣播接收器的onReceive()方法,修改監聽WIFI\_P2P\_CONNECTION\_CHANGED\_ACTION的部分,當這個意圖接收到時,調用requestConnectionInfo()方法。這是一個異步方法,所以結果會通過參數:連接信息監聽器回調回來。

        ...
        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            if (mManager == null) {
                return;
            }
            NetworkInfo networkInfo = (NetworkInfo) intent
                    .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
            if (networkInfo.isConnected()) {
                // We are connected with the other device, request connection
                // info to find group owner IP
                mManager.requestConnectionInfo(mChannel, connectionListener);
            }
            ...
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved