当前位置: 首页 > 知识库问答 >
问题:

在本机android应用程序中管理UnityPlayer生命周期时出错

史谦
2023-03-14

我正在开发一个需要在activiy中加载UnityPlayer实例的android应用程序,使用以下论坛帖子中的代码作为指南:

http://forum.unity3d.com/threads/98315-Using-Unity-Android-In-a-Sub-View .

最初,应用程序在一个名为“UnityActivity.java”的活动中正确地显示了UnityPlayer。

当用户导航回主活动(通过按下硬件后退按钮或单击操作栏后退按钮),然后尝试重新打开UnityActive时,问题就开始了。在这种情况下,会显示一个黑屏,而不是UnityPlayer。论坛中的一位用户建议将onP和onResume生命周期事件转发到UnityPlayer,如下面的代码所示。但是,当这样做时,会出现以下错误,应用程序崩溃。

这是第一次导航到Unityactive时记录的:

W/libc(21095):pthread_createsched_setscheduler调用失败:不允许操作

单击后退按钮时会记录此错误:

编舞(20963):已经有一个挂起的vsync事件。一次只能有一个

第二次导航到UnityActivity时会记录此错误:

A/libc(21095):0x00000000(code=1)处的致命信号11(SIGSEGV),线程21176(thread-5073)

...在这一点上,我被踢出了应用程序。

这是主要活动MainActivity.java的摘录:

public void startUnityActivity(View view) {
        Intent intent = new Intent(this, UnityActivity.class);
    startActivity(intent);
}

这是Unity活动UnityActivity.java的摘录:

public class UnityActivity extends ActionBarActivity {
    UnityPlayer m_UnityPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

         setContentView(R.layout.activity_unity);

        m_UnityPlayer = new UnityPlayer(this);
        int glesMode = m_UnityPlayer.getSettings().getInt("gles_mode", 1);
        m_UnityPlayer.init(glesMode, false);

        FrameLayout layout = (FrameLayout) findViewById(R.id.unityView);
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        layout.addView(m_UnityPlayer, 0, lp);
        m_UnityPlayer.windowFocusChanged(true);
        m_UnityPlayer.resume();
    }
    @Override
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);
        m_UnityPlayer.windowFocusChanged(hasFocus);
    }
    @Override
    public void onPause() {
         super.onPause();  
         m_UnityPlayer.pause();
    }
    @Override
    public void onResume() {
        super.onResume(); 
        m_UnityPlayer.resume();
    }

这就是清单中描述活动的方式. /AndroidManifest.xml

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.package.example.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity 
        android:name="com.package.example.UnityActivity" 
        android:label="@string/title_activity_unity" 
        android:screenOrientation="portrait" 
        android:launchMode="singleTask" 
        android:parentActivityName="com.package.example.MainActivity"
        android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
    </activity>
</application>

这是如何定义UnityActive的布局.../res/布局/activity_unity.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.package.example.UnityActivity"
tools:ignore="MergeRootFrame" >
    <FrameLayout
    android:id="@+id/unityView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    </FrameLayout>
</FrameLayout>

如果有任何提示和解决方案能为我指明正确的方向,我将不胜感激。

共有3个答案

裴宏壮
2023-03-14

我对此没有明确的答案,但我发现了一些有趣的人

1-pthread_create警告android谈论W/libc(21095):pthread_createsched_setscheduler调用失败:操作不允许的帖子开始后调用pthread_create函数我收到下一条消息:我从帖子中引用:

此错误意味着,尝试创建线程的进程没有适当的权限来设置指定的调度优先级。

标记为“答案”的帖子提供了一些有用的信息。请看一下,但在代码中您没有调用pthread\u create()--[1]

2-Logcat W/Choreograph er(20963)中编排器消息的含义:已经有一个挂起的vsync事件。我引用一次应该只有一个

编排器允许应用程序将自己连接到vsync,并正确计时以提高性能。

是的,我是。我知道Choreographer可能是处理动画的组件,当它没有足够的cpu周期时,它会跳过一些帧并输出此调试消息,因此这与UI上的动画有关---[2]

所以呢?基于[1]和[2]:这是Unity生成的动画的问题,不受您的控制,

我自己的结论和意见是:这是Unity代码中的一个Bug,需要由Unity修复?也许?

对不起,如果没有帮助,但我已经试过了。我从未与Unity合作过,但我试图从其他一些帖子中得出结论。

祝你们好运

燕刚捷
2023-03-14

这个问题是两年前提出的,但我仍然很难找到一个关于它的详细指南。

所以我写了一个

主要想法是将Unity项目作为本机android应用程序中的库使用。

我希望这本指南能帮助别人。

尤茂材
2023-03-14

好的,先简单的事情

W/libc(21095): pthread_create sched_setscheduler call failed: Operation not permitted

你对此无能为力。当你直接从Unity for Android编译时,你甚至会发现这个问题,所以这是引擎内部的一个问题。

你链接的指南已经过时了。你不再需要从不同的位置复制文件来创建一个简单的Android项目。

  1. 通过设置构建设置创建Android项目-

您的新Android项目中的类UnityPlayerNativeActive向您展示了如何设置UnityPlayer以及您需要转发哪些事件。这是Unity 4.3.4使用的版本

package de.leosori.NativeAndroid;

import com.unity3d.player.*;
import android.app.NativeActivity;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;

public class UnityPlayerNativeActivity extends NativeActivity
{
    protected UnityPlayer mUnityPlayer;     // don't change the name of this variable; referenced from native code

    // UnityPlayer.init() should be called before attaching the view to a layout - it will load the native code.
    // UnityPlayer.quit() should be the last thing called - it will unload the native code.
    protected void onCreate (Bundle savedInstanceState)
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);

        getWindow().takeSurface(null);
        setTheme(android.R.style.Theme_NoTitleBar_Fullscreen);
        getWindow().setFormat(PixelFormat.RGB_565);

        mUnityPlayer = new UnityPlayer(this);
        if (mUnityPlayer.getSettings ().getBoolean ("hide_status_bar", true))
            getWindow ().setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN,
                                   WindowManager.LayoutParams.FLAG_FULLSCREEN);

        int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
        boolean trueColor8888 = false;
        mUnityPlayer.init(glesMode, trueColor8888);

        View playerView = mUnityPlayer.getView();
        setContentView(playerView);
        playerView.requestFocus();
    }
    protected void onDestroy ()
    {
        mUnityPlayer.quit();
        super.onDestroy();
    }

    // onPause()/onResume() must be sent to UnityPlayer to enable pause and resource recreation on resume.
    protected void onPause()
    {
        super.onPause();
        mUnityPlayer.pause();
    }
    protected void onResume()
    {
        super.onResume();
        mUnityPlayer.resume();
    }
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
        mUnityPlayer.configurationChanged(newConfig);
    }
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);
        mUnityPlayer.windowFocusChanged(hasFocus);
    }
    public boolean dispatchKeyEvent(KeyEvent event)
    {
        if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
            return mUnityPlayer.onKeyMultiple(event.getKeyCode(), event.getRepeatCount(), event);
        return super.dispatchKeyEvent(event);
    }
}

尽管UnityPlayerNativeActive扩展了NativeActive,但据我所知,您仍然可以从ActionBaractive扩展而没有任何问题。至少在我的实验期间它起作用了。

您缺少的最重要的部分是在onDestroy()期间对mUnityPlayer.quit()的调用。试图在旧的UnityPlayer还在运行时创建一个新的实例将导致崩溃、挂起活动和无尽的痛苦。

修复了当你从UnityActivity返回时,你可能会惊讶地发现整个应用程序都关闭了<代码>市政图层。quit()将终止其内部运行的进程。调用mUnityPlayer后,没有一个方法会执行。quit(),即使onDestroy()方法也无法完成。

通往胜利的道路是通过将参数android: Process=": UnityKillsMe添加到您的活动中,将您的UnityActive作为一个新进程开始。

你的情况是这样的

<activity 
    android:name="com.package.example.UnityActivity" 
    android:label="@string/title_activity_unity" 
    android:screenOrientation="portrait" 
    android:launchMode="singleTask" 
    android:process=":UnityKillsMe"
    android:parentActivityName="com.package.example.MainActivity"
    android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale">
    <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
    <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
</activity>

我不确定参数unityplayer。ForwardNativeEventsToDalvik。。。一开始创建的项目将其设置为false,并且官方(过时)文档提到

由于触摸/运动事件是在本机代码中处理的,Java视图通常看不到这些事件。然而,Unity中有一种转发机制,允许事件传播到DalvikVM。

在我的小例子项目中,我看不到有什么不同

你需要找到一个工作流程,将你的开发与Unity和Android项目相结合,反之亦然。再次使用Unity导出将与您在Android项目中所做的更改相冲突,因此您需要导出到一个单独的文件夹中,并从Android项目链接到Unity部分。

根据上述留档,您可以将编译的Android类和AndroidManifest.xml作为插件集成到Unity中。

生成的. class文件应压缩为. jar文件并放置在Assets-

祝你好运

 类似资料:
  • Django为管理活动提供了一个随时可用的用户界面。 我们都知道管理界面对于Web项目很重要。 Django根据您的项目模型自动生成管理UI。 启动管理界面 Admin界面依赖于django.countrib模块。 要使其正常工作,您需要确保在myproject/settings.py文件的INSTALLED_APPS和MIDDLEWARE_CLASSES元组中导入一些模块。 对于INSTALLE

  • 项目是许多应用程序的总和。 每个应用程序都有一个目标,可以重复使用到另一个项目中,比如网站上的联系表单可以是一个应用程序,并且可以重用给其他人。 将其视为项目的一个模块。 创建一个应用程序 我们假设您在项目文件夹中。 在我们的主“myproject”文件夹中,相同的文件夹然后manage.py - $ python manage.py startapp myapp 你刚刚创建了myapp应用程序

  • 我在活动类中使用这些函数:onSaveInstanceState onRestoreInstanceState onPause onCreate 当用户启动活动时,onCreate会被调用,当用户结束时,onPance会被调用。到目前为止还不错。 但是当用户旋转手机时,onPence onSaveInstanceState onCreate会被调用。我本以为在onCreate之前会有onResto

  • The application module lets you manage the life cycle of your NativeScript apps from starting the application to storing user-defined settings. application模块允许你从启动应用到保存用户自定义设置整个过程进行生命周期管理。 Start Appli

  • 该节将带领大家了解Kubernetes中的基本概念,尤其是作为Kubernetes中调度的最基本单位Pod。 本节中包括以下内容: 了解Pod的构成 Pod的生命周期 Pod中容器的启动顺序模板定义 Kubernetes中的基本组件kube-controller-manager就是用来控制Pod的状态和生命周期的,在了解各种controller之前我们有必要先了解下Pod本身和其生命周期。

  • 本文向大家介绍Android Service生命周期?相关面试题,主要包含被问及Android Service生命周期?时的应答技巧和注意事项,需要的朋友参考一下 onCreate() 首次创建服务时,系统将调用此方法。如果服务已在运行,则不会调用此方法,该方法只调用一次。 onStartCommand() 当另一个组件通过调用startService()请求启动服务时,系统将调用此方法。 onD