What is the minimum required code to establish a PubNub subscription in a service class? The examples on PubNub include code for on boot subscriptions, broadcast receivers, pushalarms, etc. Am I to believe that all this code from github is the minimum required?
The reason I ask is because I am self-learning code and having a rather rough time implementing services such as PubNub because their documentations are for a level of programmer that I haven't reached yet.
I look at the examples and try to extract just the very basic, bare necessities but I am unsure of what can be stripped from those example classes.
Thank you to someone who understands what I am trying to ask.
EDIT: To be clear this is my current PubNub service class:
public class PubNubService extends Service {
SharedPreferences sP;
static final String pub_key = " - ";
static final String sub_key = " - ";
Pubnub pubnub = new Pubnub(pub_key, sub_key, false);
String channel;
PowerManager.WakeLock wl = null;
private final Handler handler = new Handler() {
public void handleMessage(Message msg) {
String pnMsg = msg.obj.toString();
final Toast toast = Toast.makeText(getApplicationContext(), pnMsg, Toast.LENGTH_SHORT);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
}
}, 200);
}
};
private void notifyUser(Object message) {
Message msg = handler.obtainMessage();
try {
final String obj = (String) message;
msg.obj = obj;
handler.sendMessage(msg);
Log.i("Received msg : ", obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public void onCreate() {
super.onCreate();
Toast.makeText(this, "PubnubService created...", Toast.LENGTH_LONG).show();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SubscribeAtBoot");
if (wl != null) {
wl.acquire();
Log.i("PUBNUB", "Partial Wake Lock : " + wl.isHeld());
Toast.makeText(this, "Partial Wake Lock : " + wl.isHeld(), Toast.LENGTH_LONG).show();
}
Log.i("PUBNUB", "PubnubService created...");
try {
pubnub.subscribe(new String[] {channel}, new Callback() {
public void connectCallback(String channel) {
notifyUser("CONNECT on channel:" + channel);
}
public void disconnectCallback(String channel) {
notifyUser("DISCONNECT on channel:" + channel);
}
public void reconnectCallback(String channel) {
notifyUser("RECONNECT on channel:" + channel);
}
#Override
public void successCallback(String channel, Object message) {
notifyUser(channel + " " + message.toString());
}
#Override
public void errorCallback(String channel, Object message) {
notifyUser(channel + " " + message.toString());
}
});
} catch (PubnubException e) {
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (wl != null) {
wl.release();
Log.i("PUBNUB", "Partial Wake Lock : " + wl.isHeld());
Toast.makeText(this, "Partial Wake Lock : " + wl.isHeld(), Toast.LENGTH_LONG).show();
wl = null;
}
Toast.makeText(this, "PubnubService destroyed...", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
This service above is copied from this example. I call to start this service from my MainActivity. I call it like this from my onCreate method:
Intent serviceIntent = new Intent(this, PubNubService.class);
startService(serviceIntent);
The one thing that Android Studio yells at me for is that the Handler class should be static or leaks would occur. When I run my app, the error that occurs is: [Error: 128-0] : Unable to get Response Code. Please contact support with error details. Unable to resolve host "pubsub-1.pubnub.com": No address associated with hostname. And on the next line [Error: 100-1] : Timeout Occurred.
My Android Manifest has this added:
<service android:name=".PubNubService"/>
PubNub Minimal Android Sample Code to Publish & Subscribe
The simplest sort of example would be to just add all the code in a single Activity. All of the following code and be seen in PubNub Android SDK docs page.
import com.pubnub.api.*;
import org.json.*;
Pubnub pubnub = new Pubnub("your_pub_key", "your_sub_key");
pubnub.subscribe("channel1", new Callback() {
#Override
public void connectCallback(String channel, Object message) {
System.out.println("SUBSCRIBE : CONNECT on channel:" + channel
+ " : " + message.getClass() + " : "
+ message.toString());
}
#Override
public void disconnectCallback(String channel, Object message) {
System.out.println("SUBSCRIBE : DISCONNECT on channel:" + channel
+ " : " + message.getClass() + " : "
+ message.toString());
}
public void reconnectCallback(String channel, Object message) {
System.out.println("SUBSCRIBE : RECONNECT on channel:" + channel
+ " : " + message.getClass() + " : "
+ message.toString());
}
#Override
public void successCallback(String channel, Object message) {
System.out.println("SUBSCRIBE : " + channel + " : "
+ message.getClass() + " : " + message.toString());
// this is the messages received from publish
// add these messages to a list UI component
}
#Override
public void errorCallback(String channel, PubnubError error) {
System.out.println("SUBSCRIBE : ERROR on channel " + channel
+ " : " + error.toString());
}
}
);
Callback callback = new Callback() {
public void successCallback(String channel, Object response) {
System.out.println(response.toString());
}
public void errorCallback(String channel, PubnubError error) {
System.out.println(error.toString());
}
};
pubnub.publish("my_channel", "Hello from the PubNub Java SDK!" , callback);
You might have to make a few changes. For one, you should create a click method with the publish inside it that is bound to a button on your interface. And as noted in the successCallback for the subscribe method, you need to display the messages in a UI component on your Activity.
That should do it for you.
Subscribe at Boot
But there isn't really anything simpler than our Subscribe at Boot sample app that uses a Service to forward messages as Intents to an Activity.
Prevent Service Start on Device Boot
The fact that the Subscribe at Boot example starts up when the device is booted (powered on) is a matter of configuration. You can change the manifest so that it is only started when the app is started. See the SO thread Trying to start a service on boot on Android and undo the parts that make it start at boot.
This is full of helpful information on Android Services
More details on this in this SO thread "Is leaving a pubnub subscription open in a service optimal"
Related
I am currently using Network Service Discovery to detect HTTP services on my local network. I used the Google Android NSDChat project example, and it only returns to me the host names, however, the host IP address NULL.
This is my function that will return the host name
public void onServiceFound(NsdServiceInfo service) {
Log.d(TAG, "Service discovery success" + service.getHost());
//pref.putString("name", service.getServiceName());
if (!service.getServiceType().equals(SERVICE_TYPE)) {
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} else if (service.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same machine: " + mServiceName);
} else if (service.getServiceName().contains(mServiceName)){
mNsdManager.resolveService(service, mResolveListener);
}
}
public void initializeResolveListener() {
mResolveListener = new NsdManager.ResolveListener() {
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Called when the resolve fails. Use the error code to debug.
Log.e(TAG, "Resolve failed" + errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
int port = mService.getPort();
host = mService.getHost(); // getHost() will work now
Log.d(TAG, "Service discovery success" + host );
}
};
}
I face similar problem and I found this website. However after trying it, it did not work as well.
Host is null in NsdServiceInfo of NsdManager.DiscoveryListener.onServiceFound
The result of the registration shouldn't be empty, this is what I get from logcat and the callback of successful registration.
registerService 46518
onServiceRegistered name: mytest, type: null, host: null, port: 0, txtRecord:
Everything is empty, the port 46518 which was generated by the system, the type, the txtrecord.
The following code is from the official guide
private String mServiceName = "mytest";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
// Initialize a server socket on the next available port.
ServerSocket mServerSocket = new ServerSocket(0);
int mLocalPort = mServerSocket.getLocalPort();
registerService(mLocalPort);
} catch (IOException e) {
e.printStackTrace();
}
}
public void registerService(int port) {
Log.i(tag, "registerService " + port);
// Create the NsdServiceInfo object, and populate it.
NsdServiceInfo serviceInfo = new NsdServiceInfo();
// The name is subject to change based on conflicts with other services advertised on the same network.
serviceInfo.setServiceName(mServiceName);
serviceInfo.setServiceType("_mytest._tcp");
serviceInfo.setPort(port);
serviceInfo.setAttribute("info", android.os.Build.MODEL);
NsdManager mNsdManager = (NsdManager) getSystemService(Context.NSD_SERVICE);
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
}
NsdManager.RegistrationListener mRegistrationListener = new NsdManager.RegistrationListener() {
#Override
public void onServiceRegistered(NsdServiceInfo nsdServiceInfo) {
// Save the service name. Android may have changed it in order to
// resolve a conflict, so update the name you initially requested
// with the name Android actually used.
mServiceName = nsdServiceInfo.getServiceName();
Log.i(tag, "onServiceRegistered " + nsdServiceInfo);
}
#Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Registration failed! Put debugging code here to determine why.
Log.i(tag, "onRegistrationFailed code " + errorCode + "\n" + serviceInfo);
}
#Override
public void onServiceUnregistered(NsdServiceInfo arg0) {
// Service has been unregistered. This only happens when you call
// NsdManager.unregisterService() and pass in this listener.
Log.i(tag, "onServiceUnregistered " + arg0);
}
#Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Unregistration failed. Put debugging code here to determine why.
Log.i(tag, "onRegistrationFailed code " + errorCode + "\n" + serviceInfo);
}
};
Got the same on my LG G5 (Android 7.0)
Checked if the MDNS-Packets show up in Wireshark and they did!
It seems that the service is announced with the right ip and port,
even if the NsdServiceInfo in onServiceRegistered() says something different.
I'm having a weird problem. I already lost a lot of time trying to understand
and solve this but nothing works.
I have an app that communicates with another device across bluetooth connection
to receive some sensor data. In that point, everything works fine, I can connect
to the device, receive and treat the messages.
But yesterday, I decided to create some kind of log file to directly save in the
internal memory the data received from the device without any kind of transformation from my app.
To receive the data from the device, I have a background thread:
public class CommunicationThread extends Thread {
private static final UUID UUID_DEVICE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final String TAG = CommunicationThread.class.getSimpleName();
private CommunicationListener mListener;
private boolean mRunning;
private BluetoothSocket mBluetoothSocket;
private InputStream mInputStream;
private OutputStream mOutputStream;
public interface CommunicationListener {
void onMessageReceived(String msg);
}
public CommunicationThread(
#NonNull BluetoothDevice device,
#Nullable CommunicationListener listener) throws IOException {
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID_DEVICE);
socket.connect();
this.mBluetoothSocket = socket;
this.mInputStream = socket.getInputStream();
this.mOutputStream = socket.getOutputStream();
this.mListener = listener;
}
#Override
public void run() {
mRunning = true;
byte[] bytes = new byte[1024];
int length;
while (mRunning) {
try {
Log.d(TAG, "Waiting for message");
// read the message (block until receive)
length = mInputStream.read(bytes);
String msg = new String(bytes, 0, length);
Log.d(TAG, "Message: " + msg);
// Message received, inform the listener
if (mListener != null)
mListener.onMessageReceived(msg);
} catch (Exception e) {
Log.e(TAG, "Error reading the message", e);
}
}
}
public void sendCommand(String msg) {
try {
mOutputStream.write((msg).getBytes());
} catch (Exception e) {
Log.e(TAG, "Error to send message", e);
}
}
public void stopCommunication() {
mRunning = false;
mListener = null;
try {
if (mBluetoothSocket != null) {
mBluetoothSocket.close();
}
if (mInputStream != null) {
mInputStream.close();
}
if (mOutputStream != null) {
mOutputStream.close();
}
} catch (IOException e) {
Log.e(TAG, "Error to stop communication", e);
}
}
}
This thread works pretty fine and when a message is received, it informs the listener,
my Controller class. The first thing that I try to do when a message comes, is save it:
public class Controller implements CommunicationThread.CommunicationListener
...
#Override
public void onMessageReceived(final String msg) {
Log.d(TAG, "onMessageReceived(msg): " + msg);
mLogCreator.saveThis(msg);
....
}
}
Here is the LogCreator class:
public class LogCreator {
private static final String TAG = LogCreator.class.getSimpleName();
public static final String LOG_FILE_NAME = "log.txt";
private final Context mContext;
private volatile String mTempFullLog;
public LogCreator(Context context) {
mContext = context.getApplicationContext();
File dir = new File(mContext.getFilesDir(), "log_folder");
if (!dir.exists()) {
dir.mkdirs();
File file = new File(dir, LOG_FILE_NAME);
writeString(file, "");
Log.d(TAG, "empty file created");
}
}
public void saveThis(final String data) {
mTempFullLog += "\n" + data;
Log.d(TAG, "New log: " + data);
}
public void start() {
File dir = new File(mContext.getFilesDir(), "log_folder");
File file = new File(dir, LOG_FILE_NAME);
mTempFullLog = readString(file);
Log.d(TAG, "File: " + file);
Log.d(TAG, "Temp full log: " + mTempFullLog);
}
public void stop() {
File dir = new File(mContext.getFilesDir(), "log_folder");
File file = new File(dir, LOG_FILE_NAME);
writeString(file, mTempFullLog);
Log.d(TAG, "log saved: " + mTempFullLog);
}
}
The LogCreator class is already initialized and it works properly, because
if I try to read the file later, everything is there.
The real problem is the following: there is a lot of calls to Log.d during
this execution flow, and this makes very easy to me to understand the all process.
But, the logs are only printed in the logcat until this Log.d call, in the
CommunicationThread class:
Log.d(TAG, "Waiting for message);
After the message received, all code executes normally, but no logs are printed in
the logcat and I really dont know why.
Logs not printed:
CommunicationThread:
Log.d(TAG, "Message: " + msg);
Controller:
Log.d(TAG, "onMessageReceived(msg): " + msg);
LogCreator:
Log.d(TAG, "New log: " + data);
Like I said, I know that everything is working fine with the code because the log
file is created in internal memory even without the logcat prints. It cost me
some hours to realize that the problem is only with the log and not really in
my code.
For testing purpose, if I add this code in the saveThis method of LogCreator,
it executes normally:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast.makeText(mContext, data, Toast.LENGTH_SHORT).show();
}
});
This makes me think that everything could be a thread problem, because the start
and stop methods of LogCreator are both called from the main thread not the CommunicationThread and both methods have their logs printed. Because of this, in the onMessageReceived method
of the Controller class, I tried this:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
mLogCreator.saveThis(msg);
}
});
But, unfortunately, the logs don't get printed in the logcat. The toast is still
executed and the data are still saved to the file.
If anyone has any idea of what might be causing this, I really want to know, thanks.
I finally find the solution myself. The reason why the following not work is not clear for me, and IMO it should be treated like a bug.
I compile the app in debug mode and discover that the string received from the device has a "\r" in the end.
Example: "15.50\r"
So, for some strange reason, if I try to do this:
Log.d(TAG, "New log: " + data);
Nothing prints and we don't receive no warnings at all.
But, if I do this instead:
Log.d(TAG, "New log: " + data.replace("\r", ""));
Where data is: "15.50\r"
Everything works and the logcat prints the message.
I'm trying to implement an application, which is going to continuously send data from the mobile device Accelerometer to the PC via UDP protocol.
So, at this moment I realised that to receive data from the device Accelerometer I need to create a new SensorEventListener and override onSensorChanged() method and and to handle sensor data from the event variable, like this:
private class AccelerationListener implements SensorEventListener {
#Override
public void onSensorChanged(SensorEvent event) {
//handle event data here
}
}
That's pretty clear for me.
To send a message via DatagramSocket I've created a new Runnable:
private class UDPSend implements Runnable {
private byte[] message;
UDPSend(byte[] message) {
this.message = message;
}
#Override
public void run() {
try {
datagramSocket = new DatagramSocket();
InetAddress receiverAddress = InetAddress.getByName(SERVER_IP);
DatagramPacket packet = new DatagramPacket(
message,
message.length,
receiverAddress,
SERVER_PORT
);
datagramSocket.send(packet);
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
}
And then invoke this Runnable in the onSensorChanged() method like this:
#Override
public void onSensorChanged(SensorEvent event) {
String message = event.timestamp + " "
+ event.values[0] + " "
+ event.values[1] + " "
+ event.values[2];
new Thread(new UDPSend(message.getBytes())).start();
}
It's working just fine and my udp server succesfully receives sensor data.
So, my question - regarding to the fact, that I've set SensorManager.SENSOR_DELAY_FASTEST as an update rate for my SensorEventListener it creates thousands of threads to handle this SensorEvent spam. I'm afraid that it could badly affect the performance of the application and wondering is there any other way to deal with threading, but continue to send data continuously?
The simplest way to do manage the large number of threads to get rid of creating threads all together and send the sensor reads synchronously:
public void onSensorChanged(SensorEvent event) {
String message = event.timestamp + " "
+ event.values[0] + " "
+ event.values[1] + " "
+ event.values[2];
(new UDPSend(message.getBytes())).run();
}
Use a ThreadPool, this way you will have only one thread:
class Sender {
final ExecutorService pool = Executors.newSingleThreadExecutor();
public void send(byte[] bytes) {
pool.submit(new UDPSend(bytes);
}
}
public void onSensorChanged(SensorEvent event) {
String message = event.timestamp + " "
+ event.values[0] + " "
+ event.values[1] + " "
+ event.values[2];
sender.send(message.getBytes());
}
I am using the proximity-reference-android sample application provided by Radius Network to detect an iBeacon. I have an iPad configured as an iBeacon and have added around 3 beacon regions in the proximity kit. The problem I am facing right now I am unable to fetch the Beacon name ,and the additional url which I had in the proximity kit in Android.
I need to basically show up the url associated with beacon region in that proximity kit in Android App just like how the iOS application does.
While Debugging I had checked that even after the beacon is detected in the application,the didEnterRegion doesn't get called.I need to basically save the details of that particular beacon in the database once it is detected.
Neither is the application calling didExitRegion.
Posting the below code,please let me know what I am doing wrong in this.
public class AndroidProximityReferenceApplication extends Application implements
BootstrapNotifier {
private static final String TAG = "AndroidProximityReferenceApplication";
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean haveDetectedIBeaconsSinceBoot = false;
public void onCreate() {
super.onCreate();
Log.d(TAG,
"setting up background monitoring for iBeacons and power saving");
// wake up the app when an iBeacon is seen
Region region = new Region(
"com.radiusnetworks.androidproximityreference.backgroundRegion",
"2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6", null, null);
regionBootstrap = new RegionBootstrap(this, region);
// simply constructing this class and holding a reference to it in your
// custom Application
// class will automatically cause the iBeaconLibrary to save battery
// whenever the application
// is not visible. This reduces bluetooth power usage by about 60%
backgroundPowerSaver = new BackgroundPowerSaver(this);
}
#Override
public void didDetermineStateForRegion(int arg0, Region arg1) {
// This method is not used in this example
}
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever
// an iBeacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedIBeaconsSinceBoot) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an iBeacon, we
// launch the
// MainActivity
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance"
// in the manifest
// to keep multiple copies of this activity from getting created if
// the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedIBeaconsSinceBoot = true;
} else {
// If we have already seen iBeacons and launched the MainActivity
// before, we simply
// send a notification to the user on subsequent detections.
Log.d(TAG, "Sending notification.");
ParseObject beacon = new ParseObject("Beacon");
beacon.put("beacon_name", arg0.getClass().getName());
beacon.put("beacon_id", arg0.getUniqueId());
beacon.put("device_type", "Android");
beacon.put("device_UUID", android.os.Build.MODEL);
beacon.put("beacon_status", "ENTRY");
beacon.saveInBackground();
sendNotification();
}
}
#Override
public void didExitRegion(Region arg0) {
Log.d(TAG, "exited region");
ParseObject beacon = new ParseObject("Beacon");
beacon.put("beacon_name", arg0.getClass().getName());
beacon.put("beacon_id", arg0.getUniqueId());
beacon.put("device_type", "Android");
beacon.put("device_UUID", android.os.Build.MODEL);
beacon.put("beacon_status", "ENTRY");
beacon.saveInBackground();
}
private void sendNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this).setContentTitle("Proximity Reference Application")
.setContentText("An iBeacon is nearby.")
.setSmallIcon(R.drawable.ic_launcher);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(new Intent(this, MainActivity.class));
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
NotificationManager notificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
}
}
The code below is of the mainActivity class
public class MainActivity extends Activity implements IBeaconConsumer,
RangeNotifier, IBeaconDataNotifier {
public static final String TAG = "MainActivity";
IBeaconManager iBeaconManager;
Map<String, TableRow> rowMap = new HashMap<String, TableRow>();
#Override
protected void onCreate(Bundle savedInstanceState) {
Parse.initialize(this, "test123",
"test345");
IBeaconManager.LOG_DEBUG = true;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iBeaconManager = IBeaconManager.getInstanceForApplication(this
.getApplicationContext());
iBeaconManager.bind(this);
}
#Override
public void onIBeaconServiceConnect() {
Region region = new Region("MainActivityRanging", null, null, null);
try {
iBeaconManager.startRangingBeaconsInRegion(region);
iBeaconManager.setRangeNotifier(this);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
super.onDestroy();
iBeaconManager.unBind(this);
}
#Override
public void didRangeBeaconsInRegion(Collection<IBeacon> iBeacons,
Region region) {
for (IBeacon iBeacon : iBeacons) {
iBeacon.requestData(this);
Log.d(TAG, "I see an iBeacon: " + iBeacon.getProximityUuid() + ","
+ iBeacon.getMajor() + "," + iBeacon.getMinor());
String displayString = iBeacon.getProximityUuid() + " "
+ iBeacon.getMajor() + " " + iBeacon.getMinor() + "\n";
displayTableRow(iBeacon, displayString, false);
}
}
#Override
public void iBeaconDataUpdate(IBeacon iBeacon, IBeaconData iBeaconData,
DataProviderException e) {
if (e != null) {
Log.d(TAG, "data fetch error:" + e);
}
if (iBeaconData != null) {
Log.d(TAG,
"I have an iBeacon with data: uuid="
+ iBeacon.getProximityUuid() + " major="
+ iBeacon.getMajor() + " minor="
+ iBeacon.getMinor() + " welcomeMessage="
+ iBeaconData.get("welcomeMessage"));
String displayString = iBeacon.getProximityUuid() + " "
+ iBeacon.getMajor() + " " + iBeacon.getMinor() + "\n"
+ "Welcome message:" + iBeaconData.get("welcomeMessage");
displayTableRow(iBeacon, displayString, true);
}
}
private void displayTableRow(final IBeacon iBeacon,
final String displayString, final boolean updateIfExists) {
runOnUiThread(new Runnable() {
#Override
public void run() {
TableLayout table = (TableLayout) findViewById(R.id.beacon_table);
String key = iBeacon.getProximity() + "-" + iBeacon.getMajor()
+ "-" + iBeacon.getMinor();
TableRow tr = (TableRow) rowMap.get(key);
if (tr == null) {
tr = new TableRow(MainActivity.this);
tr.setLayoutParams(new TableRow.LayoutParams(
TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT));
rowMap.put(key, tr);
table.addView(tr);
} else {
if (updateIfExists == false) {
return;
}
}
tr.removeAllViews();
TextView textView = new TextView(MainActivity.this);
textView.setText(displayString);
tr.addView(textView);
}
});
}
}
Any help would be appreciated.Thanks :)
When using Proximity Kit for Android, there are two separate sets of APIs available. One set uses a ProximityKitManager, and it is intended for simpler use cases where you can pre-configure all of your iBeacon identifiers and associated data server-side, and let the ProximityKitManager handle setting up ranging and monitoring in a global Application class.
The second set of APIs use the IBeaconManager and provide more fine-grained control. But because the ProximityKitManager uses the IBeaconManager under the hood, you should not use both at the same time, because you can easily break the automatic configuration done by ProximityKitManager. I suspect that is what is causing your problem, because the code uses the ProximityKitManager in the Application class and IBeaconManager in the Activity class. See here for more info.
If you need to track beacons regardless of the identifiers set up in ProximityKit, but still want to access the data configured for certain iBeacons in ProximityKit, you should not use the ProximityKitManager and instead just use the IBeaconManager. There is a reference application that shows how to access ProximityKit data using this API available here.