Kotlin代码"不要将Android上下文类放在静态字段中#34;抱怨

时间:2018-03-18 04:06:08

标签: android kotlin

我有一个用Java编写的基于Android Studio的应用程序。我工作得很好 并且不会导致Android Studio抱怨任何事情:

public class MainActivity extends AppCompatActivity {

  static Context maincActivityContext;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mainActivityContext = getApplicationContext();
    ...
  }

  /* JNI function called from c++ */
  private void updateStatus(String event, final String call) {
    ...
    runOnUiThread(new Runnable() {
      @Override
      public void run() {
            TextView caller_uri = new TextView(mainActivityContext);
            ...
      }
    });
  }
  ...
}

然后我去找Android Studio将其转换为Java 到科特林。转换后,MainActivity看起来像这样:

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)
    mainActivityContext = applicationContext
    ...
  }

  /* JNI function called from C++ */
  private void updateStatus(String event, final String call) {
    ...
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            TextView caller_uri = new TextView(mainActivityContext);
            ...
        }
    });
  }

  companion object {
    internal lateinit var mainActivityContext: Context
    ...
  }
}

否则在Java版本中,但类变量mainActivityContext 从MainActivity的顶部移动到伴侣对象。现在又来了 应用程序工作正常,但Android Studio抱怨 mainActivityContext变量声明:

Do not place Android context classes in static fields

然后我将声明移回了Java版本中的位置:

class MainActivity : AppCompatActivity() {

  internal lateinit var mainActivityContext: Context

  override fun onCreate(savedInstanceState: Bundle?) {
    mainActivityContext = applicationContext
    ...

并且Android Studio很满意。但是,当我试图 运行应用程序,它崩溃了这样:

  

03-18 16:08:52.788 7467 7467 E AndroidRuntime:kotlin.UninitializedPropertyAccessException:lateinit属性mainActivityContext尚未初始化

     

03-18 16:08:52.788 7467 7467 E AndroidRuntime:at com.foo.bar.MainActivity.updateStatus(MainActivity.kt:362)

确定变量是(像之前一样)在onCreate函数中初始化。

问题:

为什么runOnUIThread代码中没有初始化,以及在那里初始化变量的正确方法是什么?

我之前检查了有关此主题的主题,但无法找到(或理解)这里适用的答案。

3 个答案:

答案 0 :(得分:1)

永远不要在static字段(Kotlin中进入companion object)中放置任何Android上下文,这是一种不好的做法,因为你可以通过这种方式获得内存泄漏。 / p>

如果要访问类中的上下文,或者在其构造函数中传递上下文,或者如果类类似于活动,请使用getApplicationContext()来访问上下文。

在您的示例中,您根本不需要存储上下文,因为您的活动实际上是Context本身(您可以使用this作为上下文)。

答案 1 :(得分:0)

异常的原因是因为在初始化之前访问lateint属性

尝试更换:

internal lateinit var mainActivityContext: Context

var appContext: Context? = null

答案 2 :(得分:0)

我能够通过将活动上下文作为参数传递给启动本机应用程序的函数,然后将其作为updateStatus函数的参数传递回MainActivity,从而完全摆脱mainActivityContext变量:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        Thread(Runnable { nativeAppStart(applicationContext) }).start()
    }
}

原生应用程序如下所示:

static jobject *appContext;

JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_baresipStart(JNIEnv *env, jobject thiz, jobject *context)
{
    appContext = context;
    ...
}

及其updateStatus调用如下所示:

jmethodID statusId = (*env)->GetMethodID(env, pctx->jniHelperClz,
                                         "updateStatus",
                                         "(Landroid/content/Context;Ljava/lang/String)V");
...
(*env)->CallVoidMethod(env, pctx->jniHelperObj, statusId, appContext, status);

现在我在updateStatus函数中有可用的应用程序上下文,接下来的问题是如何使用它来设置内容视图。我将发布另一个关于它的问题。

感谢所有贡献者。