本文介绍了WearListenerService onDataChanged奇怪的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要让Android Wear和手持设备之间的双向数据传输。一切似乎是不错的,除了在手持触发onDataChanged。它触发才把我插上\出USB连接线,连接到PC。所以,我不明白为什么它的发生。

I want to make bidirectional data transfer between Android Wear and Handheld.All seems to be good except triggering onDataChanged on Handheld. It triggers only then I plug in\out USB cable, connected to the PC. So I don't understand why it's happen.

下面是我的code:

WearListenerService在手持设备:

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;

import java.util.List;

import ru.orangesoftware.financisto.db.DatabaseAdapter;
import ru.orangesoftware.financisto.model.Category;
import ru.orangesoftware.financisto.model.CategoryTree;
import ru.orangesoftware.financisto.utils.Log;

public class WearService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener
{
    private static final String WEARABLE_DATA_PATH = "/wearable_data";
    private static final String HANDHELD_DATA_PATH = "/handheld_data";

    private SendToDataLayerThread s;
    GoogleApiClient googleClient;

    private DatabaseAdapter db;

    @Override
    public void onCreate()
    {
        super.onCreate();

        Log.d("WearService Created");
        db = new DatabaseAdapter(this);
        db.open();

        initGoogleApiClient();
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents)
    {
        Log.d("In dataChanged");

        DataMap dataMap;
        for (DataEvent event : dataEvents)
        {

            // Check the data type
            if (event.getType() == DataEvent.TYPE_CHANGED)
            {
                // Check the data path
                String path = event.getDataItem().getUri().getPath();
                if (path.equals(HANDHELD_DATA_PATH))
                {
                    dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
                    Log.v("Path phone: " + path);
                    Log.v("DataMap received from watch: " + dataMap);

                    Intent messageIntent = new Intent();
                    messageIntent.setAction(Intent.ACTION_SEND);
                    messageIntent.putExtra("time", System.currentTimeMillis());
                    messageIntent.putExtra("DataMap", dataMap.toBundle());
                    LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);

                    // Create a DataMap object and send it to the data layer
                    dataMap = new DataMap();
                    dataMap.putString("Pong", "Pong" + String.valueOf(System.currentTimeMillis()));
                    dataMap.putLong("time", System.currentTimeMillis());

                    //Requires a new thread to avoid blocking the UI
                    s = new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap);
                    s.start();
                }
            }
        }
    }

    private void initGoogleApiClient()
    {
        // Build a new GoogleApiClient for the the Wearable API

        Log.d("Initialaizing GoogleClient");

        if (googleClient == null)
        {
            googleClient = new GoogleApiClient.Builder(this)
                    .addApi(Wearable.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();
        }

        if (!googleClient.isConnected())
        {
            Log.d("Tring to connect to GoogleApi...");

            googleClient.connect();

        }

        Log.d("Google Client ID = " + googleClient.toString());
    }

    // Disconnect from the data layer when the Activity stops
    @Override
    public void onDestroy()
    {
        super.onDestroy();

        Log.d("WearService: onDestroy");

        if (null != googleClient && googleClient.isConnected())
        {
            googleClient.disconnect();
        }

        if (db != null)
        {
            db.close();
        }

    }



  @Override
public void onConnected(Bundle bundle)
{
    Log.d("onConnected entered");
    Log.d("GoogleAPI now status:" + googleClient.isConnected());
}

    @Override
    public void onConnectionSuspended(int i)
    {

    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        Log.e("Connection to google api has failed. " + result.getErrorMessage());
    }

    class SendToDataLayerThread extends Thread
    {
        String path;
        DataMap dataMap;

        // Constructor for sending data objects to the data layer
        SendToDataLayerThread(String p, DataMap data)
        {
            path = p;
            dataMap = data;
        }

        public void run()
        {
            NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient).await();
            for (Node node : nodes.getNodes())
            {

                // Construct a DataRequest and send over the data layer
                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("DataMap: " + dataMap + " sent to: " + node.getDisplayName() + "; path=" + path);
                } else
                {
                    // Log an error
                    Log.v("ERROR: failed to send DataMap");
                }
            }
        }
    }
}

WearListenerService磨损

import android.content.Intent;
import android.os.Bundle;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;

public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener
{
    private static final String WEARABLE_DATA_PATH = "/wearable_data";
    private static final String HANDHELD_DATA_PATH = "/handheld_data";

    GoogleApiClient googleClient;

    private SendToDataLayerThread s;

    @Override
    public void onDataChanged(DataEventBuffer dataEvents)
    {
        Log.d("In dataChanged");

        DataMap dataMap;
        for (DataEvent event : dataEvents)
        {
            // Check the data type
            if (event.getType() == DataEvent.TYPE_CHANGED)
            {
                // Check the data path
                String path = event.getDataItem().getUri().getPath();
                Log.d("DataChanged: " + "path = " + path);
                if (path.equals(WEARABLE_DATA_PATH))
                {
                    dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
                    Log.d("DataChanged: " + "dataMap received on watch: " + dataMap);
                }

            }
        }
    }

    private void initGoogleApiClient()
    {
        if (googleClient == null)
        {
            Log.d("Building google client id...");
            googleClient = new GoogleApiClient.Builder(this)
                    .addApi(Wearable.API)
                            .addConnectionCallbacks(this)
                            .addOnConnectionFailedListener(this)
                    .build();

            Log.d("Google client id = " + googleClient.toString());
        }

        if (!googleClient.isConnected())
        {
            googleClient.connect();
        }

        Log.d("Google Client ID = " + googleClient.toString());
    }

    // Placeholders for required connection callbacks
    @Override
    public void onConnectionSuspended(int cause)
    {
    }

    @Override
    public void onConnected(Bundle connectionHint)
    {
        Log.v("OnConnected entered");
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult)
    {
    }

    // Connect to the data layer when the Activity starts
    @Override
    public void onCreate()
    {
        super.onCreate();
        initGoogleApiClient();
    }

    // Disconnect from the data layer when the Activity stops
    @Override
    public void onDestroy()
    {
        if (null != googleClient && googleClient.isConnected())
        {
            Log.d("onDestroy: Disconnecting googleClient");
            googleClient.disconnect();
        }

        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startid)
    {
        Log.d("onStartCommand: Service was started.");

        // Create a DataMap object and send it to the data layer
        DataMap dataMap = new DataMap();
        dataMap.putString("ping", "ping" + String.valueOf(System.currentTimeMillis()));
        dataMap.putLong("time", System.currentTimeMillis());
        //Requires a new thread to avoid blocking the UI

        s = new SendToDataLayerThread(HANDHELD_DATA_PATH, dataMap);
        s.start();

        return super.onStartCommand(intent, flags, startid);
    }

    class SendToDataLayerThread extends Thread
    {
        String path;
        DataMap dataMap;

        // Constructor for sending data objects to the data layer
        SendToDataLayerThread(String p, DataMap data)
        {
            path = p;
            dataMap = data;
        }

        public void run()
        {
            NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient).await();
            for (Node node : nodes.getNodes())
            {

                final Node node2 = node;

                // Construct a DataRequest and send over the data layer
                PutDataMapRequest putDMR = PutDataMapRequest.create(path);
                putDMR.getDataMap().putAll(dataMap);
                PutDataRequest request = putDMR.asPutDataRequest();

                PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(googleClient, request);
                pendingResult.setResultCallback(new ResultCallback<DataApi.DataItemResult>()
                {
                    @Override
                    public void onResult(DataApi.DataItemResult dataItemResult)
                    {
                        if (dataItemResult.getStatus().isSuccess())
                        {
                            Log.v("DataMap: " + dataMap + " sent to: " + node2.getDisplayName());
                        } else
                        {
                            // Log an error
                            Log.v("ERROR: failed to send DataMap");
                        }
                    }
                });


            }
        }
    }
}

在两个手持设备主要活动和磨损刚开始服务。数据路径是:1)磨损服务发送数据。 onDataChanged磨损引发的,因为它应该2)手持式触发器onDataChanged只有拔掉后或插入USB电缆。手持设备将数据发送到磨损。3)磨损onDataChanged触发,因为它应该和接收数据。

Main activities on both Handheld and Wear just start services.Data path is:1) Wear service send data. onDataChanged on wear triggered as it should2) Handheld triggers onDataChanged only after unplug or plug USB cable. Handheld send data to wear.3) onDataChanged triggers on wear as it should and receive data.

附加信息。清单手持设备:

Additional info.Manifest Handheld:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="ru.orangesoftware.financisto"
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:installLocation="internalOnly">

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:resizeable="true"
        android:smallScreens="true"/>

    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false"/>
    <uses-feature
        android:name="android.hardware.camera"
        android:required="false"/>
    <uses-feature
        android:name="android.hardware.location"
        android:required="false"/>
    <uses-feature
        android:name="android.hardware.location.network"
        android:required="false"/>
    <uses-feature
        android:name="android.hardware.location.gps"
        android:required="false"/>

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
    <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:allowBackup="true"
        android:description="@string/app_description"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.DeviceDefault">


        <uses-library
            android:name="com.google.android.maps"
            android:required="false"/>
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>
        <activity
        android:name=".activity.MainActivity"
        android:configChanges="orientation|keyboardHidden"
        android:label="@string/app_name"
        android:taskAffinity=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

        <service
            android:name=".service.WearService">
            <intent-filter>
                <action android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
            </intent-filter>
        </service>

    </application>

</manifest> 

清单磨损:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="ru.orangesoftware.financisto"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-feature android:name="android.hardware.type.watch"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.DeviceDefault">

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>

        <activity
            android:name=".MainWearActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <service
            android:name="ru.orangesoftware.financisto.ListenerService"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
            </intent-filter>
        </service>


    </application>

</manifest>

摇篮手持

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

repositories {
    maven { url "http://repo.commonsware.com.s3.amazonaws.com" }
    maven { url "https://repository-achartengine.forge.cloudbees.com/snapshot/" }
    mavenCentral()
}

android {
    compileSdkVersion 22
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "ru.orangesoftware.financisto"
        minSdkVersion 19
        targetSdkVersion 22
        versionCode 92
        versionName "1.6.8"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
    }
}

def googlePlayVersion = '8.3.0'

dependencies {
    compile "com.google.android.gms:play-services-base:$googlePlayVersion"
    compile "com.google.android.gms:play-services-drive:$googlePlayVersion"
    compile "com.google.android.gms:play-services-wearable:$googlePlayVersion"

    compile files('libs/dropbox-android-sdk-1.6.1/dropbox-android-sdk-1.6.1.jar')
    compile files('libs/google-rfc-2445/rfc2445-no-joda.jar')
    compile 'com.google.code.gson:gson:2.3'
    compile 'com.commonsware.cwac:wakeful:1.0.1'
    compile 'org.achartengine:achartengine:1.2.0'
    compile 'net.sf.trove4j:trove4j:3.0.3'
    compile 'com.wdullaer:materialdatetimepicker:2.0.0'
}

摇篮穿

apply plugin: 'com.android.application'


android {
    compileSdkVersion 22
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "ru.orangesoftware.financisto"
        minSdkVersion 20
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

def googlePlayVersion = '8.3.0'

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.google.android.support:wearable:1.3.0'
    compile "com.google.android.gms:play-services-wearable:$googlePlayVersion"
}

在手持设备的应用程序启动后登录

11-15 12:20:20.616 29043-29043/? D/Financisto: WearService Created [WearService.onCreate:44]
11-15 12:20:20.616 29043-29043/? D/Financisto: Initialaizing GoogleClient [WearService.initGoogleApiClient:94]
11-15 12:20:20.636 29043-29043/? D/Financisto: Tring to connect to GoogleApi... [WearService.initGoogleApiClient:107]
11-15 12:20:20.636 29043-29043/? D/Financisto: Google Client ID = com.google.android.gms.internal.zzmg@4344d5c0 [WearService.initGoogleApiClient:113]
11-15 12:20:21.016 29043-29043/ru.orangesoftware.financisto D/Financisto: onConnected entered [WearService.onConnected:139]
11-15 12:20:21.016 29043-29043/ru.orangesoftware.financisto D/Financisto: GoogleAPI now status:true [WearService.onConnected:140]

-------now I send data from watch and unplug usb cable after 30 seconds

11-15 12:24:31.986 29043-29091/? D/Financisto: In dataChanged [WearService.onDataChanged:54]
11-15 12:24:31.986 29043-29091/? V/Financisto: Path phone: /handheld_data [WearService.onDataChanged:68]
11-15 12:24:31.986 29043-29091/? V/Financisto: DataMap received from watch: {time=1447565065308, ping=ping1447565065306} [WearService.onDataChanged:69]
11-15 12:24:32.036 29043-29091/? D/Financisto: In dataChanged [WearService.onDataChanged:54]
11-15 12:24:32.046 29043-1493/? V/Financisto: DataMap: {Pong=Pong1447565071992, time=1447565071992} sent to: Gear 2 76A1; path=/wearable_data [SendToDataLayerThread.run:179]

登录应用后磨损启动和数据发送:

11-15 12:24:25.301 2460-2460/ru.orangesoftware.financisto D/FinancistoWear: onStartCommand: Service was started.
11-15 12:24:25.377 2460-2460/ru.orangesoftware.financisto V/FinancistoWear: DataMap: {time=1447565065308, ping=ping1447565065306} sent to: Tolive GN3
11-15 12:24:25.379 2460-3309/ru.orangesoftware.financisto D/FinancistoWear: In dataChanged
11-15 12:24:25.379 2460-3309/ru.orangesoftware.financisto D/FinancistoWear: DataChanged: path = /handheld_data

请,指向我,我在做什么错了?

Please, point me, what I'm doing wrong?

解决方案

我重写SendToDataLayerThread。现在是一个普通的类没有扩展Thread和DataRequest成为急:

I rewrite SendToDataLayerThread. Now it is a regular class without extending Thread and DataRequest became Urgent:

class SendToDataLayerThread
    {
        String path;
        DataMap dataMap;

        // Constructor for sending data objects to the data layer
        SendToDataLayerThread(String p, DataMap data)
        {
            path = p;
            dataMap = data;
        }

        public void run()
        {
            //NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient);
            PendingResult<NodeApi.GetConnectedNodesResult> nodes = Wearable.NodeApi.getConnectedNodes(googleClient);
            nodes.setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>()
            {
                @Override
                public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult)
                {
                    for (Node node : getConnectedNodesResult.getNodes())
                    {

                        final Node node2 = node;

                        // Construct a DataRequest and send over the data layer
                        PutDataMapRequest putDMR = PutDataMapRequest.create(path);
                        putDMR.getDataMap().putAll(dataMap);
                        PutDataRequest request = putDMR.asPutDataRequest();
                        request.setUrgent();

                        PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(googleClient, request);
                        pendingResult.setResultCallback(new ResultCallback<DataApi.DataItemResult>()
                        {
                            @Override
                            public void onResult(DataApi.DataItemResult dataItemResult)
                            {
                                if (dataItemResult.getStatus().isSuccess())
                                {
                                    Log.v("DataMap: " + dataMap + " sent to: " + node2.getDisplayName());
                                } else
                                {
                                    // Log an error
                                    Log.v("ERROR: failed to send DataMap");
                                }
                            }
                        });
                    }
                }
            });
        }
    }

感谢您的帮助!

Thanks for help!

推荐答案

占的:

通过谷歌Play业务8.3,我们已经更新了DataApi,以便紧迫性如何的数据项同步。现在,一个优先级可以加到该数据项以确定何时应该进行同步。例如,如果您正在构建一个应用程序,需要立即同步,如遥控器的应用程序,它仍然可以立即致电setUrgent()来实现,但是对于一些如更新您的联系人,你可以容忍一些延迟。 非紧急DataItems可能会延迟长达30分钟,但你可以期望,在大多数情况下,他们会在几分钟内交付。 低优先级现在是默认值,所以<一href="https://developers.google.com/android/reference/com/google/android/gms/wearable/PutDataRequest?utm_campaign=play%20services_discussion_google_apis_110515&utm_source=anddev&utm_medium=blog#setUrgent()"相对=nofollow> setUrgent()的需要,得到previous定时

所以一定要叫<一href="https://developers.google.com/android/reference/com/google/android/gms/wearable/PutDataRequest?utm_campaign=play%20services_discussion_google_apis_110515&utm_source=anddev&utm_medium=blog#setUrgent()"相对=nofollow> setUrgent()对数据的请求,如果你希望他们立即同步到其他连接设备。

这篇关于WearListenerService onDataChanged奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 19:53