I'm in the middle of creating an application for Wear that has a phone companion app to do some of the heavier processes and make API calls.
So far in regards to communication between the two devices, I have been following this tutorial - http://android-wear-docs.readthedocs.io/en/latest/data.html
This has left me with the phone being able to communicate with the watch, but now I'm wondering how I replicate it working the other way.
The current code I have on the Wear app is like this (a seperate listener class is also present on the phone and watch):
public void sendTestMessage(View view)
{
String WEARABLE_DATA_PATH = "/wearable_data";
DataMap dataMap = new DataMap();
dataMap.putString("WATCH2PHONE TEST MESSAGE EVENT!", "1");
new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();
}
class SendToDataLayerThread extends Thread
{
String path;
DataMap dataMap;
SendToDataLayerThread(String p, DataMap data)
{
path = p;
dataMap = data;
}
public void run()
{
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
putDMR.getDataMap().putAll(dataMap);
PutDataRequest request = putDMR.asPutDataRequest();
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleClient, request).await();
if (result.getStatus().isSuccess())
{
Log.v("myTag", "DataMap: " + dataMap + " sent successfully to data layer ");
}
else
{
Log.v("myTag", "ERROR: failed to send DataMap to data layer");
}
}
}
Listener Class (for watch, the phone version is identical):
public class ListenerService extends WearableListenerService
{
#Override
public void onDataChanged(DataEventBuffer dataEvents)
{
DataMap dataMap;
for (DataEvent event : dataEvents)
{
Log.v("myTag", "DataMap received on device: " + DataMapItem.fromDataItem(event.getDataItem()).getDataMap());
}
}
}
So sending the test message sends the messages to the layer and they send, but are received by the watch's listener service.
I'm assuming the "String WEARABLE_DATA_PATH = "/wearable_data";" is what's causing it to end up being received by the watch but I'm unsure what to change it to in order to get it to send properly.
The Data API works the same in both directions. The specific architecture to use on the handheld depends on your app's structure, but there is a good overview of the options in the documentation at https://developer.android.com/training/wearables/data-layer/events.html#Listen.
That page also discusses using a path to filter the data events received. Again, this depends on your architecture, but it might be reasonable to use paths like "/data_from_handheld" and "/data_from_wearable" to differentiate the DataItems going in the different directions. Or you can use the same path, and then the data events will appear on all connected devices - which may or may not be what you want.
One other common "gotcha": Data API events only fire when the data has actually changed. This is an efficient way for the API to handle real-world communications, but can make development difficult. To force it, simply include an item that is always different, such as:
dataMap.putLong("timestamp", System.nanoTime());
...but be sure to take that out before deploying the app!
Related
I am developing an application that uses the Spotify API. It has to start a specific track. I can achieve this.
But after the track is finished the playback stops. I want Spotify to play the following tracks of the album then. Is there a way to do so?
I have not messed with the player state yet too much (only grabbing cover art uri), but here is how I would go about it off the top of my head.
I would first subscribe to the player state to see what is going on with the player. If it is paused, I would then play the album you were talking about or want to talk about. Here is a small example that might be helpful.
SpotifyAppRemote mSpotifyAppRemote; // The app remote
/* For mAppRemoteSet the connection parameters */
connectionParams = new ConnectionParams.Builder(CLIENT_ID)
.setRedirectUri(REDIRECT_URI)
.showAuthView(true)
.build();
/* Connect to SpotifyAppRemote */
SpotifyAppRemote.connect(this, connectionParams, new Connector.ConnectionListener() {
#Override
public void onConnected(SpotifyAppRemote spotifyAppRemote) {
mSpotifyAppRemote = spotifyAppRemote;
Log.d(TAG, "App remote Connected!");
connected();
#Override
public void onFailure(Throwable throwable) {
Log.e(TAG, throwable.getMessage(), throwable);
// Hanfle errors here
}
});
}
public connected() {
/* Subscribe to the PlayerState */
mSpotifyAppRemote.getPlayerApi()
.subscribeToPlayerState()
.setEventCallback(playerState -> {
if (playerState.isPaused) {
mSpotifyAppRemote.getPlayerApi().play("ALBUM URI");
}
});
}
Where "CLIENT_ID" and "REDIRECT_URI" are specific to what you defined in your code already from the dashboard.
Where "ALBUM URI" is the id specific to that album you want to play after you play the first song you mentioned.
You can also play the specific track then set the offset of the album to the beginning and start the whole album over if the specific track is in the middle, end, etc of the album.
I am still learning the sdk and the many options it offers so I apologize ahead of time if this is completely irrelevant or unhelpful.
I am building an Android app (my first app actually) and it's about getting similar tracks to the one you searched for. I am using retrofit2 with rxJava and gson for my calls.
For each track i found i add the corresponding image provided by the response in an imageview, but this image is not the actual album image, it's just an image of the band. I want to have the album image which i can get from the API if i do an album search.
So is there a way to make a API call that returns the album info for each track without losing to much time loading? I want these calls to happen in parallel with each other so as to be less visible to the "user" (me).
This is the code that i use to search for the similar tracks:
private void loadSimilarTracks() {
String mbid = selectedTrack.getMbid();
String artist = selectedTrack.getmArtist();
String track = selectedTrack.getName();
searchService = new LastFMSearchService();
Flowable<List<TrackSimilar>> fetchDataObservable = null;
if(!mbid.equals("")) {
fetchDataObservable = searchService.getSimilarTracks(mbid);
}
else{
fetchDataObservable = searchService.getSimilarTracks(artist, track);
}
mCompositeSubscription.add(fetchDataObservable
.timeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSubscriber<List<TrackSimilar>>() {
#Override
public void onNext(List<TrackSimilar> tracks) {
mTracks = tracks;
similarTrackAdapter.setTrackList(tracks);
}
#Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), "API CALL ERROR", Toast.LENGTH_SHORT).show();
}
#Override
public void onComplete() {
resultsView.setVisibility(View.VISIBLE);
}
})
);
}
P.S i am using the lastFM api for my info.
Thanks in advance for any response.
Your code is good, one thing that you can do is that you can segment your code into multiple functions instead of a single one and run them as separate threads.
One function that makes api calls to search for similar tracks and other to get the image and trust me that significantly improves the response. Hope it helps..
Intro to me and my application school project
Hi,
iam pretty new with android and for some school project iam building an application where users can configure regions to recieve alerts from. The app need also make it posible to recieve alerts around the current location of the app user.
The app gets its info from a xml feed and sorts the data by the configured regions. The workflow is 1. to get the alerts which are in the configured regions. 2. When gps alerts are enabled the app need to get the location and when it is known it needs to do the first step again but this time the gps region is included. (i need to optimize this proces LATER)
(questions bellow)
intro to my app and problem
I'm using a asynctask in my application to download some xml feed. When the asynctask is ready i need to call 3 places for do something with the result.
1 class saves the result in the local database (alertmanager)
2 fragments (in a tabview) needs to show the results (1 in a map an one in a listview)
Now i use weakreferences for giving the call back "references" to the asynctask. in the onPostExecute() i use theWeakReference.get().updateMethod(result); for updating the class/fragments.
The alertmanager (the class who needs to recieve the updates) also calls a gps manager in the same method where it calls the asynctask to get the gps location. When i comment out (in my case with a if) the line what calls the gps manager the weak reference of the alertmanager will go to null in the asynctask between the constructor (all references are filled) and the doInBackground (the alertmanager reference is null, the other 2 still filled) which results in a crashing app.
When i dont comment out the if the app works fine.....
Alertmanager information
This is the method in the alertmanager who calls the async task. The references are filled on this place.
public void GetAlerts(List<WeakReference<e_Alerts>> callbackReferences, Context context) {
//Update the alerts in the listview and mapview with the local alerts.
List<Alert> localAlerts = internalDc.GetAllAlerts();
try {
for (WeakReference<e_Alerts> callback : callbackReferences) {
callback.get().UpdateAlerts(localAlerts);
}
} catch (Exception e) {
Log.e("AlertManager", e.getMessage());
}
//If connected to the internet then update the local db and the views
if (isConnectingToInternet(context)) {
WeakReference<e_Alerts> wr = new WeakReference<e_Alerts>(this);
callbackReferences.add(wr);
// Update the alerts where no location is needed for so the user has a quick result
externalDc.getAlerts(callbackReferences, areaManager.GetActiveAreas(false));
// If gps region is enabled then find the phones location and update the alerts
if (areaManager.GetGpsArea().IsActive()) {
new GpsManager(this.context, this, callbackReferences);
}
}
}
The GpsManager extends the LocationListener:
public class GpsManager extends Service implements LocationListener {
The listener is implemented by the Alertmanager
// This method is caled by the GPS Manager when the GPS location is changed
#Override
public void OnLocationChanged(Location location, List<WeakReference<e_Alerts>> references) {Area gpsArea = areaManager.GetGpsArea();
gpsArea.SetLocation(location);
areaManager.SaveArea(gpsArea);
externalDc.getAlerts(references, areaManager.GetActiveAreas(true));
}
Asynctask information
This are the asynctask methods:
Asynctask constructor:
Here the list callbackReferences contains 3 weakrefrences and all of them are filled (2x fragment reference 1x alertmanager reference)
public At_allAlerts(List<WeakReference<e_Alerts>> callbackReferences, List<Area> areas) {
this.mCallbackReferences = callbackReferences;
this.mAreas = areas;
}
doInBackground code:
The XmlDownloader: Downloads an xml feed an parses the xml to objects with a library
The AlertConverter: converts the xml object to the object i use in my app
Both classes can work without the asynctask class and don't use the references.
#Override
protected String doInBackground(String... inputUrl) {
Log.i("At_allAlerts", "Asynctask for downloading and parsing mAlerts is started");
try {
//Downloads the alert XMLs from the internet and parses it to xmlAlerts
this.mAlerts = new XmlDownloader().DownloadAlerts(inputUrl);
// Filters the mXml mAlerts so only the mAlerts where the enduser is interessed in will remain
this.mAlerts = filterAlerts(this.mAlerts);
// Converts the remaining xmlAlerts to Alerts;
this.mResult = new AlertConverter().Convert(this.mAlerts);
}catch (Exception e) {
Log.e("At_allAlerts",e.getMessage());
}
return null;
}
The onPostExecute method:
When the programm comes in this method the this.references.get(2) reference (alertmanager reference) = null, the other 2 references are still filed
#Override
protected void onPostExecute(String xml){
for (WeakReference<e_Alerts> reference : activityWeakReferences)
{
reference.get().UpdateAlerts(this.result);
}
}
filterAlerts Method:
private List<Item> filterAlerts(List<Item> alerts) {
List<Item> filteredXmlAlerts = new ArrayList<>();
for (Item alert : alerts)
{
Location alertLocation = new Location("");
alertLocation.setLatitude(alert.getGeometries().get(0).getLocations().get(0).getLat());
alertLocation.setLongitude(alert.getGeometries().get(0).getLocations().get(0).getLng());
for(Area area : this.mAreas)
{
if (area.IsOrganization() && alert.getCountryCode().toLowerCase().equals(area.getOrganizationcode().toLowerCase())){
filteredXmlAlerts.add(alert);
break;
}
else if(!area.IsOrganization() && isAlertInRegion(alertLocation, area)) {
filteredXmlAlerts.add(alert);
break;
}
}
}
return filteredXmlAlerts;
}
My Question(s)
I think Weakreference are the right way for giving references to asynctask is this correct or do i need to give it as an other object? (class or object or whatever?).
Why goes my reference to null? and only one of the 3? and only when i dont use the gps location class? and how to solve this?
I read something about the garbage collector what can be the cause of this problem, is this true and when yes how can i solve this?
It would be fine when the answere are simple to understand since android is pretty new for me.
I need to implement front-end for Server-Sent-Event. I use GWT, and i can not find any solution to create a listener for SSE. I need to push the data from server and to receive it on client every time hen data was changed. So for now i have a something like this:
private void method() {
final EventSource eventSource = EventSource.newEventSourceIfSupported();
if (null != eventSource) {
eventSource.setListener(this);
eventSource.open(GWT.getHostPageBaseURL() + "rest/myresource");
}
}
#Override
public void onOpen(EventSource eventSource) {
Window.alert("Open");
}
#Override
public void onClose(EventSource eventSource) {
Window.alert("onClose");
}
#Override
public void onMessage(EventSource eventSource, String lastEventId, String type, String data) {
Window.alert("lastEventId: " + lastEventId);
Window.alert("type: " + type);
Window.alert("data: " + data);
}
#Override
public void onError(EventSource eventSource) {
Window.alert("onError");
}
my class implements EventSourceListener
But it does not work. Actually this code reacting only when connection is opened, but it is impossible to receive any message from server. Do somebody know how to deal the issue with receiving data on client using GWT?
There are so many methods exist in GWT for push back services like a GWT Event Services enter link description here
In order for the server to initiate a request to the client, you will need to use WebSockets, and experimental HTML5 feature currently only supported by Chrome.
Or, to simulate this kind of interaction, you can use Comet (long-polling), made available in GWT by the rocket-gwt project.
My Jgroups config file contains the protocol/config
<FD timeout="3000" max_tries="3" />
But how do I use this in the Java code. For example, if there is a cluster and when I detect a failure I want to call an external notifier service via a REST call, like /nodeDown/nodeID
I'm not able to find any java code which does this, all I see is message receive and send, is there a way I can implement this?
Thanks
Adding some more info
I have done the step of writing a RecieverAdpater and override the start, stop, send, recieve method. Please find some code here,
public void receive(Message msg) {
JGroupsDataPacket pckt = (JGroupsDataPacket) msg.getObject();
if ( pckt.getCmd().equals("cacheUpdate") ){
int uid = pckt.getAffectedUid();
cacheUpdateRoutine(uid);
}
if ( pckt.getCmd().equals("ack") ){
System.out.println("got the mesaage!");
}
logger.log(LogLevel.ERROR, "received msg from " + msg.getSrc() + ": " + msg.getObject());
}
public void send(JGroupsDataPacket pckt){
Message msg = new Message(null, null, pckt);
msg.setFlag(Message.Flag.RSVP);
try {
channel.send(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
I want to know where should I add code for example to handle the TimeOutException when I'm sending a message with the RSVP flag enabled. Another requirement is to know, which is the Java callback method which is called when SUSPECT(P) is triggered. I want to catch and handle the machine's going down, timout etc.
Is the viewAccepted() the only place where I can handle this? Is there a sample code around this?
Also is http://www.jgroups.org/manual/html/user-channel.html
the section 3. APIs give all java/programmatic things we can do with JGroups.
Thanks again
I found some documentation here, I think this is the class which I'm supposed to override
public interface MembershipListener {
void viewAccepted(View new_view);
void suspect(Object suspected_mbr);
void block();
void unblock();
}
OK, first off, you have a JChannel. You need to use it to register for view callbacks, like this:
JChannel ch;
ch.setReceiver(this);
'this' extends ReceiverAdapter and overrides viewAccepted():
public void viewAccepted(View view) {
// handle new view
}
To determine the members which left between views v1 and v2:
List<Address> left_mbrs=View.leftMembers(v1,v2);