I'm developing an Android app where you enter a list of courier tasks (get something in point A
and take it to the point B
) and these points are shown on a map
App has two snippets:
ReclyclerView
containing the task list.
Bulleted map showing points A
and B
of each list item in recyclerView
.
When the map is created (or recreated) it takes the coordinates of the database (which also feeds the to-do list).
The question arises when inserting a new task. New bookmarks will only appear if you force map re-creation (by rotating the device or restarting the app ).
How do I insert bookmarks into the map when inserting a new task?
UPDATE: As Ack Lay observed, my question lacked more detail. And as a picture is worth a thousand words ...
** I'm new here and I can only publish two images ... Then it will be the last two.
1.When you open the application, an empty panel appears in the left half and an empty map on the right.
Touching the + push button opens a form. to enter the task. You should be informed: What will be transported, where to pick up with whom, where to deliver, for whom.
Thetaskdataiswrittentothedatabase.The'adapter'isupdatedalongwiththe'reviewer'andthecardappearsshowingtheinformation.Themapisstillempty.
**Operationsinthedatabase(SQLite)aredonebya'dbHelper'classwiththeCRUDmethods.
That is, the markers appear when the'fragment 'is (re) created. What does not work is updating the map, along with the reviewer, when I enter a new task.
Now it's time to describe the structure of app .
The main activity is
public class MainActivity extends FragmentActivity
It loads the layout it has is made up of
<?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 task list class
public class RecyclerFragment extends Fragment
The map class
public class MapFragment extends Fragment
The code is very similar to what you ordered, it is only more adapted to the app . For example, the pins are fixed. We do not want them to change by touching the map. Only updating the card. To avoid course problems.
It seems to have 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 map instance and add the new'marker '.
This would be done in'A' event 'onClick ()' of the'positiveButton 'of the dialog that inflates the form (ie when you hit CONFIRM). Or 'B' method wouldbHelper.insert () '
But there have to be other ways.
Can someone give me a light?
UPDATE: In response to @ramaral's tips
Implementing the 'interface' worked. It was not even necessary to create a custom 'listener', since the button had already been implemented.
But it's not over yet: - (
When the device is vertically oriented (portrait), it works correctly. However, when it is horizontal (landscape) not yet.
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>
Map fragment layout
<?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"
/>
Next, the parts of code that I consider pertinent to this question, especially this line of 'MainActivity':
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 it 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 the line again
MarkersFragment mFragment = (MarkersFragment) getSupportFragmentManager().findFragmentById(R.id.viewpager);
It works vertically because the view R.id.viewpager is instantiated, and like I said the other views return null
Given the above code, could you guide me how to reference the most appropriate view?
(If you think you have too much code, feel free to eliminate any excess.)