首页 > 解决方案 > Android 地图 - 跳帧!应用程序可能在其主线程上做了太多工作

问题描述

我正在开发一个电子商务应用程序,我必须获取用户的位置。我使用 Google Maps 的 Places Picker API 来完成这些任务。有一段时间一切都很好,但现在我突然收到以下错误消息:

I/Choreographer(691):跳过55帧!应用程序可能在其主线程上做了太多工作

前两个活动工作正常,错误消息仅在地图活动开始时出现。地图屏幕开始闪烁,应用程序返回主活动。该错误是随机发生的,并且不会一直发生。有时它工作正常,有时它会出现问题。

在这里,我把我的整个地图代码:

  public class LocationActivity extends AppCompatActivity implements OnMapReadyCallback,GoogleApiClient.OnConnectionFailedListener{

        ArrayList<Products> products_list;
        //products_list =

SharedPrefManager.getInstance(getApplicationContext()).GetCart();

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

}

@Override
public void onMapReady(GoogleMap googleMap) {
    Log.i(TAG, "onMapReady: Map is ready");
    Toast.makeText(this, "Map is Ready", Toast.LENGTH_SHORT).show();
    mMap = googleMap;

    if (mLocationPermissionGranted) {
        getDeviceLocation();

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            return;
        }
        mMap.setMyLocationEnabled(true);
        mMap.getUiSettings().setMyLocationButtonEnabled(false);
        Init();
    }
}

private static final String TAG = "MapActivity";
private static final String FINE_LOCATION=Manifest.permission.ACCESS_FINE_LOCATION;
private static final String COARSE_LOCATION=Manifest.permission.ACCESS_COARSE_LOCATION;
private static final int mLocationPermissionRequestCode = 1234;
private static final float DEFAULT_ZOOM = 15f;
protected GeoDataClient mGeoDataClient;
private static final LatLngBounds LAT_LNG_BOUNDS = new LatLngBounds(new LatLng(5,79),new LatLng(10,82));
private static final int PLACE_PICKER_REQUEST = 1;

//widgets
private AutoCompleteTextView mSearch_text;
private ImageView mGps,mPicker;
private Button button;

//vars
private Boolean mLocationPermissionGranted = false;
private GoogleMap mMap;
private FusedLocationProviderClient mFusedLocationProviderClient;
private PlaceAutocompleteAdapter placeAutocompleteAdapter;
private GoogleApiClient mGoogleApiClient;
private LatLng selectedLatLng;
private String selectedname;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_location);

    // Construct a GeoDataClient.
    mGeoDataClient = Places.getGeoDataClient(this, null);

    button=findViewById(R.id.btn_confirm);
    mSearch_text = findViewById(R.id.search_text);
    mGps = findViewById(R.id.ic_gps);
    mPicker = findViewById(R.id.ic_picker);


    getPermissionAccess();

}


private void Init(){
    Log.i(TAG, "Init: Initializing");

    mGoogleApiClient = new GoogleApiClient
            .Builder(this)
            .addApi(Places.GEO_DATA_API)
            .addApi(Places.PLACE_DETECTION_API)
            .enableAutoManage(this, this)
            .build();

    mSearch_text.setOnItemClickListener(mAutocompleteAdapterViewListener);


    placeAutocompleteAdapter = new PlaceAutocompleteAdapter(this,mGeoDataClient,LAT_LNG_BOUNDS,null);

    mSearch_text.setAdapter(placeAutocompleteAdapter);

    mSearch_text.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if(actionId == EditorInfo.IME_ACTION_SEARCH
                    || actionId == EditorInfo.IME_ACTION_DONE
                    || event.getAction() == event.ACTION_DOWN
                    || event.getAction() == event.KEYCODE_ENTER){
                //Method for search
                geoLocate();

            }
            return false;
        }
    });
    mGps.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Log.i(TAG, "onClick: gps icon clicked");
            getDeviceLocation();
        }
    });

    mPicker.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();

            try {
                startActivityForResult(builder.build(LocationActivity.this), PLACE_PICKER_REQUEST);
            } catch (GooglePlayServicesRepairableException e) {
                e.printStackTrace();
            } catch (GooglePlayServicesNotAvailableException e) {
                e.printStackTrace();
            }
        }
    });

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            NextActivity();
        }
    });

}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PLACE_PICKER_REQUEST) {
        if (resultCode == RESULT_OK) {
            Place place = PlacePicker.getPlace(this,data);
            String toastMsg = String.format("Place: %s", place.getName());
            Toast.makeText(this, toastMsg, Toast.LENGTH_LONG).show();

            PendingResult<PlaceBuffer>  placeResult = Places.GeoDataApi.getPlaceById(mGoogleApiClient,place.getId());
            placeResult.setResultCallback(mUpdatePlaceDetailsCallback);
        }
    }
}

private void geoLocate(){
    Log.i(TAG, "geoLocate: geolocating");
    String searchstring = mSearch_text.getText().toString();
    Geocoder geocoder = new Geocoder(LocationActivity.this);
    List<Address> list = new ArrayList<>();
    try{
        list = geocoder.getFromLocationName(searchstring,1);
    }catch (IOException e)
    {
        Log.i(TAG, "geoLocate: IOException"+ e.getMessage());
    }
    if(list.size()>0){
        Address address = list.get(0);
        Log.i(TAG, "geoLocate: Found LocationActivity"+ address.toString());
        MoveCamera(new LatLng(address.getLatitude(),address.getLongitude()),DEFAULT_ZOOM,
                address.getAddressLine(0));

    }
}

private void getDeviceLocation(){
    Log.i(TAG, "getDeviceLocation: Getting Device LocationActivity");
    mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    try{
        if(mLocationPermissionGranted){
            Task location =mFusedLocationProviderClient.getLastLocation();
            location.addOnCompleteListener(new OnCompleteListener() {
                @Override
                public void onComplete(@NonNull Task task) {
                    if(task.isSuccessful()){
                        Log.i(TAG, "onComplete: LocationActivity Found");
                        android.location.Location currentLocation = (android.location.Location) task.getResult();

                        MoveCamera(new LatLng(currentLocation.getLatitude(),currentLocation.getLongitude()),DEFAULT_ZOOM
                                ,"My LocationActivity");

                    }
                    else {
                        Log.i(TAG, "onComplete: LocationActivity Null");
                        Toast.makeText(LocationActivity.this, "Unable to get LocationActivity", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }

    } catch (SecurityException e){
        Log.i(TAG, "getDeviceLocation: SecurityException: "+e.getMessage());
    }


}

private void MoveCamera(LatLng latLng , float zoom, String title){
    Log.i(TAG, "MoveCamera: Moving Camera to lat: "+latLng.latitude+" ,lng: "+latLng.longitude);
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,zoom));

    mMap.clear();

    if(!title.equals("My LocationActivity")){
        MarkerOptions markerOptions = new MarkerOptions()
                .position(latLng)
                .title(title);
        mMap.addMarker(markerOptions);
    }



}

private void InitMap(){
    Log.i(TAG, "InitMap: Initilizing Map");
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(LocationActivity.this);
}

private void getPermissionAccess(){
    Log.i(TAG, "getPermissionAccess: Getting LocationActivity permissions");
    String[] permissions = {FINE_LOCATION,COARSE_LOCATION};
    if(ContextCompat.checkSelfPermission(this.getApplicationContext(),FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
        if(ContextCompat.checkSelfPermission(this.getApplicationContext(),COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
            mLocationPermissionGranted = true;
            InitMap();
        } else {
            ActivityCompat.requestPermissions(this,permissions,mLocationPermissionRequestCode);
        }
    } else {
        ActivityCompat.requestPermissions(this,permissions,mLocationPermissionRequestCode);
    }

}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Log.i(TAG, "onRequestPermissionsResult: Called");
    mLocationPermissionGranted = false;
    switch (requestCode){
        case mLocationPermissionRequestCode:{
            if(grantResults.length>0){
                for(int i=0; i<grantResults.length; i++){
                    if(grantResults[i]!= PackageManager.PERMISSION_GRANTED){
                        mLocationPermissionGranted=false;
                        Log.i(TAG, "onRequestPermissionsResult: Permission Denied.");
                        Log.i(TAG, "onRequestPermissionsResult:"+grantResults[i]);
                        return;
                    }
                }
                mLocationPermissionGranted=true;
                Log.i(TAG, "onRequestPermissionsResult: Permission Granted");
                //initialization of Map
                InitMap();
            }
        }
    }
}

/*
 google places api auto complete */

private AdapterView.OnItemClickListener mAutocompleteAdapterViewListener = new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        final AutocompletePrediction item = placeAutocompleteAdapter.getItem(position);
        final String placeid = item.getPlaceId();

        PendingResult<PlaceBuffer> placeResult = Places.GeoDataApi.getPlaceById(mGoogleApiClient,placeid);
        placeResult.setResultCallback(mUpdatePlaceDetailsCallback);

    }
};

private ResultCallback<PlaceBuffer> mUpdatePlaceDetailsCallback = new ResultCallback<PlaceBuffer>() {
    @Override
    public void onResult(@NonNull PlaceBuffer places) {

        if(!places.getStatus().isSuccess()){
            Log.i(TAG, "onResult: Place query did not complete"+places.getStatus().toString());
            places.release();
        }
        final Place place = places.get(0);
        Log.i(TAG, "onResult: Name:"+place.getName());
        Log.i(TAG, "onResult: Latitude:"+place.getLatLng().latitude);
        Log.i(TAG, "onResult: Longtitude:"+place.getLatLng().longitude);

        selectedname=place.getName().toString();
        selectedLatLng=place.getLatLng();

        MoveCamera(selectedLatLng,DEFAULT_ZOOM,selectedname);
        places.release();
        Log.i(TAG, "onResult: Name:"+selectedname);
        Log.i(TAG, "onResult: Selected LAtLng"+selectedLatLng);
    }

};

private void NextActivity(){
    if(selectedLatLng!=null && !selectedname.equals("")){
        Intent intent = new Intent(getApplicationContext(),CheckoutActivity.class);
        SharedPrefManager.getInstance(getApplicationContext()).SaveLocation(selectedname,selectedLatLng);
        startActivity(intent);
    }
    else{
        showErrorMsg("Location Cannot be Empty");
    }
}
public void showErrorMsg(String message){
    new AlertDialog.Builder(this)
            .setTitle("Oops")
            .setMessage(message)
            .setPositiveButton(android.R.string.ok,null)
            .show();
}
}

标签: javaandroidgoogle-mapschoregraphe

解决方案


这是您需要开始进行一些挖掘的地方,以找到您的活动中的繁重工作并让 Thread/AyscTask/Worker 代替您的主线程来完成工作。这是一个警告/错误,因为您的主线程处理渲染应用程序的 GUI,并且您告诉它进行大量计算,从而使应用程序看起来像是被冻结了。

一旦你发现你的主线程正在做很多工作,你就可以创建一个线程和 Runnable 之类的东西,线程将在其上运行。

private Thread thread = null;
private final Runnable thread_DoWork = new Runnable() {
    @Override public void run() {
        // Your code here or call some function to run for the thread
        someHeavyLiftingFunction();
    }
};

下面是你如何创建并告诉线程开始处理你给它的 Runnable。

// Check if already created/started
if (thread == null) {
    // Create new thread
    thread = new Thread(thread_DoWork);
    // Start Thread in background
    thread.start();
}

差不多就是这样。您的主线程将被释放。还有一些其他类型的工作线程/线程具有更多内置功能,例如在线程完成工作时调用的回调函数(AsyncTask Android 示例)。


推荐阅读