2012-02-25 9 views
10

Tôi đang cố gắng hiển thị MapView bên trong một đoạn (sử dụng thư viện tương thích bị tấn công). Sau đây đã chỉ làm việc tốt trong quá khứ:MapView bên trong Fragment - con được chỉ định đã có một phụ huynh

  • đoạn của onCreateView() chỉ đơn giản là trả về một mới FrameLayout
  • đoạn của onActivityCreated() nhận được MapView từ Acitivity và thêm nó vào xem hệ thống cấp bậc của nó
  • onDestroyView() loại bỏ các MapView từ của nó xem hệ thống phân cấp

Bây giờ tôi muốn đoạn sử dụng bố cục được xác định trong xml để tôi có thể có một số nội dung giao diện người dùng khác. Đưa yếu tố MapView trong file bố trí luôn bị treo, vì vậy tôi đang làm nó theo cách này:

map_screen_fragment.xml

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


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

</LinearLayout> 

My MapScreenActivity giữ thực tế MapView, và đoạn gọi getMapView(), vì vậy tôi không chạy vào "không thể có nhiều hơn một MapView" vấn đề:

MapScreenActivity.java

public class MapScreenActivity extends FragmentActivity { 
    protected Fragment fragment; 
    protected MapView mapView; 

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

     if (savedInstanceState == null) { 
      fragment = new MapScreenFragment(); 

      getSupportFragmentManager().beginTransaction().add(R.id.root_container, fragment) 
        .commit(); 
     } 
    } 

    public MapView getMapView() { 
     if (mapView == null) { 
      mapView = new MapView(this, getResources().getString(R.string.maps_api_key)); 
     } 

     return mapView; 
    } 
} 

MapScreenFragment.java

public class MapScreenFragment extends Fragment { 
    protected ViewGroup mapContainer; 
    protected MapView mapView; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle args) { 
     View root = inflater.inflate(R.layout.map_screen_fragment, container); 
     mapContainer = (ViewGroup) root.findViewById(R.id.map_container); 
     return root; 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     mapView = ((MapScreenActivity) getActivity()).getMapView(); 
     mapView.setClickable(true); 
     mapView.setBuiltInZoomControls(true); 

     mapContainer.addView(mapView); 

    } 

    @Override 
    public void onDestroyView() { 
     super.onDestroyView(); 
     mapContainer.removeView(mapView); 
    } 

} 

Về lý thuyết, điều này tất cả phải làm việc theo cách tương tự như new FrameLayout phương pháp mô tả đầu tiên. Tuy nhiên, tôi có được điều này mỗi khi:

02-24 18:01:28.139: E/AndroidRuntime(502): FATAL EXCEPTION: main 
02-24 18:01:28.139: E/AndroidRuntime(502): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.mapfragment/com.example.mapfragment.MapScreenActivity}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.ActivityThread.access$1500(ActivityThread.java:117) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.os.Handler.dispatchMessage(Handler.java:99) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.os.Looper.loop(Looper.java:130) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.ActivityThread.main(ActivityThread.java:3683) 
02-24 18:01:28.139: E/AndroidRuntime(502): at java.lang.reflect.Method.invokeNative(Native Method) 
02-24 18:01:28.139: E/AndroidRuntime(502): at java.lang.reflect.Method.invoke(Method.java:507) 
02-24 18:01:28.139: E/AndroidRuntime(502): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
02-24 18:01:28.139: E/AndroidRuntime(502): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
02-24 18:01:28.139: E/AndroidRuntime(502): at dalvik.system.NativeStart.main(Native Method) 
02-24 18:01:28.139: E/AndroidRuntime(502): Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.view.ViewGroup.addViewInner(ViewGroup.java:1976) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.view.ViewGroup.addView(ViewGroup.java:1871) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.view.ViewGroup.addView(ViewGroup.java:1828) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.view.ViewGroup.addView(ViewGroup.java:1808) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.support.v4.app.NoSaveStateFrameLayout.wrap(Unknown Source) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.support.v4.app.BackStackRecord.run(Unknown Source) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.support.v4.app.FragmentManagerImpl.execPendingActions(Unknown Source) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.support.v4.app.FragmentActivity.onStart(Unknown Source) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1129) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.Activity.performStart(Activity.java:3791) 
02-24 18:01:28.139: E/AndroidRuntime(502): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1620) 
02-24 18:01:28.139: E/AndroidRuntime(502): ... 11 more 

tôi đã cố gắng loại bỏ các các MapView từ đó là cha mẹ trước khi trở về từ getMapView(), và đó vẫn bị treo. Tôi thực sự không hiểu tại sao phương pháp này không hiệu quả, bất kỳ sự trợ giúp nào cũng sẽ được đánh giá cao.

Trả lời

15

Tôi không chắc liệu đây có phải là vấn đề tương tự như bạn đang gặp phải hay không, nhưng hóa ra là lạm phát là ổn, miễn là bạn không đính kèm vào thư mục gốc.

Ví dụ, bạn cần phải làm điều gì đó như thế này:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    return inflater.inflate(R.id.my_layout, container, false); 
} 

Nếu bạn thất bại trong việc thêm rằng false luận cuối cùng để các inflate() cuộc gọi, sau đó bạn sẽ nhận được IllegalStateException.

Tôi nghĩ điều đang xảy ra là không có đối số false bổ sung, cây xem được tăng cao của bạn được gắn vào chế độ xem gốc (container) và sau đó khi Bắt đầu hoạt động, hệ thống sẽ cố gắng thêm cây xem vào gốc một lần nữa . Do đó lỗi.

+1

Đã một thời gian kể từ khi tôi xem lại dự án đó, nhưng các mảnh vỡ khá mới đối với tôi vào thời điểm đó, vì vậy tôi nghi ngờ đây thực sự là câu trả lời đúng. – Karakuri

+1

Cảm ơn vì điều này, đã không nhận ra những gì đang xảy ra cho đến khi bạn cho thấy đối số cuối cùng :) – lfxgroove

+0

Cuộc gọi tốt, cảm ơn vì điều đó. :-) –

0

[UPDATE] Tôi đã viết một thư viện nhỏ, nghiền tất cả các giải pháp này LocalActivityManager với nhau: https://github.com/coreform/android-tandemactivities

[bài cũ] Bạn nên

mapContainer.removeView(mapView); 

trước khi bạn

mapContainer.addView(mapView); 

để tránh một ngoại lệ như vậy.

... giống như trong dòng trước đây.

OK, followup sau khi nhận xét:

Hãy thử điều này:

if(mapView.getParent() != null) { 
    mapContainer.addView(mapView); 
} 
+0

Tôi cũng đã thử điều đó và nó không hoạt động. Vẫn đưa ra cùng một lỗi chính xác. – Karakuri

+0

Tôi cũng đã thử các biến thể trên '((ViewGroup) mapView.getParent()). RemoveView (mapView)', và không có biến nào trong số đó hoạt động. – Karakuri

+0

thử tìm hiểu xem cha mẹ của bạn đã được gắn vào MapView nào. nếu nó là cha mẹ mà bạn định thêm nó vào, thì nó được thêm vào để bạn có thể xử lý trường hợp với logic hoặc câu lệnh try/catch. Tôi ue các giải pháp tôi đăng trong ý kiến ​​về chủ đề này: http://nextlevelandroid.com/?p=114 (ý kiến ​​của lindo) nó hoạt động và không yêu cầu mỗi Friggen FragmentActivity để mở rộng MapActivity! – straya

1

Sau khi thử vô số sự vật, tôi đã kết thúc làm điều này:

Quan điểm gốc tôi trở về trong onCreateView() được tạo ra theo chương trình, không tăng cao. Tuy nhiên, việc tăng lượt xem khác và thêm chúng dưới dạng trẻ em vào chế độ xem gốc được lập trình có vẻ không gây ra bất kỳ sự cố nào.

Có ai đó không thể tìm ra những gì đằng sau hành vi kỳ lạ này. Hy vọng điều này có thể hữu ích cho người khác.

EDIT

Nó được một lúc kể từ khi tôi xem xét lại chủ đề này, nhưng khi tôi gọi lại, này sẽ không làm việc cho tôi ...

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) { 
    return inflater.inflate(R.layout.some_layout, container, false); 
} 

... trong khi này sẽ làm việc cho tôi ...

private ViewGroup mapContainer; 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) { 
    mapContainer = new LinearLayout(getActivity()); 
    return mapContainer; 
} 

.. và sau đó trong onActivityCreated() Tôi sẽ nhận được một MapView từ hoạt động và thêm nó làm con của mapContainer. Nếu tôi muốn các khung nhìn khác (giống như một tiêu đề phía trên MapView), tôi có thể thổi phồng chúng một cách riêng biệt và thêm chúng vào mapContainer, như đoạn mã này cho thấy.

private ViewGroup mapContainer; 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) { 
    mapContainer = new LinearLayout(getActivity()); 
    mapContainer.setOrientation(LinearLayout.VERTICAL); 
    View headerView = inflater.inflate(R.layout.some_layout, mapContainer, false); 
    mapContainer.addView(headerView); 
    return mapContainer; 
} 
+0

Bạn có thể đăng một ví dụ xin vui lòng? –

0

Đây là những gì làm việc cho tôi ... Bất cứ khi nào tôi chuyển sang mảnh tôi đã làm

if (mapContainer.getChildAt(0) != null){ 
     mapContainer.removeViewAt(0); 
} 

tôi không đưa rằng trong onDestroy của tôi() hoặc các phương pháp onPause(). Tôi đã làm điều đó bất cứ khi nào tôi chuyển mảnh vỡ. Vì lý do nào đó, đoạn của tôi không gọi onPause().

Trong phương pháp của tôi onResume() tôi đã làm

mapContainer.addView(mapView); 

và tất cả mọi thứ làm việc cho tôi. Không có thêm IllegalStateExceptions.