How to insert markers (Marker) into a map in another Fragment?

Asked

Viewed 1,031 times

2

I’m developing a app Android where you insert a courier task list (pick something up on the dot A and bring to the point B) and these dots are shown on a map.

The App has two fragments:

  1. ReclyclerView containing the list of tasks.

  2. map with markers showing points A and B of each item in the recyclerView.

When the map is created (or recreated) it takes the coordinates from the database (which also feeds the task list).

The question arises when inserting a new task. The new markers only appear if you force the map to be recreated (by rotating the device or restarting the app).

How do I insert the markers into the map when inserting a new task?

UPDATE: As Ack Lay noted my question needed more details. And how an image is worth a thousand words...

** I’m new here and I can only publish two images... Then it’ll be the last two.

1.When opening the application appears an empty panel in the left half and an empty map on the right.

  1. When you touch the +drop button, you open a form. for the task input. You must be informed: What will be transported, where to pick up with whom ,where to deliver, to whom.

  2. Complete form, tap finish and... Card com informações da tarefa

  3. The task data is recorded in the database. Adapter is updated along with recyclerview and the card appears showing the information. The map is still empty.

** Database operations (Sqlite) are performed by a dbHelper class with CRUD methods.

Mapa com marcadores

  1. You need to change the orientation of the device or restart the application for the markers to appear.

That is, markers appear when Fragment is (re)created. What doesn’t work is updating the map, along with recyclerview , when I enter a new task.

The structure of the app.

The main activity is

public class MainActivity extends FragmentActivity 

It loads the layout it has is formed by

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:fitsSystemWindows="true"
    android:id="@+id/myContainer"
    android:orientation="horizontal">
    <fragment
        android:id="@+id/runFragment"
        android:name="br.com.medamais.motonoix.RecyclerFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        tools:layout="@layout/fragment_recycler" />
    <fragment
        android:id="@+id/markersMapFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        tools:layout="@layout/fragment_map"
        android:name="br.com.medamais.motonoix.MarkersFragment"
        />
</LinearLayout>

The class of the task list

public class RecyclerFragment extends Fragment 

The class of the map

public class MapFragment extends Fragment

The code is very similar to what you sent, is only more adapted to the app. For example, the pins are fixed. We don’t want them to change when you touch the map. Only updating the card. To avoid course problems.

It seems that there are several possible approaches. I have some experience as a developer, but this is my first Android app.

I imagine the solution is a way to access the instance of the map and add the new Marker.

This would be done in The onClick() event from the positiveButton dialog that inflates the form (i.e., when you tap CONFIRM). Or B method dbHelper.Insert()

But there must be other ways.

Someone can give me a light?

UPDATE: In response to @ramaral tips

Implementing the interface worked. There was no need to create a custom system once the button had already been implemented.

But it’s not over yet :-(

When the device is oriented vertically (portrait), it works correctly. However, when it is horizontal (landscape) not yet.

The vertical layout is composed like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/myContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <android.support.design.widget.TabLayout
        android:id="@+id/sliding_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabGravity="fill"
        app:tabMaxWidth="0dp"
        app:tabMode="fixed" />
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />
</LinearLayout>

Horizontally:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:fitsSystemWindows="true"
    android:id="@+id/myContainer"
    android:orientation="horizontal">
    <fragment
        android:id="@+id/runFragment"
        android:name="br.com.medamais.motonoix.RecyclerFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        tools:layout="@layout/fragment_recycler" />
    <fragment
        android:id="@+id/markersMapFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        tools:layout="@layout/fragment_map"
        android:name="br.com.medamais.motonoix.MarkersFragment"
        />
</LinearLayout>

Layout of the map fragment

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:id="@+id/markersMapFragment"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    map:cameraTargetLat="-23.7941"
    map:cameraTargetLng="-46.8825"
    map:cameraZoom="13"
/>

Then the code parts that I consider relevant to this issue, especially this Mainactivity line:

MarkersFragment mFragment = (MarkersFragment) getSupportFragmentManager().findFragmentById(R.id.viewpager);

I tried findFragmentById with R.id.markersMapFragment, R.id.myContainer, but all return null. The only one that returns the object is R.id.viewpager and is the one that works.

The Fragment that shows the list and the button +

public class RecyclerFragment extends Fragment implements AlertDialog.OnClickListener {
    ...
    ...
    public RecyclerFragment() { 
        this.mCallback = null;
    }
    ...
    ...
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...
        ...        
        FloatingActionButton fab = (FloatingActionButton) mInflate.findViewById(R.id.fabAdd);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // abre o dialogo de inserção de dados
                dialogInsertRun();
            }
        });
        ...
        ...
    }

    public void dialogInsertRun() { // implementa a janela de dialogo de inserção de dados
        ...
        ...
        addRunDialog.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() { // implementa botão <CONFIRMAR>

            @Override
            public void onClick(DialogInterface dialog, int id) { // Listener 'padrão'
                ...
                ...
                mCallback.addMarkersToMap(runData); // metodo definido na Activity
            }
            ...
            ...
        }
    }
    ...
    ...
    @Override
    public void onClick(DialogInterface dialogInterface, int i) { 
        Log.d(TAG, "onClick: ");
    }
    ...
    ...
    private OnOkButtonListener mCallback;
    public interface OnOkButtonListener {
        void addMarkersToMap(RunData runData);
    }
    ...
    ...
}

In the Activity that controls the fragments we have

public class MainActivity extends FragmentActivity implements RecyclerFragment.OnOkButtonListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // replace the splash theme with app theme
        setTheme(R.style.AppTheme);
        // finish is overdue
        checkDateLimit();
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        ScreenUtility utility = new ScreenUtility(this);
        if (utility.getWidth() < 500.0) {
            // Get the ViewPager and set it's PagerAdapter so that it can display items
            ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
            viewPager.setAdapter(new TabsPagerAdapter(getSupportFragmentManager(), getApplicationContext()));

            // Give the TabLayout the ViewPager
            TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
            tabLayout.setupWithViewPager(viewPager);
        }
    }

    ...
    ...
    public void addMarkersToMap(RunData runData) {
        if (runData != null) {
            MarkersFragment mFragment = (MarkersFragment) getSupportFragmentManager().findFragmentById(R.id.viewpager);

            mFragment.addSingleMarker(runData); 
    }
}

And in the fragment that controls the map

public class MarkersFragment extends Fragment {
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setUpMapIfNeeded(); 
    }
    private void setUpMapIfNeeded() { 
        // Do a null check to confirm that we have not already instantiated the map.
        if (markersMapFragment == null) {
            markersMapFragment = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.markersMapFragment));
            // Check if we were successful in obtaining the map.
            if (markersMapFragment != null) {
                markersMapFragment.getMapAsync(new OnMapReadyCallback() {
                    @Override
                    public void onMapReady(GoogleMap mGoogleMap) {
                        if (mGoogleMap != null) {
                            ...
                            ...
                            LatLng tLatLng, mLatLng;
                            mLatLng = new LatLng(-23.5492, -46.6336);
                            // iterates through the runList as instance of RunData
                            for (RunData runData : runList) { 
                                tLatLng = addMarkers(runData.collect_lat, runData.collect_lng, runData.collect_address, runData.collect_person, runData.delivery_lat, runData.delivery_lng, runData.delivery_address, runData.delivery_person, runData.run_parcel, mGoogleMap);
                                ...
                                ...                               
                            }
                            // Show the current location in Google Map
                            mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(mLatLng));
                            // Zoom in the Google Map
                            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(13));
                            ...
                            ...
                        }
                    }
                });
            }
        }
    }

    // metodo que adiciona os marcadores.
    public LatLng addMarkers(String collectLat, String collectLng, String collectAddress, String collectPerson,
                             String deliveryLat, String deliveryLng, String deliveryAddress, String deliveryPerson,
                             String parcel, GoogleMap googleMap) {
        LatLng cLatLng, dLatLng;
        String mSnippet;
        // add collect marker
        if ((collectLat != null & collectLng != null) && (collectLat.length() > 0 & collectLng.length() > 0)) {
            ...
            ...
            googleMap.addMarker(new MarkerOptions()
                    .position(cLatLng)
                    .icon(collectMarker)
                    .title(collectAddress)
                    .draggable(false)
                    .snippet(mSnippet)
            );
        } 

        // add delivery marker
        if ((deliveryLat != null & deliveryLng != null) && (deliveryLat.length() > 0 & deliveryLng.length() > 0)) {
            ...
            ...
            googleMap.addMarker(new MarkerOptions()
                    .position(dLatLng)
                    .icon(deliveryMarker)
                    .title(deliveryAddress)
                    .draggable(false)
                    .snippet(mSnippet)
            );
        }
        // retorna LatLng ou null
        if (cLatLng != null) {
            return cLatLng;
        } else if (dLatLng != null) {
            return dLatLng;
        } else {
            return null;
        }
    }

    // metodo que adiciona os marcadores de coleta e entrega de um unico registro
    // executado pela atividade controladora
    public void addSingleMarker(RunData runData) {
        final String collectLat = runData.collect_lat;
        final String collectLng = runData.collect_lng;
        ...
        ...

        if (markersMapFragment == null) {
            markersMapFragment = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.markersMapFragment));
            // Check if we were successful in obtaining the map.
            if (markersMapFragment != null) {
                markersMapFragment.getMapAsync(new OnMapReadyCallback() {
                    @Override
                    public void onMapReady(GoogleMap mGoogleMap) {
                        LatLng mLatLng;
                        mLatLng = new LatLng(-23.5492, -46.6336);
                        if (mGoogleMap != null) {
                            mLatLng = addMarkers(collectLat, collectLng, collectAddress, collectPerson, deliveryLat, deliveryLng, deliveryAddress, deliveryPerson, parcel, mGoogleMap);
                            mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(mLatLng));
                            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(13));
                        }
                    }
                });
            }
        } else {
            if (markersMapFragment != null) {
                markersMapFragment.getMapAsync(new OnMapReadyCallback() {
                    @Override
                    public void onMapReady(GoogleMap mGoogleMap) {
                        LatLng mLatLng;
                        mLatLng = new LatLng(-23.5492, -46.6336);
                        if (mGoogleMap != null) {
                            mLatLng = addMarkers(collectLat, collectLng, collectAddress, collectPerson, deliveryLat, deliveryLng, deliveryAddress, deliveryPerson, parcel, mGoogleMap);
                            mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(mLatLng));
                            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(13));
                        }
                    }
                });
            }
        }
    }
}

I highlight again the line

MarkersFragment mFragment = (MarkersFragment) getSupportFragmentManager().findFragmentById(R.id.viewpager);

It works vertically because the R.id.viewpager view is instantiated, and as I said the other views return null

Given the above code, you could guide me how to reference the most appropriate view?

(If you feel you have too much code, feel free to eliminate any excess).

3 answers

2


The way to solve this depends on how you have structured your code.

One of the approaches used is Activity managing the two Fragments, making them intermediate between them.

Thus, when a Fragment wants an action to be executed in another Fragment, the first asks Activity to inform the second of that intention.

In this case the Dialog Fragment calls an Activity method, passing the necessary information, so that it calls a Map Fragment method to add the Marker.

See in How to pass the Edittext value of a Fragment to the Textview of another Fragment? and Change Fragment components through an Activity how similar situations were resolved this.

1

Considering the minimum details provided in your question, I will try below to show how the basics would be when it comes to Google Maps API. See below for a simple class in which it is marked with a point setting latitude and latitude using Markers:

public class MapPane extends Activity implements OnMapReadyCallback {

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

        MapFragment mapFragment = (MapFragment) getFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap map) {
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(
                new LatLng(41.889, -87.622), 16));

        // You can customize the marker image using images bundled with
        // your app, or dynamically generated bitmaps.
        map.addMarker(new MarkerOptions()
                .icon(BitmapDescriptorFactory.fromResource(R.drawable.house_flag))
                .anchor(0.0f, 1.0f) // Anchors the marker on the bottom left
                .position(new LatLng(41.889, -87.622)));
    }
}

How do I insert the markers into the map when inserting a new one task?

The moment you enter this new task, simply insert a new marker in this way:

map.addMarker(new MarkerOptions().icon(BitmapDescriptorFactory.
fromResource(R.drawable.house_flag))
                    .anchor(0.0f, 1.0f) 
                    .position(new LatLng(41.889, -87.622)));

Follows below a additional where you can do a test by clicking on any point on the map to add a marker according to the coordinate. See:

map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

                @Override
                public void onMapClick(LatLng point) {

                    MarkerOptions marker = new MarkerOptions().position(
                            new LatLng(point.latitude, point.longitude)).title("New Marker");

                    googleMap.addMarker(marker);

                System.out.println(point.latitude+"---"+ point.longitude);  
                }
            });

For more details, just follow the guidelines of documentation on the Android website.

  • I hope that, with the new details, you see that the correct answer you gave has no relation to the central question.

  • @Renefreak Bookmarks are being added via sqlite?

  • No. The database only has one table with the data you see on the card, plus the coordinates. That is, I save the addresses and the lat. and long. both collection and delivery.

  • At the event onMapReady I retrieve the table and interact with each record, using the lat/lng to add the marker. If there is no lat. /long. I use the address to try to find them.

1

I ended up finding a solution to 'find' the correct element in the map’s Fragment and insert the markers. The interface method:

public void addMarkersToMap(RunData runData) {
    if (runData != null) {
        MarkersFragment mFragment = (MarkersFragment) getSupportFragmentManager().findFragmentById(R.id.viewpager);

        mFragment.addSingleMarker(runData); 
}

was like this:

public void addMarkersToMap(RunData runData) {
    if (runData != null) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        MarkersFragment mFragment;

        if(getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) {
            mFragment = (MarkersFragment) fragmentManager.findFragmentById(R.id.markersMapPanel);
        } else if(getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT){
            mFragment = (MarkersFragment) fragmentManager.findFragmentById(R.id.viewpager);
        }

        if (mFragment != null) {
            mFragment.addSingleMarker(runData);
        }

    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.