简体   繁体   中英

No view found for id for fragment (in listView)

I'm a long time stackOverflow lurker and a first time poster so I apologize if I miss any steps or requirements. I have been stuck on this bug for 2 weeks now and have extensively searched for related bugs online but nothing has solved my problem so I'm hoping one of you guys can help shed some light on this! The weird thing about this is, it used to work and I've made no code changes so it's either an outdated API that I'm just not catching or something else.

I've got a ListView, and one of the list items holds a fragment with a map. When the ListView is loading, I get this crash:

> FATAL EXCEPTION: main
Process: com.example.dev , PID: 10386
java.lang.IllegalArgumentException: No view found for id 0x7f0d00a4 (com.example.dev:id/map_container) for fragment LocationMapFragment{4266c870 #1 id=0x7f0d00a4}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:939)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:454)
at android.os.Handler.handleCallback(Handler.java:733
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5872)
at java.lang.reflect.Method.invokeNative(Native Method
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1069)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:885)
at dalvik.system.NativeStart.main(Native Method)

Here is the list item that holds the fragment with the map:

package com.csf.ui.form;

import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;

import com.csf.R;
import com.csf.model.CSFormElement;
import com.csf.ui.form.location.FormLocationMapActivity;
import com.csf.ui.fragment.FormFragment;
import com.csf.ui.form.location.LocationMapFragment;
import com.csf.utils.Constants;

public class LocationFormCell extends FormCell {

    private LocationMapFragment locationFrag;

    public LocationFormCell(Context ctx, CSFormElement elem, FormFragment frag, boolean editable) {
        super(ctx, elem, frag, editable);
        View view  = LayoutInflater.from(ctx).inflate(R.layout.form_element_location, this);
        Button overlayButton;

        overlayButton = (Button) view.findViewById(R.id.overlayButton);
        setupOnClickListener(overlayButton);
        if (ctx instanceof FragmentActivity) {
            FragmentActivity act = (FragmentActivity) ctx;
            locationFrag = LocationMapFragment.newInstance(formElement.disp_name,false);
            FragmentTransaction ft = act.getSupportFragmentManager().beginTransaction();
            ft.add(R.id.map_container, locationFrag);
            ft.commitAllowingStateLoss();
            locationFrag.setValue(value);
        }
    }

    public void setupOnClickListener(Button overlayButton) {
        overlayButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent;
                formFragment.currentCell = LocationFormCell.this;
                intent = new Intent(formFragment.getActivity(),FormLocationMapActivity.class);
                intent.putExtra(FormLocationMapActivity.EXTRA_FORM_ELEMENT_ID,formElement.element_id);
                intent.putExtra(FormLocationMapActivity.EXTRA_LOCATION_VALUE,value);
                formFragment.startActivityForResult(intent,Constants.REQ_CODE_LOCATION);
            }
        });
    }

    @Override
    public void setValue(String value) {
        this.value = value;
        locationFrag.setValue(value);
        setInvalid(false);
    }

    @Override
    public void clearValue() {
        value = "";
        locationFrag.clearValue();
    }

    @Override
    public void setInvalid(boolean invalid) {
        // TODO Auto-generated method stub  
    }
}

here is the list item xml layout: form_element_location.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/containerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/map_container">
    </FrameLayout>

    <Button
        android:id="@+id/overlayButton"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"/>

    </FrameLayout>

Here is the LocationMapFragment.java

package com.csf.ui.form.location;

import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ZoomControls;

import com.csf.R;
import com.csf.model.CSGlobalSetting;
import com.csf.provider.DatabaseManager;
import com.csf.utils.GeoUtils;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.kaciula.utils.LogUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

public class LocationMapFragment extends Fragment implements OnMapClickListener,  OnMarkerClickListener, GoogleMap.OnMyLocationChangeListener {

    public static final String ARG_TITLE = "TITLE";
    public static final String ARG_FULLSCREEN = "FULLSCREEN";
    private String value;
    private Location currentLocation;
    private Location mItemLocation;
    private Marker mItemMarker;
    private Circle mItemRadiusCircle;
    private Polyline mPolyline;
    private double mLocationRadius;
    boolean mMapLayoutOccurred = false;
    boolean mGooglePlayServicesAvailable = false;
    private Date mGPSCheckDate;
    private boolean mUserInteracted = false;
    ImageView gpsIndicatorImageView;
    TextView titleLabel;
    TextView distanceLabel;
    TextView gpsWarningLabel;
    LinearLayout mapWrapperView;
    MapView mapView;
    LocationMapFragmentListener listener;

    public static LocationMapFragment newInstance(String title, boolean fullScreen) {
        Bundle bundle;
        LocationMapFragment locationMapFragment;
        bundle = new Bundle();
        bundle.putString(ARG_TITLE,title);
        bundle.putBoolean(ARG_FULLSCREEN, fullScreen);
        locationMapFragment = new LocationMapFragment();
        locationMapFragment.setArguments(bundle);

        return locationMapFragment;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MapsInitializer.initialize(getActivity());
        if ( GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) == ConnectionResult.SERVICE_MISSING) {
            mGooglePlayServicesAvailable = false;
        } else {
            mGooglePlayServicesAvailable = true;
        }
    }



    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if ( activity instanceof LocationMapFragmentListener ) {
            listener = (LocationMapFragmentListener)activity;
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        listener = null;
    }

    public String getTitle() {
        return getArguments().getString(ARG_TITLE, "");
    }

    public boolean getFullscreen() {
        return getArguments().getBoolean(ARG_FULLSCREEN);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.widget_location_map, container, false);
        gpsIndicatorImageView = (ImageView) view.findViewById(R.id.gpsIndicatorImageView);
        titleLabel = (TextView)view.findViewById(R.id.titleLabel);
        distanceLabel = (TextView)view.findViewById(R.id.distanceLabel);
        gpsWarningLabel = (TextView)view.findViewById(R.id.gpsWarningLabel);
        mapWrapperView = (LinearLayout)view.findViewById(R.id.mapWrapperView);
        mapView = (MapView)view.findViewById(R.id.mapView);
        mapView.onCreate(savedInstanceState);
        mGPSCheckDate = new Date();
        titleLabel.setText(getTitle());
        mMapLayoutOccurred = false;
        setupMap();
        LogUtils.d("LocationMapFragment", "Creating LocationMapFragment " + LocationMapFragment.this);
        return view;
    }

    private void setupMap() {
        Handler handler = new Handler();
        GoogleMap map;

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                updateGPSIndicator();
            }
        },5000);
        try {
            if (mapView != null && mapView.getMap() != null) {
                map = mapView.getMap();
                map.getUiSettings().setZoomControlsEnabled(getFullscreen());
                map.setOnMapClickListener(this);
                map.setOnMarkerClickListener(this);
                map.getUiSettings().setScrollGesturesEnabled(true);
                map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(39.095963, -98.275452), 4));
                if ( !getFullscreen() ) {
                    map.getUiSettings().setMyLocationButtonEnabled(false);
                    map.getUiSettings().setScrollGesturesEnabled(false);

                } else {
                    mapWrapperView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            updateAnnotations();
            updateZoom();
            updateLineBetweenAnnotations();
            showDistance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if (!mMapLayoutOccurred && mapView.getMap() != null) {
                    if (mapView.getWidth() > 0 && mapView.getHeight() > 0) {
                        mapView.getMap().setMyLocationEnabled(true);
                        mapView.getMap().setOnMyLocationChangeListener(LocationMapFragment.this);
                        updateGPSIndicator();
                        showDistance();
                        updateZoom();
                        updateAnnotations();
                        updateLineBetweenAnnotations();
                        LogUtils.d("LocationMapFragment", "Layout occurred " + LocationMapFragment.this);
                        mMapLayoutOccurred = true;
                    }
                }
            }
        });
    }

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

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

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

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

    @Override
    public void onMapClick(LatLng location) {
        if ( listener != null ) {
            listener.onLocationSelected(location);
        }
    }

    @Override
    public boolean onMarkerClick(Marker arg0) {
        return false;
    }

    public void resetZoom() {
        mUserInteracted = false;
        updateZoom();
    }

    private void updateLineBetweenAnnotations() {
        List<LatLng> points;

        if ( mItemLocation != null && currentLocation != null) {
            points = new ArrayList<LatLng>(2);
            points.add(GeoUtils.LatLngFromLocation(mItemLocation));
            points.add(GeoUtils.LatLngFromLocation(currentLocation));
            if ( mPolyline != null ) {
                mPolyline.setPoints(points);
            } else {
                mPolyline = mapView.getMap().addPolyline(new PolylineOptions().add(points.get(0)).add(points.get(1)).color(0xffff0000).width(2));
            }
        }
    }

    private void updateZoom() {
        LatLngBounds.Builder rangeBuilder;
        int buffer = getFullscreen() ? 40 : 10;

        if ( !mMapLayoutOccurred || !mGooglePlayServicesAvailable || mUserInteracted ) {
            return;
        }

        rangeBuilder = new LatLngBounds.Builder();

        if ( mItemLocation != null && currentLocation != null ) {
            rangeBuilder.include(GeoUtils.LatLngFromLocation(mItemLocation));
            rangeBuilder.include(GeoUtils.LatLngFromLocation(currentLocation));
            mapView.getMap().animateCamera(CameraUpdateFactory.newLatLngBounds(rangeBuilder.build(), buffer));
        } else if ( mItemLocation != null ) {
            mapView.getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(GeoUtils.LatLngFromLocation(mItemLocation), buffer));
        } else if ( currentLocation != null ) {
            mapView.getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(GeoUtils.LatLngFromLocation(currentLocation), buffer));
        }
    }

    private void updateAnnotations() {
        if ( mItemLocation != null ) {
            if ( mItemMarker == null ) {
                BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.map_pin);
                mItemMarker = mapView.getMap().addMarker(new MarkerOptions().position(GeoUtils.LatLngFromLocation(mItemLocation)).icon(icon));
            } else {
                mItemMarker.setPosition(GeoUtils.LatLngFromLocation(mItemLocation));
            }
            if ( mLocationRadius != 0 ) {
                if ( mItemRadiusCircle == null ) {
                    mItemRadiusCircle = mapView.getMap().addCircle(new CircleOptions().center(mItemMarker.getPosition()).radius(mLocationRadius).strokeColor(0xff00ff00).strokeWidth(1).fillColor(0x7700ff00));
                } else {
                    mItemRadiusCircle.setCenter(mItemMarker.getPosition());
                    mItemRadiusCircle.setRadius(mLocationRadius);
                }
            } else {
                if ( mItemRadiusCircle != null ) {
                    mItemRadiusCircle.remove();
                    mItemRadiusCircle = null;
                }
            }
        } else {
            if ( mItemMarker != null ) {
                mItemMarker.remove();
                mItemMarker = null;
            }
        }
    }

    private void updateGPSIndicator() {
        float accuracy = 0;
        int badAccuracyThreshold;
        CSGlobalSetting thresholdSetting;


        if ( getView() == null ) {
            return;
        }
        if ( Math.abs(mGPSCheckDate.getTime() - new Date().getTime()) < 5000 ) {
            return;//Give the GPS time to get going
        }
            thresholdSetting = DatabaseManager.getInstance().getGlobalSettingName(CSGlobalSetting.CSGlobalSettingGPSAccuracyWarningLevel);
        if ( thresholdSetting != null  ) {
            badAccuracyThreshold = thresholdSetting.getIntValue();
            if ( badAccuracyThreshold == 0 ) {
                badAccuracyThreshold = 200;
            }
        } else {
            badAccuracyThreshold = 200;
        }
        if ( this.currentLocation != null ) {
            accuracy = this.currentLocation.getAccuracy();
            if (accuracy <= 0) {
                gpsIndicatorImageView.setImageResource(R.drawable.icon_gps_indicator_none);
            } else if (accuracy > 163) {
                gpsIndicatorImageView.setImageResource(R.drawable.icon_gps_indicator_poor);
            } else if (accuracy > 48) {
                gpsIndicatorImageView.setImageResource(R.drawable.icon_gps_indicator_fair);
            } else {
                gpsIndicatorImageView.setImageResource(R.drawable.icon_gps_indicator_good);
            }
            if ( badAccuracyThreshold > 0 && accuracy > badAccuracyThreshold ) {
                gpsWarningLabel.setText("Device has poor GPS signal. Some GPS functions may not be accurate.");
                gpsWarningLabel.setVisibility(View.VISIBLE);
            } else {
                gpsWarningLabel.setVisibility(View.GONE);
            }
        } else {
            gpsWarningLabel.setText("Current location not yet available.");
            gpsWarningLabel.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onMyLocationChange(Location location) {
        Location oldLocation = currentLocation;
        currentLocation = location;
        if ( !mMapLayoutOccurred ) {
            return;
        }
        updateGPSIndicator();
        showDistance();
        updateLineBetweenAnnotations();
        if ( oldLocation == null || !getFullscreen() ) {
            updateZoom();
        }
    }

    public void acceptLocation(Location l) {
        mItemLocation = l;
        updateAnnotations();
        updateZoom();
        updateLineBetweenAnnotations();
    }

    public void setValue(String value) {

        this.value = value;
        mItemLocation = getLocationFromValue(value);
        if ( mapView != null && mMapLayoutOccurred ) {
            updateAnnotations();
            updateZoom();
            updateLineBetweenAnnotations();
        }
    }


    public void clearValue() {
        value = "";
    }

    public void setLocationRadius(double locationRadius) {
        mLocationRadius = locationRadius;
    }

    public String getValue() {
        return value;
    }

    private void showDistance() {
        if (currentLocation != null && mItemLocation != null) {

            int distance = GeoUtils.measure(mItemLocation.getLatitude(), mItemLocation.getLongitude(), currentLocation.getLatitude(),currentLocation.getLongitude());
            String distanceString, unitString;

            if (Locale.US.equals(Locale.getDefault())) {
                // imperial
                double feetDistance = distance * 3.2808399;
                double yardDistance = distance * 1.0936133;
                double milesDistance = distance / 1609.344;

                if (feetDistance < 300) {
                    distanceString = "" + feetDistance;
                    unitString = "ft";
                } else if (yardDistance < 500) {
                    distanceString = "" + yardDistance;
                    unitString = "yds";
                } else {
                    distanceString = "" + milesDistance;
                    unitString = (milesDistance > 1.0 && milesDistance < 1.1) ? "mile" : "miles";
                }
            } else {
                // metric
                double meterDistance = distance;
                double kilometerDistance = distance / 1000;

                if (kilometerDistance >= 1) {
                    distanceString = "" + kilometerDistance;
                    unitString = "km";
                } else {
                    distanceString = "" + meterDistance;
                    unitString = "m";
                }
            }
            if (distanceString != null) {
                int comma = distanceString.indexOf('.');
                if (distanceString.length() > comma + 2) {
                    distanceString = distanceString.substring(0, comma + 3);
                }
            }
            distanceLabel.setText(distanceString + " " + unitString + " away");
        }
    }

    public Location getLocationFromValue(String value) {
        double lat = -1;
        double lng = -1;
        Location location = null;
        if (!TextUtils.isEmpty(value)) {
            StringTokenizer tok = new StringTokenizer(value, ",");
            if (tok.hasMoreTokens()) {
                lat = Double.parseDouble(tok.nextToken());
                if (tok.hasMoreTokens()) {
                    lng = Double.parseDouble(tok.nextToken());
                }
            }
        }
        if ( lat != -1 && lng != -1 ) {
            location = new Location(LocationManager.PASSIVE_PROVIDER);
            location.setLatitude(lat);
            location.setLongitude(lng);
        }
        return location;
    }

    public Location getCurrentLocation() {
        return currentLocation;
    }


    private class TouchableWrapper extends FrameLayout {
        public TouchableWrapper(Context context) {
            super(context);
        }

        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    mUserInteracted = true;
                    break;
            }

            return super.dispatchTouchEvent(ev);
        }
    }

    public interface LocationMapFragmentListener {
        public void onLocationSelected(LatLng location);
    }


}

and here is the widget_location_map.xml layout for the LocationMapFragment

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/gray" android:layout_alignParentTop="true" android:padding="5dp" >

        <ImageView
                android:id="@+id/gpsIndicatorImageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/icon_gps_indicator_none" android:maxHeight="20dp"/>
        <View
            android:layout_width="0dip"
            android:layout_height="match_parent"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/titleLabel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:textColor="@color/white"
            style="@style/CustomLayoutFont" />

        <TextView
            android:id="@+id/distanceLabel"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="right|center_vertical"
            android:textColor="@color/white"
            android:textSize="@dimen/text_micro"
            style="@style/CustomLayoutFont" />
    </LinearLayout>
    <TextView
            android:id="@+id/gpsWarningLabel"
            android:visibility="gone"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Weak GPS signal. Some GPS functions may not behave correctly."
            android:layout_alignParentBottom="true"
            android:background="@color/red"
            android:textColor="@color/white"
        style="@style/CustomLayoutFont"/>

    <LinearLayout
            android:id="@+id/mapWrapperView"
            android:layout_width="match_parent"
            android:layout_height="@dimen/form_elem_map_height">
        <com.google.android.gms.maps.MapView
                android:id="@+id/mapView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clickable="true"
                />
            </LinearLayout>

</LinearLayout>

Any idea what is going on?? Any advice is welcome! Thank you.

You are pointing the wrong context to fragmentTransaction . Try with the below one. you can able to get the context of a view using view.getContext() .

Update LocationFormCell constructor like below.

public LocationFormCell(Context ctx, CSFormElement elem, FormFragment frag, boolean editable) {
    super(ctx, elem, frag, editable);
    View view  = LayoutInflater.from(ctx).inflate(R.layout.form_element_location, this);
        Button overlayButton;

        overlayButton = (Button) view.findViewById(R.id.overlayButton);
        setupOnClickListener(overlayButton);
        locationFrag = LocationMapFragment.newInstance(formElement.disp_name,false);
        FragmentTransaction ft = ((FragmentActivity)view.getContext()).getSupportFragmentManager().beginTransaction();
        ft.add(R.id.map_container, locationFrag);
        ft.commitAllowingStateLoss();
        locationFrag.setValue(value);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM