简体   繁体   中英

How do I prevent recreation/reload of MapView inside a Fragment?

I am using a navigation bar in my app and each time I choose an item it loads a fragment.

I was able to save the state of a fragment with same text fields and buttons but there is a fragment that loads a map, add markers, clusters and executes an AsyncTask .

Each time I go to another menu item and come back it reloads everything again like AsyncTask, Cluster, Markers. How can i stop this fragment to not recreate the map again and save the state when it comes back:

Udate 1: i Update the code but the problem still remained

MainActivity:

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    NavigationView navigationView = null;
    Toolbar toolbar = null;
    GoogleMap nMap;
    SparseArray<Fragment> myFragments;
    JSONArray jArray;
    private static final int ERROR_DIALOG_REQUEST = 9001;
    public static final int ID_OF_BEACH = 5;
    //initBeach test = new initBeach();
    //JSONArray jsonArray = test.ExcuteLoad();

    /**
     * ATTENTION: This was auto-generated to implement the App Indexing API.
     * See https://g.co/AppIndexing/AndroidStudio for more information.
     */
    private GoogleApiClient client;
    Fragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myFragments = new SparseArray<>();

        //setTitle("");
        setContentView(R.layout.activity_main);

        if (servicesOK()) {
            try {
                jArray = new LoadJson().execute().get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            setContentView(R.layout.activity_main);
        }

        //Set the fragment initially
        FragmentTransaction fragmentTransaction =
                getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, new MainFragment(jArray));
        fragmentTransaction.addToBackStack("1");
        fragmentTransaction.commit();

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        //noinspection ConstantConditions
        getSupportActionBar().setDisplayShowTitleEnabled(false);


        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);

        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();


        navigationView = (NavigationView) findViewById(R.id.nav_view);

        //How to change elements in the header programatically


        navigationView.setNavigationItemSelectedListener(this);
        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
        navigationView.setItemIconTintList(null);

    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        //noinspection SimplifiableIfStatement
        return super.onOptionsItemSelected(item);
    }


    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camara) {
            fragment = myFragments.get(1);
            // if fragment doesn't exist in myFragments, create one and add to it
            if (fragment == null) {
                fragment = new MainFragment(jArray);
                myFragments.put(1, fragment);
            }
            FragmentTransaction fragmentTransaction =
                    getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container, fragment);
            fragmentTransaction.commit();


            // Handle the camera actionn

        } else if (id == R.id.nav_gallery) {
            //Set the fragment initially
            fragment = myFragments.get(2);
            // if fragment doesn't exist in myFragments, create one and add to it
            if (fragment == null) {
                fragment = new GalleryFragment();
                myFragments.put(2, fragment);
            }

            FragmentTransaction fragmentTransaction =
                    getSupportFragmentManager().beginTransaction();
            fragmentTransaction.replace(R.id.fragment_container, fragment);
            fragmentTransaction.commit();


        } else if (id == R.id.nav_search) {
            //Set the fragment initially

            // Handle the camera action

        } else if (id == R.id.nav_manage) {

            // Handle the camera action

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    public boolean servicesOK() {

        int isAvailable = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

        if (isAvailable == ConnectionResult.SUCCESS) {
            return true;
        } else if (GooglePlayServicesUtil.isUserRecoverableError(isAvailable)) {
            Dialog dialog =
                    GooglePlayServicesUtil.getErrorDialog(isAvailable, this, ERROR_DIALOG_REQUEST);
            dialog.show();
        } else {
            Toast.makeText(this, "Can't connect to mapping service", Toast.LENGTH_SHORT).show();
        }

        return false;
    }


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

        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client.connect();
        Action viewAction = Action.newAction(
                Action.TYPE_VIEW, // TODO: choose an action type.
                "Main Page", // TODO: Define a title for the content shown.
                // TODO: If you have web page content that matches this app activity's content,
                // make sure this auto-generated web page URL is correct.
                // Otherwise, set the URL to null.
                Uri.parse("http://host/path"),
                // TODO: Make sure this auto-generated app URL is correct.
                Uri.parse("android-app://com.compscitutorials.basigarcia.navigationdrawervideotutorial/http/host/path")
        );
        AppIndex.AppIndexApi.start(client, viewAction);
    }

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

        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        Action viewAction = Action.newAction(
                Action.TYPE_VIEW, // TODO: choose an action type.
                "Main Page", // TODO: Define a title for the content shown.
                // TODO: If you have web page content that matches this app activity's content,
                // make sure this auto-generated web page URL is correct.
                // Otherwise, set the URL to null.
                Uri.parse("http://host/path"),
                // TODO: Make sure this auto-generated app URL is correct.
                Uri.parse("android-app://com.compscitutorials.basigarcia.navigationdrawervideotutorial/http/host/path")
        );
        AppIndex.AppIndexApi.end(client, viewAction);
        client.disconnect();
    }


    //AsyincTask to load JSON
    public class LoadJson extends AsyncTask<String, Void, JSONArray> {
        String URLu = "SOME_JSON_URL";


        @Override
        protected JSONArray doInBackground(String... params) {

            try {
                URL url = new URL(URLu);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                InputStream stream = connection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }
                String finalJson = buffer.toString();

                JSONObject jsonObject = new JSONObject(finalJson);
                JSONArray jsonArray = jsonObject.getJSONArray("marcadores");

                return jsonArray;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }

        }

        @Override
        protected void onPostExecute(JSONArray result) {
            super.onPostExecute(result);
        }

        @Override
        protected void onPreExecute() {
          super.onPreExecute();
        }

    }
}

MainFragment:

public class MainFragment extends Fragment {
    GoogleMap nMap;
    MapView mapView;
    CameraUpdate update;
    JSONArray array;
    private ClusterManager<ItemCluster> mClusterManager;
    private void parseJSON(JSONArray array) {
        if (mapView != null) {
            nMap = mapView.getMap();
            nMap.getUiSettings().setMyLocationButtonEnabled(false);
            nMap.setMyLocationEnabled(true);
            nMap.getUiSettings().setZoomControlsEnabled(true);
            mClusterManager = new ClusterManager<>(this.getActivity(), nMap);
            nMap.setOnCameraChangeListener(mClusterManager);
            nMap.setInfoWindowAdapter(mClusterManager.getMarkerManager());
            nMap.setOnMarkerClickListener(mClusterManager);
        }

        try {
            //Loading LAT LOng of markers on map
            for (int i = 0; i < array.length(); i++) {
                JSONObject jsonObject = array.getJSONObject(i);
                String locality = jsonObject.getString("nombre");
                String vientos = jsonObject.getString("viento");
                int temp = jsonObject.getInt("temperatura");
                double lat = jsonObject.getDouble("lat");
                double lon = jsonObject.getDouble("lon");
                nMap = mapView.getMap();

                mClusterManager.setRenderer(new OwnIconRendered(getActivity().getApplicationContext(), nMap, mClusterManager));
                ItemCluster offsetItem = new ItemCluster(lat, lon, locality, vientos, temp);
                mClusterManager.addItem(offsetItem);
            }
            LatLng latLon = new LatLng(39.4666667, -0.3666667);
            update = CameraUpdateFactory.newLatLngZoom(latLon, 10);
            nMap.moveCamera(update);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @SuppressLint("ValidFragment")
    public MainFragment(JSONArray input) {
        array = input;
    }
    public MainFragment() {

    }



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        mapView = (MapView) rootView.findViewById(R.id.map);
        mapView.onCreate(savedInstanceState);

        parseJSON(array);

        // Inflate the layout for this fragment
        setRetainInstance(true);
        return rootView;

    }

    class OwnIconRendered extends DefaultClusterRenderer<ItemCluster> {

        private final IconGenerator mClusterIconGenerator = new IconGenerator(getActivity().getApplicationContext());
        private final TextView mClusterImageView;
        private final ImageView mClusterViento;
        private int tempAvg = 0;
        private final Drawable TRANSPARENT_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);


        public OwnIconRendered(Context context, GoogleMap map,
                               ClusterManager<ItemCluster> clusterManager) {
            super(context, map, clusterManager);

            View clusterIcon = getActivity().getLayoutInflater().inflate(R.layout.info_windows, null);
            mClusterIconGenerator.setContentView(clusterIcon);
            mClusterImageView = (TextView) clusterIcon.findViewById(R.id.maxTmp);
            mClusterViento = (ImageView) clusterIcon.findViewById(R.id.viento);

        }

        @Override
        protected void onBeforeClusterItemRendered(ItemCluster item, MarkerOptions markerOptions) {
            markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marcador_playa));
            markerOptions.title(item.getTitle());
            super.onBeforeClusterItemRendered(item, markerOptions);
        }

        @Override
        protected void onBeforeClusterRendered(Cluster<ItemCluster> cluster, MarkerOptions markerOptions) {

            tempAvg = 0;
            String vientoStr = null;
            for (ItemCluster item : cluster.getItems()) {
                tempAvg = (item.getTemp()+tempAvg);
            }

            mClusterImageView.setText(String.valueOf(tempAvg/cluster.getSize()));
            if ((tempAvg/cluster.getSize()) > 32) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_32_o_mas);
            } else if ((tempAvg/cluster.getSize()) <= 31 && (tempAvg/cluster.getSize()) >= 25) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_25_a_31);
            } else if ((tempAvg/cluster.getSize()) <= 24 && (tempAvg/cluster.getSize()) >= 20) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_20_a_24);
            } else if ((tempAvg/cluster.getSize()) <= 19 && (tempAvg/cluster.getSize()) >= 15) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_15_a_19);
            } else if ((tempAvg/cluster.getSize()) <= 14 && (tempAvg/cluster.getSize()) >= 10) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_10_a_14);
            } else if ((tempAvg/cluster.getSize()) <= 9 && (tempAvg/cluster.getSize()) >= 5) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_5_a_9);
            } else if ((tempAvg/cluster.getSize()) <= 4) {
                mClusterImageView.setBackgroundResource(R.drawable.temp_4_o_menos);
            }

            for (ItemCluster item : cluster.getItems()) {
                vientoStr = item.getViento();
                if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NE2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_ne2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NW2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_nw2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_E2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_e2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NE1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_ne1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NE3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_ne3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NE4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_ne4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NW1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_nw1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NW3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_nw3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_NW4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_nw4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_E1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_e1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_E3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_e3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_E4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_e4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_N1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_n1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_N2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_n2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_N3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_n3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_N4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_n4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_W1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_w1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_W2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_w2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_W3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_w3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_W4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_w4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SW1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_sw1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SW2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_sw2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SW3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_sw3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SW4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_sw4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SE1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_se1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SE2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_se2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SE3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_se3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_SE4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_se4);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_S1.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_s1);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_S2.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_s2);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_S3.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_s3);
                } else if (Objects.equals(vientoStr, "appvalenciaplayas/static/images/viento/viento_S4.svg")) {
                    mClusterViento.setImageResource(R.drawable.viento_s4);
                }
                break;
            }


            mClusterIconGenerator.setBackground(TRANSPARENT_DRAWABLE);
            Bitmap bitmap = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
            markerOptions.icon(BitmapDescriptorFactory.fromBitmap(bitmap));
        }


        @Override
        protected boolean shouldRenderAsCluster(Cluster cluster) {
            // Always render clusters.
            return cluster.getSize() > 1;
        }
    }


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

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

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

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

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }
}

You are replacing the fragment after every event, please add the fragment to the backstack and then pop it from the backstack. Then it will work. Check the below code:

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(android.R.id.content, testFragment);
fragmentTransaction.addToBackStack(TAG);
fragmentTranscation.commit();

Google Maps' Docs say:

Users of this class must forward all the life cycle methods from the Activity or Fragment containing this view to the corresponding ones in this class. In particular, you must forward on the following methods:

  • onCreate(Bundle)
  • onResume()
  • onPause()
  • onDestroy()
  • onSaveInstanceState()
  • onLowMemory()

So in your MainFragment.java, you'd MUST override all of the methods above and delegate the calls to mapView .

For clarity, you'd override onSaveInstanceState() like this:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mapView.onSaveInstanceState(outState);
}

Edit

Other problem is that you're creating MainFragment first time without caching it. Which means that you do not "re-use" this instance when you bring back the one from drawer (you can check by clicking drawer items in this order nav_gallery -> nav_camera -> nav_gallery -> nav_camera . The MainFragment at 4th position should not load like the one at 2nd):

Fragment fragment = new MainFragment(jArray);
myFragments.put(1, fragment);

//Set the fragment initially
FragmentTransaction fragmentTransaction =
        getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack("1");
fragmentTransaction.commit();

Edit2

For maintaining the state of your Fragment, you will have to do following things:

  1. update your onSaveInstanceState() , to save its state, like following:

     @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); outState.putString("jsonArr", jsonArray.toString()); // TODO put more things which you need to. } 
  2. update your onCreateView() , to restore the state, like:

     @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (savedInstanceState != null) { String jsonArrString = savedInstanceState.getString("jsonArr"); try { jsonArray = new JSONArray(jsonArrString); } catch (Exception e) { e.printStackTrace() } } // TODO your old code goes after this line. } 

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