片段上的 Mapbox 膨胀视图

Posted

技术标签:

【中文标题】片段上的 Mapbox 膨胀视图【英文标题】:Mapbox Inflate View on Fragment 【发布时间】:2016-04-12 12:36:18 【问题描述】:

我在为 android 片段上的 Mapbox MapView 充气时遇到问题。当我在 Activity 上使用相同的代码时(除了 Activity 和 Fragment 之间的标准差异),我可以让 MapView 正确加载,但不能在 Fragment 上。

Mapbox 也有一个 MapFragment 类here,但我不确定如何在 Fragment 中正确使用它(示例仍在 Activity 中);借助 Google Maps API,我可以毫无问题地在 Fragment 上使用 MapView。

以下 logcat 行:

at com.example.exampleapp.FragmentMap.onCreateView(FragmentMap.java:133)

指的是Java行:

fragmentLayout = inflater.inflate(R.layout.fragment_map, container, false);

这里是这个问题的相关代码以及日志:

fragment_map.xml:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    android:layout_
    android:layout_ >

    <com.mapbox.mapboxsdk.views.MapView
        android:id="@+id/mapview"
        android:layout_
        android:layout_
        mapbox:access_token="@string/access_token"/>

    <android.support.v7.widget.CardView
        android:id="@+id/map_card"
        android:layout_
        android:layout_
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp">
        <com.mapbox.mapboxsdk.views.MapView
            android:layout_
            android:layout_
            android:id="@+id/mini_map"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"
            mapbox:access_token="@string/access_token"/>
    </android.support.v7.widget.CardView>

FragmentMap.java:

public class FragmentMap extends Fragment 
    private MapView mv, miniMap;
        View fragmentLayout;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
        fragmentLayout = inflater.inflate(R.layout.fragment_map, container, false);

    mv = (MapView) fragmentLayout.findViewById(R.id.mapview);
    mv.onCreate(savedInstanceState);

    miniMap = (MapView) fragmentLayout.findViewById(R.id.mini_map);
    miniMap.onCreate(savedInstanceState);

    return fragmentLayout;



@Override
public void onStart() 
    super.onStart();
    mv.onStart();
    miniMap.onStart();

@Override
public void onStop() 
    super.onStop();
    mv.onStop();
    miniMap.onStop();



@Override
public void onDestroy() 
    super.onDestroy();
    mv.onDestroy();
    miniMap.onDestroy();


@Override
public void onResume() 
    super.onResume();
    mv.onResume();
    miniMap.onResume();


@Override
public void onPause() 
    super.onPause();
    mv.onPause();
    miniMap.onPause();

@Override
public void onLowMemory() 
    super.onLowMemory();
    mv.onLowMemory();
    miniMap.onLowMemory();


@Override
public void onSaveInstanceState(Bundle outState) 
    super.onSaveInstanceState(outState);
    mv.onSaveInstanceState(outState);
    miniMap.onSaveInstanceState(outState);

日志猫:

01-07 08:07:00.548 710-710/com.example.exampleapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.exampleapp, PID: 710
android.view.InflateException: Binary XML file line #13: Error inflating class com.mapbox.mapboxsdk.views.MapView
at android.view.LayoutInflater.createView(LayoutInflater.java:633)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at com.example.exampleapp.FragmentMap.onCreateView(FragmentMap.java:133)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:552)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:514)
at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:495)
at android.support.design.widget.TabLayout$ViewPagerOnTabSelectedListener.onTabSelected(TabLayout.java:1778)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:871)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:841)
at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1115)
at android.support.design.widget.TabLayout$1.onClick(TabLayout.java:665)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19884)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:288)
at android.view.LayoutInflater.createView(LayoutInflater.java:607)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at com.example.exampleapp.FragmentMap.onCreateView(FragmentMap.java:133)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:552)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:514)
at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:495)
at android.support.design.widget.TabLayout$ViewPagerOnTabSelectedListener.onTabSelected(TabLayout.java:1778)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:871)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:841)
at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1115)
at android.support.design.widget.TabLayout$1.onClick(TabLayout.java:665)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19884)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
Caused by: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.exampleapp-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libmapbox-gl.so"
at java.lang.Runtime.loadLibrary(Runtime.java:366)
at java.lang.System.loadLibrary(System.java:988)
at com.mapbox.mapboxsdk.views.NativeMapView.<clinit>(NativeMapView.java:42)
at com.mapbox.mapboxsdk.views.MapView.initialize(MapView.java:680)
at com.mapbox.mapboxsdk.views.MapView.<init>(MapView.java:621)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:288)
at android.view.LayoutInflater.createView(LayoutInflater.java:607)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:743)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at com.example.exampleapp.FragmentMap.onCreateView(FragmentMap.java:133)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1962)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1106)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:552)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:514)
at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:495)
at android.support.design.widget.TabLayout$ViewPagerOnTabSelectedListener.onTabSelected(TabLayout.java:1778)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:871)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:841)
at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1115)
at android.support.design.widget.TabLayout$1.onClick(TabLayout.java:665)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19884)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)

应用分级:

buildscript 
    repositories 
        mavenCentral()
    
    dependencies 
        classpath 'com.android.tools.build:gradle:1.3.0'
    


apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

repositories 
    mavenCentral()
    jcenter()


android 
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig 
        applicationId "com.example.exampleapp"
        minSdkVersion 19
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    
    useLibrary 'org.apache.http.legacy'

    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        
    


dependencies 
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:cardview-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
    compile 'com.google.android.exoplayer:exoplayer:r1.5.2'
    compile 'com.google.android.gms:play-services-auth:8.3.0'
    compile 'com.google.android.gms:play-services-maps:8.3.0'
    compile('com.mapbox.mapboxsdk:mapbox-android-sdk:2.3.0@aar') 
        transitive = true
    
    compile files('libs/commons-lang3-3.3.2.jar')

项目结构:

【问题讨论】:

你能附上你的项目文件夹结构的截图吗?问题可能在于错误放置libmapbox-gl.so 刚刚添加的app gradle 是的,你可能是对的,但我之前使用过 Mapbox 没有问题,根本不需要处理这个问题。事实上,我可以在 Activity 中获得一个 Mapbox 视图来处理这个应用程序,而无需更改任何其他内容。 我会尽快截取截图 检查您在android/java/lib/src/main/jniLibs/armeabi-v7a/android/java/lib/src/main/libs/armeabi-v7a/android/java/lib/src/main/jni/armeabi-v7a/ 中是否有libmapbox-gl.so - 这些位置之一应该可以工作(不确定哪一个) 【参考方案1】:

您正在谈论通货膨胀,但请查看堆栈跟踪:

引起:java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip 文件 "/data/app/com.example.exampleapp-2/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] 找不到“libmapbox-gl.so” java.lang.Runtime.loadLibrary(Runtime.java:366) 在 java.lang.System.loadLibrary(System.java:988) 在 com.mapbox.mapboxsdk.views.NativeMapView.(NativeMapView.java:42) 在 com.mapbox.mapboxsdk.views.MapView.initialize(MapView.java:680) 在 com.mapbox.mapboxsdk.views.MapView.(MapView.java:621)

顺便说一句:

第一

你需要决定是每次都膨胀视图局部变量)还是重用它(全局变量)

示例:

if(_view==null) 
   _view = inflater.inflate(..);
return _view;

秒:

不要手动调用onCreate onPause之类的activity或者fragment方法(os用来维护生命周期的方法)

第三个:

如果你使用 viewpager 和嵌套片段,你需要创建带有子片段管理器的适配器

更多和更多:

请记住,在子片段 viewpager 片段中设置一些数据和属性需要布局

“第一:我每次都在膨胀它,这通常不是问题(我的标签可以与我创建的任何其他片段一起使用,包括谷歌地图,但不是 Mapbox)第二:是的,你确实调用了活动手动生命周期方法。您必须使用 onCreate 来膨胀视图。第三:我有一个适配器,我只是没有在此处包含它。这不是问题,我的选项卡可以与我创建的任何其他片段一起正常工作。最后:我'不知道你在说什么,但我的片段在我的其他标签中工作正常。

请关注手头的问题...将 Mapbox 视图放在片段中,> 无论该片段在哪里(标签页查看器与否).. – TangoJLabs"

/**
 * Called to do initial creation of a fragment.  This is called after
 * @link #onAttach(Activity) and before
 * @link #onCreateView(LayoutInflater, ViewGroup, Bundle).
 *
 * <p>Note that this can be called while the fragment's activity is
 * still in the process of being created.  As such, you can not rely
 * on things like the activity's content view hierarchy being initialized
 * at this point.  If you want to do work once the activity itself is
 * created, see @link #onActivityCreated(Bundle).
 *
 * @param savedInstanceState If the fragment is being re-created from
 * a previous saved state, this is the state.
 */
public void onCreate(@Nullable Bundle savedInstanceState) 
    mCalled = true;

将它从片段的 onCreate 移动到 onViewCreated(View,Bundle)

mv = (MapView) fragmentLayout.findViewById(R.id.mapview);
mv.onCreate(savedInstanceState);

miniMap = (MapView) fragmentLayout.findViewById(R.id.mini_map);
miniMap.onCreate(savedInstanceState);


/**
 * Called immediately after @link #onCreateView(LayoutInflater, ViewGroup, Bundle)
 * has returned, but before any saved state has been restored in to the view.
 * This gives subclasses a chance to initialize themselves once
 * they know their view hierarchy has been completely created.  The fragment's
 * view hierarchy is not however attached to its parent at this point.
 * @param view The View returned by @link #onCreateView(LayoutInflater, ViewGroup, Bundle).
 * @param savedInstanceState If non-null, this fragment is being re-constructed
 * from a previous saved state as given here.
 */
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 

最后一句话:gradle 文件

我不知道您的文件内容是否同时包含 gradle 文件或仅包含应用程序文件,但这些行不应该在应用程序 gradle 文件中 - 这些是*** gradle:

buildscript 
    repositories 
        mavenCentral()
    
    dependencies 
        classpath 'com.android.tools.build:gradle:1.3.0'
    


repositories 
    mavenCentral()
    jcenter()

你应该考虑迁移到最新的 android 应用插件 - 但我看到你正在使用 gms 服务 - 所以你的*** gradle 文件包含其他插件,上面的那些被省略了

我无法按照您的编辑逻辑进行操作。我没有可以从中移动任何东西的 onCreate

/** inflate fragment  - this will create view */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    return inflater.inflate(R.layout.fragment_map, container, false);


/** after view is created - set map view */
@Override
public void onViewCreated(View view, Bundle savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);

    if(view!=null) 
       MapView mv = (MapView) view.findViewById(R.id.mapview);
       mv.onCreate(savedInstanceState);
    

顺便说一句,我对其余的生命周期方法有更多的担忧——片段可以或不保留状态,所以简单地将活动生命周期方法放在片段方法中可能会产生更多问题:)

我不使用 & 不知道 MapView 的源实现,所以我不能告诉你如何实现这个,但我可以给你一个提示,在你调用任何 mapview 方法之前检查片段是否附加到活动

@ceph3us -1 这里提到的一切都是错误的,你的语法 可以改进。我没有答案,我在这里 同样的问题。第一个根视图不应该是一个字段,它应该是 每次调用 onCreateView 时都会膨胀,第二个是正确的调用,第三个 其余的都是题外话,对主题没有帮助。 ——海登凯

@海登凯

    首先请指定来源供您审议 为什么要重新创建视图?目的 ?浪费资源(比如你编写代码和用户 CPU 和 MEM 的时间)? - 在那里你可以负担得起或需要一个新的然后没关系,但在其他情况下 REUSE !!! 视图根本不需要膨胀,它可以正常创建,例如通过返回 new LinearLayout(Context) 或 FrameLayout 或任何其他复杂视图 - 这是使用 xml 或 java 的开发人员选择 - 我不喜欢使用 xml - 我喜欢纯 JAVA :) 所以最后我可以说你的 -1 对我来说是空的

【讨论】:

第一:我每次都在充气,这通常不是问题(我的标签可以与我创建的任何其他片段一起使用,包括谷歌地图,但不是 Mapbox)第二:是的,你确实打电话活动生命周期方法手动。您必须使用 onCreate 来膨胀视图。第三:我有一个适配器,我只是没有在这里包含它。这不是问题,我的选项卡可以与我创建的任何其他片段一起正常工作。最后:我不确定你在说什么,但我的片段在我的其他标签中工作正常。 请关注手头的问题...将 Mapbox 视图放入片段中,无论该片段在哪里(标签页查看器与否)... 我无法按照您的编辑逻辑进行操作。我没有可以从中移动任何东西的 onCreate。 @HaydenKai 对你很友好 - 顺便说一句,你值得特别编辑 :)【参考方案2】:

这个库看起来处于繁重的开发状态,可能存在一些问题,这些问题在 GitHub 上有所提及,尤其是在您运行 2.2.0 版本时。

尝试将版本更改为最新的稳定版:

compile 'com.mapbox.mapboxsdk:mapbox-android-sdk:3.0.0'

【讨论】:

很遗憾,Mapbox 3.0.0 没有解决这个特定的错误,但 Damian 是对的,Mapbox Android SDK 显然正在大力开发。希望 Mapbox 能在不久的将来提供在 Fragment 中使用的文档。 我遇到了同样的问题。您是说 Mapbox MapView 不能用于片段吗?那将是一个真正的耻辱。 @jmc34 在有问题的 cmets 中存在聊天链接。你可以阅读我与 Tango 的讨论。 我已经设法在 Fragment 中使用 Mapbox 3.2 视图,但是一旦引入 ViewPager,我就会收到类似的膨胀错误,但没有“找不到”/unsatsfiedLinkError。可以在这里查看我的问题:***.com/questions/35557857/…

以上是关于片段上的 Mapbox 膨胀视图的主要内容,如果未能解决你的问题,请参考以下文章

Android:在片段内膨胀自定义视图

java 片段将重用以前膨胀的根视图,这可以节省内存。好可怜 ......

手动膨胀视图上的 layout()

Android:自定义视图上的膨胀异常

在画布上绘制片段视图

片段未附加到我的活动