我正在尝试通过 wifi direct 连接 2 台设备,假设设备 A 和设备 B 的 android > 4.1。如果我在设备 A 上按下按钮搜索其他设备,它的行为并不总是相同。
例如,如果我按下设备 A 上的搜索按钮,它不会找到任何东西,直到我也按下设备 B 上的搜索按钮,即使该应用程序同时在两台设备上运行也是如此。 因此设备 B 在不开始搜索其他设备之前是不可见的。
其他时候,如果我使用设备 A 搜索设备,它会找到设备 B,即使该应用最近在设备 B 上关闭,如果我尝试连接到设备 B,它也能正常工作。 问题是我只想在应用程序在两个设备上运行时建立连接。
有时,当设备 A 发现设备 B 并尝试连接到它时,直到设备 B 开始寻找设备,它才起作用。 因此,当我开始在设备 B 上搜索时,它会收到来自 A 的连接请求,但在此之前什么也没有。
有些时候,在设备 A 上按下搜索按钮后,它会显示一些当时没有启用 wifi 或超出范围的设备。
这是我的代码:
主要 Activity .java
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnItemClickListener, PeerListListener {
private WifiP2pManager mManager;
private Channel mChannel;
private BroadcastReceiver mReceiver;
private IntentFilter mIntentFilter;
private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
private List<WifiP2pDevice> peersConnect = new ArrayList<WifiP2pDevice>();
private ArrayList<String> peersName = new ArrayList<String>();
private ListView list;
private Button bSearch;
private Button bConnect;
private Button bDisconnect;
private int nSelectedDevices = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
try {
Class<?> wifiManager = Class
.forName("android.net.wifi.p2p.WifiP2pManager");
Method method = wifiManager
.getMethod(
"enableP2p",
new Class[] { android.net.wifi.p2p.WifiP2pManager.Channel.class });
method.invoke(mManager, mChannel);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
bSearch = (Button) this.findViewById(R.id.searcher);
bSearch.setOnClickListener(new OnClickListener() {
public void onClick (View v) {
list.setVisibility(ListView.INVISIBLE);
bConnect.setVisibility(View.INVISIBLE);
bDisconnect.setVisibility(View.INVISIBLE);
nSelectedDevices = 0;
peersConnect.clear();
peers.clear();
peersName.clear();
searchDevices();
}
});
bConnect = (Button) this.findViewById(R.id.connecter);
bConnect.setOnClickListener(new OnClickListener() {
public void onClick (View v) {
bDisconnect.setVisibility(View.VISIBLE);
connectDevices();
bConnect.setVisibility(View.INVISIBLE);
nSelectedDevices = 0;
peersConnect.clear();
}
});
bDisconnect = (Button) this.findViewById(R.id.disconnecter);
bDisconnect.setOnClickListener(new OnClickListener() {
public void onClick (View v) {
disconnectDevices();
peersConnect.clear();
bDisconnect.setVisibility(View.INVISIBLE);
}
});
list = (ListView) this.findViewById(R.id.list);
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//-- text filtering
list.setTextFilterEnabled(true);
}
/* register the broadcast receiver with the intent values to be matched */
@Override
protected void onResume() {
super.onResume();
mReceiver = new WifiReceiver(mManager, mChannel, this);
registerReceiver(mReceiver, mIntentFilter);
}
/* unregister the broadcast receiver */
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
finish();
}
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
CheckedTextView item = (CheckedTextView) v;
if(item.isChecked()) {
nSelectedDevices++;
peersConnect.add(peers.get(position));
}
else {
nSelectedDevices--;
peersConnect.remove(peers.get(position));
}
if(nSelectedDevices == 1)
bConnect.setVisibility(View.VISIBLE);
else if(nSelectedDevices == 0)
bConnect.setVisibility(View.INVISIBLE);
}
@Override
public void onPeersAvailable(WifiP2pDeviceList peerList) {
// Out with the old, in with the new.
peers.clear();
peers.addAll(peerList.getDeviceList());
getDeviceName();
list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, peersName));
list.setOnItemClickListener(this);
list.setVisibility(ListView.VISIBLE);
// 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.
//((ListAdapter) getListAdapter()).notifyDataSetChanged();
if (peers.size() == 0) {
return;
}
}
private void searchDevices() {
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
//Toast.makeText(MainActivity.this, "Inizio ricerca...", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int reasonCode) {
//Toast.makeText(MainActivity.this, "Ricerca fallita!", Toast.LENGTH_SHORT).show();
}
});
}
private void connectDevices() {
for(int i = 0; i < peersConnect.size(); i++) {
// Picking the first device found on the network.
WifiP2pDevice device = peersConnect.get(i);
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.
Toast.makeText(MainActivity.this, "Connection requested...", Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(int reason) {
Toast.makeText(MainActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show();
}
});
}
}
public void disconnectDevices() {
if (mManager != null && mChannel != null) {
mManager.requestGroupInfo(mChannel, new GroupInfoListener() {
@Override
public void onGroupInfoAvailable(WifiP2pGroup group) {
if (group != null && mManager != null && mChannel != null && group.isGroupOwner()) {
mManager.removeGroup(mChannel, new ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
}
});
}
}
});
}
}
private void getDeviceName() {
int i = 0;
peersName.clear();
while(i < peers.size()) {
peersName.add(peers.get(i).deviceName);
i++;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
无线接收器.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.widget.Toast;
public class WifiReceiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private Channel mChannel;
private MainActivity mActivity;
public WifiReceiver(WifiP2pManager manager, Channel channel, MainActivity activity) {
super();
this.mManager = manager;
this.mChannel = channel;
this.mActivity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { // check if wifi is enabled/disabled
System.out.println("Connection changed");
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
//mActivity.setIsWifiP2pEnabled(true);
} else {
//mActivity.setIsWifiP2pEnabled(false);
}
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// Call WifiP2pManager.requestPeers() to get a list of current peers
// 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()
System.out.println("Peers changed");
if (mManager != null) {
mManager.requestPeers(mChannel, mActivity);
}
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// Respond to new connection or disconnections
System.out.println("Connection changed");
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
// Respond to this device's wifi state changing
System.out.println("This device changed");
}
else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)) {
// Respond to this device's wifi state changing
System.out.println("Search peers");
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/linearlayout1" >
<Button
android:id="@+id/searcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_send" />
<Button
android:id="@+id/connecter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_connect"
android:visibility="invisible" />
<Button
android:id="@+id/disconnecter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_disconnect"
android:visibility="invisible" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/linearlayout1" >
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="380dp"
android:layout_alignParentLeft="true"
android:visibility="invisible" >
</ListView>
</LinearLayout>
"
</RelativeLayout>
我不明白 mManager.discoverPeers() 和 mManager.requestPeers() 是如何工作的。
感谢您的关注!!
最佳答案
实际上您有有效的观察结果,这就是 API 实际工作的方式:
这就是 API 的工作方式。基本上,为了对其他设备可见,WiFi 接口(interface)需要通电并处于 Activity 状态,到目前为止,当设备进行主动发现或进行主动连接时,我已经看到它发生了。
基本上,我认为您能做的最好的事情就是在应用程序运行时公布服务,并在连接时发现服务。这并不是 100% 准确的,因此,您还可以实现从客户端到组所有者的连接和握手,以全面检查两端是否正常并存在。如果握手失败,则断开连接。
这个我没有直接的答案,基本上可能是哪里不对劲。我知道如果设备 B 不活动,它不应该是可见的,并且如果设备 B 不在 API 的实际发现对等列表中,那么所有连接尝试都会失败,所以可能是一些问题的组合真的发生在这里。
假设 API 确实有时会缓存一些结果,但不得不承认我没有看到这个问题,当我关闭附近的设备时,我通常会收到 peer changed 事件,然后 Service discovery 没有给出任何设备上的任何结果实际上都不会存在,因此请务必在获得 Peers Changed 事件后始终尝试服务发现。
关于java - Android wifi p2p 对端可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31011341/
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在编写一个方法,它将在一个类中定义一个实例方法;类似于attr_accessor:classFoocustom_method(:foo)end我通过将custom_method函数添加到Module模块并使用define_method定义方法来实现它,效果很好。但我无法弄清楚如何考虑类(class)的可见性属性。例如,在下面的类中classFoocustom_method(:foo)privatecustom_method(:bar)end第一个生成的方法(foo)必须是公共(public)的,第二个(bar)必须是私有(private)的。我怎么做?或者,如何找到调用我的cust
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.
Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur