TL; DR见下文
我的Android应用程序的核心功能是在前台服务中广播用户的当前位置,该服务在从活动中解除绑定后继续运行。在发布到频道和从频道接收数据的订阅者方面,我的一切工作正常。服务很好。我甚至设置了谷歌地图相机的动画,以便按照订阅信息中的位置进行操作。
我担心的是,我收到了这条消息:
I/Choreographer: Skipped 49 frames! The application may be doing too much work on its main thread.
我当然研究了这条消息。很多人似乎都说它与动画有关,所以我认为它与地图有关,因为它是唯一动画的东西。虽然,我也了解到编舞者可以因其他原因而产生这种信息。
当我的应用程序启动时,它会启动一个前台服务,该服务使用GoogleAPIClient连接到谷歌位置服务。初始化后,我立即请求我当前的位置并使用PubNub将lng和lat广播到一个频道。然后我订阅该频道,当收到消息时,我的MapFragmentPresenter类会侦听来自服务的位置更新。然后,演示者调用MapFragment的视图(MVP中的V)来为摄像机设置动画并将标记放置在每个新位置。
这一切都很好。我只是想确保我没有引起跳过的帧而不是在主线程上做太多工作。考虑到我计划在其上做的所有其他事情,我现在对主线程做的很少。现在我只是不断地重新定位相机以跟随设备的当前位置,我认为这是非常基本的。
另外,我没有使用任何唤醒锁功能,但我的PubNub广播工作正常。为什么是这样?我在某个地方看到,当设备被锁定时,使用PubNub运行需要这个,但我的工作没有它。
很抱歉这篇长篇文章。
注意:我没有大型资源文件。除了从AS本身导入的图标之外,我甚至还没有添加任何其他内容。
TL; DR 我似乎在主线程上做了太多。谷歌位置服务和PubNub操作可以在服务中的不同线程上完成,这将解决我的问题吗?
问题:
以下是一些代码:
感谢您抽出宝贵时间!
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");
}
});
}
}
服务
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;
}
}
}
答案 0 :(得分:0)
您的问题的一些答案:
<强> 1。应该/我可以在工作线程上执行所有位置请求吗? 除了订阅将发布位置数据的频道之外,您不需要做任何特殊的事情。
<强> 2。应该/可以将PubNub操作放在他们自己的线程上吗? 他们将只使用异步API,而不是同步API(你不能在没有额外工作的情况下在Android中使用同步,否则Android会抛出异常)。
第3。我做得不好吗?当设备处于睡眠/锁定状态时,我的前台服务似乎工作得很好,但我根本没有弄乱WAKE_LOCK。我应该吗? 当你提出这个问题时,你可能已经配置了WAKE_LOCK,但可能不再允许在Android操作系统中使用(可能没有最终用户的额外权限),但这并不重要。只需在app处于后台时使用推送通知。
<强> 4。当我的服务似乎正在做我期望的一切时,操纵锁定状态的区别是什么? 不太确定你的意思,所以需要更多细节。
如果您仍然遇到上述问题,请submit full details to PubNub Support。发送样本项目压缩(如果可能),PubNub子键和PubNub SDK logs that captures any scenarios您遇到问题。