PubNub在工作线程上

Ant*_*ith 5 multithreading android google-maps pubnub

TL; DR见下文

我的Android应用程序的核心功能是在前台服务中广播用户的当前位置,该服务在从活动中解除绑定后继续运行.在发布到频道和从频道接收数据的订阅者方面,我的一切工作正常.服务很好.我甚至动画谷歌地图相机,以遵循从订阅的消息收到的位置.

我担心的是我收到这条消息:

I/Choreographer: Skipped 49 frames!  The application may be doing too much work on its main thread.
Run Code Online (Sandbox Code Playgroud)

我当然研究过这条消息.很多人似乎都说它与动画有关,所以我认为它与地图有关,因为它是唯一动画的东西.虽然,我也了解到编舞者可以因为其他原因而产生这个信息.

当我的应用程序启动时,它会启动一个前台服务,该服务使用GoogleAPIClient连接到谷歌位置服务.初始化后,我立即请求我当前的位置并使用PubNub将lng和lat广播到一个频道.然后我订阅该频道,当收到消息时,我的MapFragmentPresenter类会侦听来自服务的位置更新.然后,演示者调用MapFragment的视图(MVP中的V)来为摄像机设置动画并将标记放置在每个新位置.

这一切都很好.我只是想确保我没有引起跳过的帧并且没有在主线程上放太多工作.考虑到我计划在其上做的所有其他事情,我现在在主线程上做的很少.现在我只是不断地重新定位相机以跟随设备的当前位置,我认为非常基本.

此外,我没有使用任何唤醒锁功能,但我的PubNub广播工作正常.为什么是这样?我读到某个地方,当设备被锁定时使用PubNub运行需要这个,但我的工作没有它.

对不起,很长的帖子.

注意:我没有大型资源文件.除了从AS本身导入的图标之外,我甚至没有添加任何其他内容.

TL; DR 我似乎在我的主线程上做了太多.谷歌位置服务和PubNub操作可以在服务中的不同线程上完成,这将解决我的问题吗?

问题:

  1. 应该/我可以在工作线程上执行所有位置请求吗?
  2. 应该/可以将PubNub操作放在自己的线程上吗?
  3. 我做得不好吗?
  4. 当设备处于睡眠/锁定状态时,我的前台服务似乎工作得很好,但我根本没有弄乱WAKE_LOCK.我是不是该?当我的服务似乎正在做我期望的一切时,操纵锁定状态的区别是什么?

这是一些代码:

感谢您抽出宝贵的时间!

MapViewFragment

public class MapViewFragment extends Fragment
        implements OnMapReadyCallback, IMapFragment {

    private static final String TAG = "MAP_VIEW_FRAGMENT";

    private MapView mapView;
    private GoogleMap gMap;
    private IMapPresenter presenter;
    private boolean mapReady;
    private Handler handler;
    private LatLng myLocation;


    //ToDo: newInstance method

    //==========================
    //Fragment Lifecycle
    //==========================
    @Override @Nullable
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        mapReady = false;
        presenter = new MapPresenter(this);
        View v = inflater.inflate(R.layout.map_view, container, false);
        handler = new Handler(Looper.getMainLooper());

        mapView = (MapView) v.findViewById(R.id.mapview);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(this);

        return  v;
    }

    @Override
    public void onResume() {
        super.onResume();
        mapView.onResume();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }


    public MapPresenter getPresenter(){
        return (MapPresenter) presenter;
    }


    //==========================
    //Map
    //==========================
    @Override
    public void onMapReady(GoogleMap googleMap) {

        this.gMap = googleMap;
        mapReady = true;

    }


    @Override
    public void moveToMyLocation(final LatLng locData) {

        handler.post(new Runnable() {
            @Override
            public void run() {
                gMap.addMarker(new MarkerOptions().position(locData).title("myLocation"));
                gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(locData,20));
                Log.d(TAG,"//////////////////moveToMyLocation");

            }
        });

    }

}
Run Code Online (Sandbox Code Playgroud)

服务

public class MapService extends Service implements
        GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
        LocationListener {

    private static final String TAG = "MAP_VIEW_SERVICE";

    private int REQUEST_CODE = 101;
    private int NOTIFICATION_ID = 102;

    private LocationRequest gLocationRequest;
    private GoogleApiClient gApiClient;

    private Pubnub mPubnub;

    private Location lastLocation;
    private String mapFragTag;

    private final IBinder mBinder = new LocalBinder();
    private LatLng mLatLng;

    private ServiceRequestListener requestListener;

    //==========================
    //Service Lifecycle
    //==========================
    @Override
    public void onCreate() {
        super.onCreate();

        gLocationRequest = LocationRequest.create();
        gLocationRequest.setInterval(5000);
        gLocationRequest.setFastestInterval(5000);
        gLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        gApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

        mPubnub = new Pubnub(
                getString(R.string.pubnub_publish_key)
                ,getString(R.string.pubnub_subscribe_key));

        try{
            mPubnub.subscribe("Channel-d2160eqlk",subscribeCallback);
        }catch (PubnubException e) {
            Log.e("**MapService**", e.toString());
        }

        gApiClient.connect();
        setupAndLaunchForeground();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
            return START_STICKY;
}

    @Nullable @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(gApiClient.isConnected()) {
            gApiClient.disconnect();
        }
    }


    public void setRequestListener(ServiceRequestListener requestListener) {
        this.requestListener = requestListener;
    }


    //==========================
    //StartForeground
    //==========================
    private void setupAndLaunchForeground() {

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Service Running")
                .setTicker("AppName Services Initiated")
                .setWhen(System.currentTimeMillis())
                .setOngoing(true);

        Intent startIntent = new Intent(this, MapViewFragment.class);

        PendingIntent contentIntent = PendingIntent.getActivity(this,
                REQUEST_CODE, startIntent, 0);

        builder.setContentIntent(contentIntent);

        Notification notification = builder.build();

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(NOTIFICATION_ID, notification);

        startForeground(NOTIFICATION_ID,notification);

    }


    //==========================
    //Google API Client
    //==========================
    @Override
    public void onConnected(@Nullable Bundle bundle) {

        PackageManager manager = getPackageManager();
        if(manager.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION,"com.firsttread.appname")
                == PackageManager.PERMISSION_GRANTED){

            LocationServices.FusedLocationApi.requestLocationUpdates(gApiClient, gLocationRequest, this);
            lastLocation = LocationServices.FusedLocationApi.getLastLocation(gApiClient);
        }

    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }


    //==========================
    //Location
    //==========================
    @Override
    public void onLocationChanged(Location location) {

        broadcastLocation(location);
        this.lastLocation = location;

        Log.d("****LocationChange****","Lat: " + location.getLatitude() + "Lng: " + location.getLongitude());

    }


    //==========================
    //PubNub
    //==========================
    private void broadcastLocation(Location location){

        JSONObject message = new JSONObject();

        try{
            message.put("lat", location.getLatitude());
            message.put("lng", location.getLongitude());
        }catch (JSONException e){
            Log.e("MapService", e.toString());
        }

        mPubnub.publish("ChannelName", message, publishCallback);

    }

    Callback publishCallback = new Callback() {
        @Override
        public void successCallback(String channel, Object response) {
            Log.d("**PUBNUB**", response.toString());
        }

        @Override
        public void errorCallback(String channel, PubnubError error) {
            Log.e("**PUBNUB**", error.toString());
        }
    };

    Callback subscribeCallback = new Callback() {

        @Override
        public void successCallback(String channel, Object message) {

            JSONObject jsonMessage = (JSONObject) message;
            try {
                double mLat = jsonMessage.getDouble("lat");
                double mLng = jsonMessage.getDouble("lng");

                if(requestListener != null){
                    sendLocation(new LatLng(mLat,mLng));
                }


            } catch (JSONException e) {
                Log.e("**PUBNUB_ERROR**", e.toString());
            }

        }
    };


    //==========================
    //Location Data Methods
    //==========================
    private void sendLocation(LatLng locData){
        requestListener.retrieveLocation(locData);
    }


    //==========================
    //MapInterface
    //==========================
    public interface ServiceRequestListener {
        void retrieveAppNameLocations(HashMap<String,Long> memberLocations);
        void retrieveLocation(LatLng locData);
    }

    //==========================
    //ServiceBinder
    //==========================
    public class LocalBinder extends Binder {
        public MapService getService() {
            return MapService.this;
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

Cra*_*ver 0

对你的问题的一些回答:

1. 我应该/可以在工作线程上执行所有位置请求吗? 除了订阅将发布位置数据的频道之外,您不需要做任何特殊的事情。

2. PubNub 操作应该/可以在自己的线程上吗? 它们将是,只使用异步 API,而不是同步 API(无论如何,如果没有额外的工作,您就不能在 Android 中使用同步,否则 Android 将抛出异常)。

3.我有什么做得不好的地方吗?当设备处于睡眠/锁定状态时,我的前台服务似乎工作得很好,但我根本没有搞乱 WAKE_LOCK。我是不是该? 当您提出这个问题时,您可能已经能够配置 WAKE_LOCK,但在最新的 Android 操作系统中可能不再被允许(也许没有最终用户的额外权限),但这并不重要。只需在应用程序处于后台时使用推送通知即可。

4. 当我的服务似乎正在执行我期望的所有操作时,操作锁定状态有什么不同? 不太确定你在这里的意思,所以需要更多细节。

如果您仍然遇到上述问题,请向 PubNub 支持提交完整详细信息。发送压缩的示例项目(如果可能)、您的 PubNub 子密钥和捕获您遇到问题的任何场景的 PubNub SDK 日志。