accep stack 图片下载 clas prot internet lose .get
WiFi 直连可以在不通过网络或热点的情况下,直接与周围的设备进行连接并进行信息交换。WiFi 直连是在 Android 4.0(API level 14) 或更高的版本中才加入的新功能。本文主要介绍通过 Wi-Fi Direct 查找附近的设备,实现连接并完成图片的发送。一般包括如下几个步骤:
在 AndroidManifest 文件中声明相关权限
创建对等网络管理器(WifiP2pManager),注册相关广播监听 WiFi 直连状态
创建 MyAdapter,用于显示搜索到的对等点列表,监听点击连接事件
开始对对等点的搜索,获取对等点列表
连接一个对等点
判断一方为组拥有者(GroupOwner),提交接收图片的异步任务
调用系统图库选择图片,开启后台服务将其发送
分别设作为组拥有者,完成图片的互发
在 AndroidManifest 文件中声明相关权限
- "14"/>"android.permission.ACCESS_WIFI_STATE"/>"android.permission.CHANGE_WIFI_STATE"/>"android.permission.CHANGE_NETWORK_STATE"/>"android.permission.INTERNET"/>"android.permission.ACCESS_NETWORK_STATE"/>"android.permission.WRITE_EXTERNAL_STORAGE"/>"android.permission.READ_EXTERNAL_STORAGE"/>
WiFi 直连是在 api level 14 及更高的版本才能使用,所以要声明
- android:minSdkVersion="14"。
创建对等网络管理器(WifiP2pManager),注册相关广播监听 WiFi 直连状态
使用 WiFi 直连,需要监听如下动作:
- WIFI_P2P_STATE_CHANGED_ACTION — 表明Wi-Fi对等网络(P2P)是否已经启用
- WIFI_P2P_PEERS_CHANGED_ACTION — 表明可用的对等点的列表发生了改变
- WIFI_P2P_CONNECTION_CHANGED_ACTION — 表明Wi-Fi对等网络的连接状态发生了改变
- WIFI_P2P_THIS_DEVICE_CHANGED_ACTION — 表明该设备的配置信息发生了改变
- private BroadcastReceiver mReceiver;
- private IntentFilter mFilter;
- private void initIntentFilter() {
- mFilter =newIntentFilter();
- mFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
- mFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
- mFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
- mFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
- }mReceiver=newWifiDirectBroadcastReceiver(mManager, mChannel,this, mPeerListListerner, mInfoListener);@Overrideprotected void onResume() {
- super.onResume();
- registerReceiver(mReceiver, mFilter);
- }
- @Override
- public void onPause() {
- super.onPause();
- unregisterReceiver(mReceiver);
- }
广播接收
- public classWifiDirectBroadcastReceiverextends BroadcastReceiver {
- private WifiP2pManager mManager;
- private WifiP2pManager.Channel mChannel;
- private Activity mActivity;
- private WifiP2pManager.PeerListListener mPeerListListener;
- private WifiP2pManager.ConnectionInfoListener mInfoListener;
- public WifiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, Activity activity,
- WifiP2pManager.PeerListListener peerListListener,
- WifiP2pManager.ConnectionInfoListener infoListener
- ) {
- this.mManager = manager;
- this.mChannel = channel;
- this.mPeerListListener = peerListListener;
- this.mActivity = activity;
- this.mInfoListener = infoListener;
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- /*check if the wifi is enable*/
- if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
- intstate = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
- }
- /*get the list*/
- else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
- mManager.requestPeers(mChannel, mPeerListListener);
- } /*Respond to new connection or disconnections*/
- 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()) {
- mManager.requestConnectionInfo(mChannel, mInfoListener);
- } else {return;
- }
- }
- /*Respond to this device's wifi state changing*/
- else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
- }
- }
- }
创建 MyAdapter,用于显示接下来搜索到的对等点列表,监听点击连接事件
- 继承RecyclerView.Adapter,实现获取对等点列表的显示和响应事件
- public classMyAdapterextendsRecyclerView.Adapter {
- privateList> mList;
- /*
- * 设置回调接口,实现点击
- * */
- public interface OnItemClickListener {
- voidOnItemClick(View view,int position);
- }
- public OnItemClickListener mOnItemClickListener;
- public void SetOnItemClickListener(OnItemClickListener listener) {
- this.mOnItemClickListener = listener;
- }
- publicMyAdapter(List> list) {
- super();
- this.mList = list;
- }
- @Override
- publicMyHolder onCreateViewHolder(ViewGroup parent,int viewType) {
- LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- View view = inflater.inflate(R.layout.card_item,
- parent, false);
- MyHolder myHolder =new MyHolder(view);
- return myHolder;
- }
- @Override
- public voidonBindViewHolder(finalMyHolder holder,final int position) {
- holder.tvname.setText(mList.get(position).get("name"));
- holder.tvaddress.setText(mList.get(position).get("address"));
- if(mOnItemClickListener !=null) {
- holder.itemView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mOnItemClickListener.OnItemClick(holder.itemView, position);
- }
- });
- }
- }
- @Override
- public int getItemCount() {
- return mList.size();
- }
- classMyHolderextends RecyclerView.ViewHolder {
- public TextView tvname;
- public TextView tvaddress;
- public MyHolder(View View) {
- super(View);
- tvname = (TextView) View.findViewById(R.id.tv_name);
- tvaddress = (TextView) View.findViewById(R.id.tv_address);
- }
- }
- }
开始对对等点的搜索,获取对等点列表
首先在 onCreate() 方法中获得了 WifiP2pManager 的一个实例,调用它的 initialize() 方法。这个方法返回一个 WifiP2pManager.Channel 对象,并触发
的广播,把应用程序连接到 Wi-Fi Direct 框架中。
- WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION
- protected void onCreate(Bundle savedInstanceState) {
- ...
- mManager = (WifiP2pManager) getSystemService(WIFI_P2P_SERVICE);
- mChannel = mManager.initialize(this, Looper.myLooper(),null);
- }
点击开启搜索,调用 discoverPeers() 方法。其参数如下:
WifiP2pManager.Channel 即从上一步调用 initialize() 的 方法得到
WifiP2pManager.ActionListener 实现了系统在查找成功或失败时会调用的方法
- mManager.discoverPeers(mChannel,new WifiP2pManager.ActionListener() {
- //Register for WIFI_P2P_PEERS_CHANGED_ACTION
- @Override
- public void onSuccess() {
- }
- @Override
- public voidonFailure(int reason) {
- }
- });
如果发现设备会回调上面的 onSuccess() 方法,讲触发
这个广播,在 onReceive() 中可以调用
- WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
方法,然后在 MainActivity 的 PeerListListerner 接口中,调用 onPeersAvailable() 回调方法,获取到对等列表的详细信息,通过 MyAdapter 在 RecyclerView 列表中显示。
- requestPeers()
- WifiP2pManager.PeerListListener mPeerListListerner =new WifiP2pManager.PeerListListener() {
- @Override
- public void onPeersAvailable(WifiP2pDeviceList peersList) {
- peers.clear();
- peersshow.clear();
- Collection aList = peersList.getDeviceList();
- peers.addAll(aList);
- for(inti = 0; i < aList.size(); i++) {
- WifiP2pDevice a = (WifiP2pDevice) peers.get(i);
- HashMap map = newHashMap();
- map.put("name", a.deviceName);
- map.put("address", a.deviceAddress);
- peersshow.add(map);
- }
- mAdapter =new MyAdapter(peersshow);
- mRecyclerView.setAdapter(mAdapter);
- mRecyclerView.setLayoutManager(new LinearLayoutManager
- (MainActivity.this));
- }
- };
连接一个对等点
触摸 RecyclerView 列表上的对等设备信息,触发响应事件,调用 CreateConnect() 方法,方法参数为触摸列表上的设备信息。在该方法中,需要先创建一个新的 WifiP2pConfig 对象,记录传进来的设备参数,然后调用 connect() 方法。 如果设备会回调 onSuccess() 方法,这说明对等点连接成功。
- private voidCreateConnect(String address,final String name) {
- WifiP2pDevice device;
- WifiP2pConfig config =new WifiP2pConfig();
- config.deviceAddress = address;
- config.wps.setup = WpsInfo.PBC;
- mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
- // Register for WIFI_P2P_CONNECTION_CHANGED_ACTION
- @Override
- public void onSuccess() {
- }
- @Override
- public voidonFailure(int reason) {
- }
- });
- }
判断一方为组拥有者(GroupOwner),提交接收图片的异步任务
对等点连接成功后,会触发
这个广播,在 onReceive() 中调用
- WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION
方法,然后在 MainActivity 的 ConnectionInfoListerner 接口中,调用 onConnectionInfoAvailable() 回调方法,获取到组连接信息,根据获取到的信息,判断是否为组拥有者。若是,作为服务端,向其提交图片下载、读取的异步任务。
- requestConnectionInfo()
- WifiP2pManager.ConnectionInfoListener mInfoListener =new WifiP2pManager.ConnectionInfoListener() {
- @Override
- public voidonConnectionInfoAvailable(final WifiP2pInfo minfo) {
- info = minfo;
- view = (TextView) findViewById(R.id.tv_main);
- if(info.groupFormed && info.isGroupOwner) {//确定为组拥有者,创建线程用于接收连接请求
- //提交图片下载、读取的异步任务
- } else if (info.groupFormed) {
- //作为客户端,创建一个线程用于连接组拥有者
- }
- }
- };
- public classFileServerAsyncTaskextends
- AsyncTask {
- private Context context;
- private TextView statusText;
- /**
- * @param context
- * @param statusText
- */
- public FileServerAsyncTask(Context context, View statusText) {
- this.context = context;
- this.statusText = (TextView) statusText;
- }
- @Override
- protected String doInBackground(Void... params) {
- try {
- ServerSocket serverSocket =newServerSocket(8888);
- Socket client = serverSocket.accept();
- finalFile f =new File(
- Environment.getExternalStorageDirectory() + "/" + "RecvPicture"+
- "/wifip2pshared-" + System.currentTimeMillis() + ".jpg");
- File dirs =new File(f.getParent());
- if(!dirs.exists())
- dirs.mkdirs();
- f.createNewFile();
- /*Returns an input stream to read data from this socket*/
- InputStream inputstream = client.getInputStream();
- copyFile(inputstream, new FileOutputStream(f));
- serverSocket.close();
- return f.getAbsolutePath();
- } catch (IOException e) {
- Log.e("xyz", e.toString());
- return null;
- }
- }
- /*
- * (non-Javadoc)
- *
- * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
- */
- @Override
- protected void onPostExecute(String result) {if(result !=null){
- Toast.makeText(context, "RecvPic:"+result, Toast.LENGTH_SHORT).show();
- }
- if(result !=null) {
- statusText.setText("RecvPic: " + result);
- Intent intent =new Intent();
- intent.setAction(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.parse("file://" + result), "image/*");
- context.startActivity(intent);
- }
- }public static boolean copyFile(InputStream inputStream, OutputStream out) {
- bytebuf[] =new byte[1024];
- int len;
- try {
- while((len = inputStream.read(buf)) != -1) {
- out.write(buf, 0, len);
- }
- out.close();
- inputStream.close();
- } catch (IOException e) {
- return false;
- }
- return true;
- }
- }
调用系统图库选择图片,开启后台服务将其发送
点击发送图片按钮,调用系统图库。选取图片后,开启图片发送服务,并将图片路径,发送的 ip 地址和接收的端口号传入。
- public classFileTransferServiceextends IntentService {
- private static final intSOCKET_TIMEOUT = 5000;
- public static finalString ACTION_SEND_FILE = "com.example.android.wifidirect.SEND_FILE";
- public static finalString EXTRAS_FILE_PATH = "sf_file_url";
- public static finalString EXTRAS_GROUP_OWNER_ADDRESS = "sf_go_host";
- public static finalString EXTRAS_GROUP_OWNER_PORT = "sf_go_port";
- public FileTransferService(String name) {
- super(name);
- }
- public FileTransferService() {
- super("FileTransferService");
- }
- /*
- * (non-Javadoc)
- *
- * @see android.app.IntentService#onHandleIntent(android.content.Intent)
- */
- @Override
- protected void onHandleIntent(Intent intent) {
- Context context = getApplicationContext();
- if (intent.getAction().equals(ACTION_SEND_FILE)) {
- String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
- String host = intent.getExtras().getString(
- EXTRAS_GROUP_OWNER_ADDRESS);
- Socket socket =new Socket();
- intport = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
- try {
- Log.d("xyz", "Opening client socket - ");
- socket.bind(null);
- socket.connect((new InetSocketAddress(host, port)),
- SOCKET_TIMEOUT);
- Log.d("xyz",
- "Client socket - " + socket.isConnected());
- /*returns an output stream to write data into this socket*/
- OutputStream stream = socket.getOutputStream();
- ContentResolver cr = context.getContentResolver();
- InputStream is =null;
- try {
- is = cr.openInputStream(Uri.parse(fileUri));
- } catch (FileNotFoundException e) {}FileServerAsyncTask.copyFile(is, stream);
- } catch (IOException e) {
- } finally {
- if(socket !=null) {
- if (socket.isConnected()) {
- try {
- socket.close();
- } catch (IOException e) {
- // Give up
- e.printStackTrace();
- }
- }
- }
- }
- }
- }
- }
分别设作为组拥有者,完成图片的互发
调用 createGroup() 方法,分别设定本设备为组拥有者,实现设备图片的互发。
- mManager.createGroup(mChannel,new WifiP2pManager.ActionListener() {
- @Override
- public void onSuccess() {
- Log.i("tag","BeGroupOwner success");
- }
- @Override
- public voidonFailure(int reason) {
- Log.i("tag","BeGroupOwner failed");
- }
- });
Android WiFi 直连并互发图片
来源: http://www.bubuko.com/infodetail-2053120.html