Мне нужно что-то, что займет два списка и может сделать то, что diff
в bash
. Поскольку этот вопрос появляется сначала, когда вы ищете «python diff two lists» и не очень специфичен, я опубликую то, что я придумал.
Используя SequenceMather
из difflib
вы можете сравнить два списка, например diff
. Ни один из других ответов не скажет вам, где эта разница, но это делает. Некоторые ответы дают разницу только в одном направлении. Некоторые переупорядочивают элементы. Некоторые не обрабатывают дубликаты. Но это решение дает вам истинную разницу между двумя списками:
a = 'A quick fox jumps the lazy dog'.split()
b = 'A quick brown mouse jumps over the dog'.split()
from difflib import SequenceMatcher
for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes():
if tag == 'equal': print('both have', a[i:j])
if tag in ('delete', 'replace'): print(' 1st has', a[i:j])
if tag in ('insert', 'replace'): print(' 2nd has', b[k:l])
Это выдает:
both have ['A', 'quick']
1st has ['fox']
2nd has ['brown', 'mouse']
both have ['jumps']
2nd has ['over']
both have ['the']
1st has ['lazy']
both have ['dog']
Конечно, если ваше приложение делает те же предположения, что и другие ответы, вы выиграете от них больше всего. Но если вы ищете истинную функциональность diff
, то это единственный способ пойти.
Например, ни один из других ответов не может обрабатывать:
a = [1,2,3,4,5]
b = [5,4,3,2,1]
Но это делает:
2nd has [5, 4, 3, 2]
both have [1]
1st has [2, 3, 4, 5]
Ответ Мэтт предлагает работы, но это заставляет карту воссоздаваться и перерисовываться, что не всегда желательно. После многих проб и ошибок я нашел решение, которое работает для меня:
private static View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
try {
view = inflater.inflate(R.layout.map, container, false);
} catch (InflateException e) {
/* map is already there, just return view as it is */
}
return view;
}
Для хорошей меры, вот «map.xml» (R.layout.map) с R.id.mapFragment ( android: id = "@ + id / mapFragment"):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
Надеюсь, это поможет, но я не могу гарантировать, что он не имеет никаких побочных эффектов.
Изменить: Были некоторые неблагоприятные эффекты, например, при выходе из приложения и повторном запуске. Поскольку приложение не обязательно полностью отключается (но просто укладывается в фоновом режиме), предыдущий код, который я отправил, не смог перезапустить приложение. Я обновил код до чего-то, что работает для меня, идя в & amp; из карты и выхода и перезапуска приложения, я не слишком доволен битком try-catch, но, похоже, он работает достаточно хорошо. При просмотре трассировки стека мне пришло в голову, что я могу просто проверить, есть ли фрагмент карты в FragmentManager, нет необходимости в блоке try-catch, обновлен код.
Дополнительные изменения: оказывается, что вам нужно что try-catch в конце концов. Просто проверка фрагмента карты оказалась не очень хорошей. Blergh.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.gms.maps.MapView
android:id="@+id/mapview"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_alignParentTop="true"
android:layout_alignRight="@+id/textView1"
android:layout_marginRight="15dp" >
</com.google.android.gms.maps.MapView>
Почему вы не вставляете карту, используя объект MapView вместо MapFragment? Я не уверен, есть ли какие-либо ограничения в MapView, хотя я нашел его полезным.
Сегодня я потерял часы, чтобы найти причину, к счастью, эта проблема связана не с реализацией MapFragment, но, к сожалению, это не работает, потому что вложенные фрагменты поддерживаются только через библиотеку поддержки от версии 11.
My реализация имеет действие с панелью действий (в режиме с вкладками) с двумя вкладками (без просмотра), один имеет карту, а другой - список записей. Конечно, я был очень наивным, чтобы использовать MapFragment внутри своих вкладки-фрагментов, et voila, приложение разбилось каждый раз, когда я переключился обратно на карту-вкладку.
(та же проблема, которую я также имел бы в случае моей вкладки -фрагмент будет раздувать любой макет, содержащий любой другой фрагмент).
Один из вариантов заключается в использовании MapView (вместо MapFragment) с некоторыми накладными расходами (см. MapView Docs вместо замены в layout.xml другой вариант - использовать библиотеку поддержки от версии 11, но затем использовать программный подход, поскольку вложенные фрагменты не поддерживаются с помощью макета. Или просто работайте программно, явно разрушая фрагмент (например, в ответе от Matt / Vidar), btw: тот же эффект достигается с помощью MapView (вариант 1).
Но на самом деле я не хотел потерять карту каждый раз, когда я убираю ее, то есть хочу сохранить он в памяти и очистке только после закрытия операции, поэтому я решил просто скрыть / показать карту во время табуляции, см. FragmentTransaction / hid е
Я бы рекомендовал replace()
вместо attach()
/ detach()
в вашей обработке вкладок.
Или переключитесь на ViewPager
. Вот пример проекта , показывающий ViewPager
, с вкладками, содержащими 10 карт.
У меня была такая же проблема, и я смог ее решить, вручную удалив MapFragment
в методе onDestroy()
класса Fragment
. Вот код, который работает и ссылается на MapFragment
по ID в XML:
@Override
public void onDestroyView() {
super.onDestroyView();
MapFragment f = (MapFragment) getFragmentManager()
.findFragmentById(R.id.map);
if (f != null)
getFragmentManager().beginTransaction().remove(f).commit();
}
Если вы не удалите MapFragment
вручную, он будет зависать, чтобы он не стоил много ресурсов для воссоздания / отображения карты снова. Кажется, что сохранение базового MapView
отлично подходит для переключения между вкладками, но при использовании в фрагментах это поведение вызывает создание дубликата MapView
для каждого нового MapFragment
с тем же идентификатором. Решение состоит в том, чтобы вручную удалить MapFragment
и таким образом воссоздать базовую карту каждый раз, когда фрагмент завышен.
Я также отметил это в другом ответе [ 1 ].
Для тех, кто все еще сталкивается с этой проблемой, лучший способ убедиться, что вы не получите эту ошибку с помощью Карты в Tab, заключается в том, чтобы сделать фрагмент расширенным SupportMapFragment
вместо вложенности SupportMapFragment
внутри Фрагмент, используемый для вкладки
Я только что получил эту работу, используя ViewPager
с FragmentPagerAdapter
, с поддержкой SupportMapFragment в третьей вкладке.
Вот общая структура, обратите внимание, что нет необходимости переопределять метод onCreateView()
, и нет необходимости раздувать макет xml:
public class MapTabFragment extends SupportMapFragment
implements OnMapReadyCallback {
private GoogleMap mMap;
private Marker marker;
public MapTabFragment() {
}
@Override
public void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
getMapAsync(this);
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
setUpMap();
}
private void setUpMap() {
mMap.setMyLocationEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.getUiSettings().setMapToolbarEnabled(false);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng point) {
//remove previously placed Marker
if (marker != null) {
marker.remove();
}
//place marker where user just clicked
marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)));
}
});
}
}
Результат:
[/g0]
Вот полный код класса, который я использовал для тестирования, который включает фрагментарный фрагмент, используемый для первых двух вкладок, и фрагмент карты, используемый для третьей вкладки:
public class MainActivity extends AppCompatActivity implements ActionBar.TabListener{
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return PlaceholderFragment.newInstance(position + 1);
case 1:
return PlaceholderFragment.newInstance(position + 1);
case 2:
return MapTabFragment.newInstance(position + 1);
}
return null;
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
TextView text;
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
text = (TextView) rootView.findViewById(R.id.section_label);
text.setText("placeholder");
return rootView;
}
}
public static class MapTabFragment extends SupportMapFragment implements
OnMapReadyCallback {
private static final String ARG_SECTION_NUMBER = "section_number";
private GoogleMap mMap;
private Marker marker;
public static MapTabFragment newInstance(int sectionNumber) {
MapTabFragment fragment = new MapTabFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public MapTabFragment() {
}
@Override
public void onResume() {
super.onResume();
Log.d("MyMap", "onResume");
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
if (mMap == null) {
Log.d("MyMap", "setUpMapIfNeeded");
getMapAsync(this);
}
}
@Override
public void onMapReady(GoogleMap googleMap) {
Log.d("MyMap", "onMapReady");
mMap = googleMap;
setUpMap();
}
private void setUpMap() {
mMap.setMyLocationEnabled(true);
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.getUiSettings().setMapToolbarEnabled(false);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng point) {
Log.d("MyMap", "MapClick");
//remove previously placed Marker
if (marker != null) {
marker.remove();
}
//place marker where user just clicked
marker = mMap.addMarker(new MarkerOptions().position(point).title("Marker")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)));
Log.d("MyMap", "MapClick After Add Marker");
}
});
}
}
}
Проблема в том, что то, что вы пытаетесь сделать, не должно быть сделано. Вы не должны раздувать фрагменты внутри других фрагментов. Из документации от Android :
Примечание. Вы не можете раздувать макет во фрагмент, если этот макет содержит & lt; фрагмент & gt ;. Вложенные фрагменты поддерживаются только при динамическом добавлении к фрагменту.
Хотя вы можете выполнить задачу с представленными здесь хаками, я настоятельно рекомендую вам не делать этого. Невозможно убедиться, что эти хаки будут обрабатывать то, что делает каждая новая ОС Android, когда вы пытаетесь раздуть макет для фрагмента, содержащего другой фрагмент.
Единственный поддерживаемый Android способ добавления фрагмента к другому фрагменту - это транзакция из диспетчера дочерних фрагментов.
Просто измените свой XML-макет в пустой контейнер (добавьте идентификатор если необходимо):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragmentContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout>
Затем в методе фрагмента
onViewCreated(View view, @Nullable Bundle savedInstanceState)
:@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); FragmentManager fm = getChildFragmentManager(); SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentByTag("mapFragment"); if (mapFragment == null) { mapFragment = new SupportMapFragment(); FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.mapFragmentContainer, mapFragment, "mapFragment"); ft.commit(); fm.executePendingTransactions(); } mapFragment.getMapAsync(callback); }
4.3
при использовании SupportMapFragment
, определенного в XML. Динамическое создание фрагмента и его ввод в представление контейнера разрешили проблему. См. Этот ответ SO .
– theblang
30 April 2014 в 17:24
SupportMapFragment.newInstance();
developers.google.com/maps/documentation/android-api/map
– Jemshit Iskenderov
17 February 2017 в 19:55
Мое решение:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_map_list, container, false);
// init
//mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map);
// don't recreate fragment everytime ensure last map location/state are maintain
if (mapFragment == null) {
mapFragment = SupportMapFragment.newInstance();
mapFragment.getMapAsync(this);
}
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
// R.id.map is a layout
transaction.replace(R.id.map, mapFragment).commit();
return view;
}
Объявить объект SupportMapFragment глобально
private SupportMapFragment mapFragment;
В методе onCreateView () помещен ниже код
mapFragment = (SupportMapFragment) getChildFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
В onDestroyView () помещен ниже код
@Override
public void onDestroyView() {
super.onDestroyView();
if (mapFragment != null)
getFragmentManager().beginTransaction().remove(mapFragment).commit();
}
В вашем xml-файле, помещенном ниже кода
<fragment
android:id="@+id/map"
android:name="com.abc.Driver.fragment.FragmentHome"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Выше код решил мою проблему, и он отлично работает
Замечание: ваше приложение сильно сработает в любом из двух случаев: -
1) Для повторного использования фрагмента с Картами снова Фрагмент MapView должен быть удален, когда ваш фрагмент, показывающий Карты был заменен другим фрагментом в обратном вызове onDestroyView.
else, когда вы пытаетесь раздуть один и тот же фрагмент дважды Дублирующий идентификатор, тег null или родительский идентификатор с другим фрагментом для com.google.android.gms.maps Ошибка .MapFragment .
2) Во-вторых, вы не должны смешивать операции app.Fragment с операциями API android.support.v4.app.Fragment, например, не использовать android.app.FragmentTransaction для удаления v4.app.Fragment type MapView Fragment , Смешение этого снова приведет к сбою со стороны фрагмента.
Вот пример фрагмента кода для правильного использования MapView
import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; 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.MapFragment; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.serveroverload.yago.R; /** * @author 663918 * */ public class HomeFragment extends Fragment implements LocationListener { // Class to do operations on the Map GoogleMap googleMap; private LocationManager locationManager; public static Fragment newInstance() { return new HomeFragment(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.home_fragment, container, false); Bundle bdl = getArguments(); // setuping locatiomanager to perfrom location related operations locationManager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE); // Requesting locationmanager for location updates locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1, 1, this); // To get map from MapFragment from layout googleMap = ((MapFragment) getActivity().getFragmentManager() .findFragmentById(R.id.map)).getMap(); // To change the map type to Satellite // googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); // To show our current location in the map with dot // googleMap.setMyLocationEnabled(true); // To listen action whenever we click on the map googleMap.setOnMapClickListener(new OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { /* * LatLng:Class will give us selected position lattigude and * longitude values */ Toast.makeText(getActivity(), latLng.toString(), Toast.LENGTH_LONG).show(); } }); changeMapMode(2); // googleMap.setSatellite(true); googleMap.setTrafficEnabled(true); googleMap.setBuildingsEnabled(true); googleMap.setMyLocationEnabled(true); return v; } private void doZoom() { if (googleMap != null) { googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(18.520430, 73.856744), 17)); } } private void changeMapMode(int mapMode) { if (googleMap != null) { switch (mapMode) { case 0: googleMap.setMapType(GoogleMap.MAP_TYPE_NONE); break; case 1: googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); break; case 2: googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); break; case 3: googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN); break; case 4: googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); break; default: break; } } } private void createMarker(double latitude, double longitude) { // double latitude = 17.385044; // double longitude = 78.486671; // lets place some 10 random markers for (int i = 0; i < 10; i++) { // random latitude and logitude double[] randomLocation = createRandLocation(latitude, longitude); // Adding a marker MarkerOptions marker = new MarkerOptions().position( new LatLng(randomLocation[0], randomLocation[1])).title( "Hello Maps " + i); Log.e("Random", "> " + randomLocation[0] + ", " + randomLocation[1]); // changing marker color if (i == 0) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)); if (i == 1) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_BLUE)); if (i == 2) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_CYAN)); if (i == 3) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); if (i == 4) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); if (i == 5) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)); if (i == 6) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_RED)); if (i == 7) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_ROSE)); if (i == 8) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_VIOLET)); if (i == 9) marker.icon(BitmapDescriptorFactory .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW)); googleMap.addMarker(marker); // Move the camera to last position with a zoom level if (i == 9) { CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(randomLocation[0], randomLocation[1])) .zoom(15).build(); googleMap.animateCamera(CameraUpdateFactory .newCameraPosition(cameraPosition)); } } } /* * creating random postion around a location for testing purpose only */ private double[] createRandLocation(double latitude, double longitude) { return new double[] { latitude + ((Math.random() - 0.5) / 500), longitude + ((Math.random() - 0.5) / 500), 150 + ((Math.random() - 0.5) * 10) }; } @Override public void onLocationChanged(Location location) { if (null != googleMap) { // To get lattitude value from location object double latti = location.getLatitude(); // To get longitude value from location object double longi = location.getLongitude(); // To hold lattitude and longitude values LatLng position = new LatLng(latti, longi); createMarker(latti, longi); // Creating object to pass our current location to the map MarkerOptions markerOptions = new MarkerOptions(); // To store current location in the markeroptions object markerOptions.position(position); // Zooming to our current location with zoom level 17.0f googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position, 17f)); // adding markeroptions class object to the map to show our current // location in the map with help of default marker googleMap.addMarker(markerOptions); } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onDestroyView() { // TODO Auto-generated method stub super.onDestroyView(); locationManager.removeUpdates(this); android.app.Fragment fragment = getActivity().getFragmentManager() .findFragmentById(R.id.map); if (null != fragment) { android.app.FragmentTransaction ft = getActivity() .getFragmentManager().beginTransaction(); ft.remove(fragment); ft.commit(); } } }
XML
<fragment android:id="@+id/map" android:name="com.google.android.gms.maps.MapFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
Результат выглядит следующим образом: -
Надеюсь, что это поможет кому-то.
Вложенные фрагменты в настоящее время не поддерживаются. Попробуйте пакет поддержки , версия 11 .
Я уважаю все ответы, но я нашел это одно решение для линейки: Если n - количество вкладок, то:
mViewPager.setOffscreenPageLimit(n);
Пример: В случае, упомянутом выше:
mViewPager.setOffscreenPageLimit(2);
Просмотр пейджера реализует очередь, поэтому вам не нужно удалять этот фрагмент. onCreateView вызывается только один раз.
Вы пытались ссылаться на свой собственный класс MapFragment
в файле макета?
<?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" >
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFragment"
android:name="com.nfc.demo.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
В этом решении вам не нужно принимать статическую переменную;
Button nextBtn;
private SupportMapFragment mMapFragment;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
if (mRootView != null) {
ViewGroup parent = (ViewGroup) mRootView.getParent();
Utility.log(0,"removeView","mRootView not NULL");
if (parent != null) {
Utility.log(0, "removeView", "view removeViewed");
parent.removeAllViews();
}
}
else {
try {
mRootView = inflater.inflate(R.layout.dummy_fragment_layout_one, container, false);//
} catch (InflateException e) {
/* map is already there, just return view as it is */
e.printStackTrace();
}
}
return mRootView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FragmentManager fm = getChildFragmentManager();
SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentById(R.id.mapView);
if (mapFragment == null) {
mapFragment = new SupportMapFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.mapView, mapFragment, "mapFragment");
ft.commit();
fm.executePendingTransactions();
}
//mapFragment.getMapAsync(this);
nextBtn = (Button) view.findViewById(R.id.nextBtn);
nextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Utility.replaceSupportFragment(getActivity(),R.id.dummyFragment,dummyFragment_2.class.getSimpleName(),null,new dummyFragment_2());
}
});
}`
Я думаю, что были некоторые ошибки в предыдущей папке App-Compat lib для дочернего фрагмента. Я попробовал @ Vidar Wahlberg и @ Matt и они не работали для меня. После обновления библиотеки appcompat мой код работает без каких-либо дополнительных усилий.
Я немного опаздываю на вечеринку, но Non из этого ответа помог мне в моем случае. Я использовал карту Google в качестве SupportMapFragment и PlaceAutocompleteFragment как в моем фрагменте. Поскольку все ответы указывали на то, что проблема заключается в том, что SupportMapFragment является картой, которую нужно воссоздать и перерисовать. Но после того, как выкапывание выяснилось, моя проблема была на самом деле с PlaceAutocompleteFragment
. Итак, это рабочее решение для тех, кто сталкиваются с этой проблемой из-за SupportMapFragment и SupportMapFragment
//Global SupportMapFragment mapFragment;
mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mapFragment);
FragmentManager fm = getChildFragmentManager();
if (mapFragment == null) {
mapFragment = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.mapFragment, mapFragment).commit();
fm.executePendingTransactions();
}
mapFragment.getMapAsync(this);
//Global PlaceAutocompleteFragment autocompleteFragment;
if (autocompleteFragment == null) {
autocompleteFragment = (PlaceAutocompleteFragment) getActivity().getFragmentManager().findFragmentById(R.id.place_autoCompleteFragment);
}
И в onDestroyView очистить SupportMapFragment и SupportMapFragment
@Override
public void onDestroyView() {
super.onDestroyView();
if (getActivity() != null) {
Log.e("res","place dlted");
android.app.FragmentManager fragmentManager = getActivity().getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(autocompleteFragment);
fragmentTransaction.commit();
//Use commitAllowingStateLoss() if getting exception
autocompleteFragment = null;
}
}
Другое решение:
if (view == null) {
view = inflater.inflate(R.layout.nearbyplaces, container, false);
}
Вот оно, если не null, вам не нужно повторно инициализировать его удаление из родителя, это необязательный шаг.
У меня было это в viewPager, и авария была связана с тем, что у любого фрагмента должен быть свой собственный тег, дублирующие теги или идентификаторы для одного и того же фрагмента.
Если вы будете использовать только ответ Видара Уолберга, вы получите сообщение об ошибке при открытии другой активности (например) и обратно на карту. Или в моем случае открыть другую активность, а затем снова открыть новую карту (без использования кнопки возврата). Но когда вы примете решение Vidar Wahlberg и решение Matt, у вас не будет исключений.
layout
<com.example.ui.layout.MapWrapperLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/map_relative_layout">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/root">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</RelativeLayout>
</<com.example.ui.layout.MapWrapperLayout>
Фрагмент
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null){
parent.removeView(view);
}
}
try {
view = inflater.inflate(R.layout.map_view, null);
if(view!=null){
ViewGroup root = (ViewGroup) view.findViewById(R.id.root);
...
@Override
public void onDestroyView() {
super.onDestroyView();
Fragment fragment = this.getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.map);
if (fragment != null)
getFragmentManager().beginTransaction().remove(fragment).commit();
}
Это мой ответ:
1, Создайте макет xml, как показано ниже:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
2, в классе Fragment, программно добавьте карту google.
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {@link android.support.v4.app.Fragment} subclass. Activities that
* contain this fragment must implement the
* {@link MapFragment.OnFragmentInteractionListener} interface to handle
* interaction events. Use the {@link MapFragment#newInstance} factory method to
* create an instance of this fragment.
*
*/
public class MapFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
private GoogleMap mMap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_map, container, false);
SupportMapFragment mMapFragment = SupportMapFragment.newInstance();
mMap = mMapFragment.getMap();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.map_container, mMapFragment).commit();
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d("Attach", "on attach");
}
@Override
public void onDetach() {
super.onDetach();
}
}
SupportMapFragment
вonDestroyView
методе. – ULazdins 25 April 2017 в 15:22