Повысить видимость интерфейса - PullRequest
0 голосов
/ 27 февраля 2019

У меня есть два пакета:

1. com.test.hidden:

Содержит защищенный интерфейс MyListener и открытый класс FancyClass с открытым методом для регистрации MyListener объектов:

package com.test.hidden;
public class FancyClass {
    public void registerListener(MyListener listener) {
        // ...
    }
}

package com.test.hidden;
interface MyListener {
    void doSomething();
}

2. com.test.myapp:

Здесь у меня естьэкземпляр FancyClass, и я хочу зарегистрировать для него новый объект MyListener.

Очевидно, это не будет работать, поскольку MyListener не отображается в com.test.myapp.Моя интуиция заключалась в том, чтобы создать новый интерфейс в com.test.hidden, который расширяет MyListener и является общедоступным:

package com.test.hidden;
public interface MyListenerWrapper extends MyListener {
    @Override
    void doSomething();
}

package com.test.myapp
import com.test.hidden.FancyClass
import com.test.hidden.MyListenerWrapper

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        val fc = FancyClass()
        fc.registerListener(object : MyListenerWrapper {
            override fun doSomething() {
                // ...
            }
        })
    }
}

Но я получаю IllegalAccessError:

java.lang.IllegalAccessError: Illegal class access: 'com.test.myapp.MainActivity' attempting to access 'com.test.hidden.MyListener' (declaration of 'com.test.myapp.MainActivity' appears in /data/app/com.test.myapp-ZzNlHhuBCCdAEV4QsZHspw==/base.apk)
        at com.test.myapp.MainActivity.onCreate(MainActivity.kt:15)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2899)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3054)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1814)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:280)
        at android.app.ActivityThread.main(ActivityThread.java:6710)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Когда я изменяю видимость MyListener на общедоступную, она прекрасно работает, поэтому я подозреваю, что Java не любит увеличивать видимость интерфейсов в подынтерфейсах.Почему это не работает и как это решить?

1 Ответ

0 голосов
/ 27 февраля 2019

Kotlin не любит выставлять внутренние API в публичных методах, и даже делает это, если вы делаете это.Это также влияет на код Java, если вы вызываете код из Kotlin, но выдает исключение во время выполнения, а не во время компиляции.

Что касается решений, у Kotlin есть internal, но это действительно специальное ключевое слово:в отличие от частного пакета Java (без модификатора), внутренний делает его видимым везде в модуле.

Это также одно решение: конвертировать в Kotlin и использовать internal.Если вы создаете библиотеку, она не будет видна за пределами модуля, но вы сможете объявить ее как минимум внутри.

Второй - преобразование интерфейса в класс и использование sealed class.Обратите внимание, что для этого необходимо, чтобы все дочерние элементы были объявлены в одном файле.См. this для получения дополнительной информации о закрытых классах.

И окончательное решение: сделайте его публичным.Я очень рекомендую вам пойти на это по сравнению с другими альтернативами, в основном потому, что это самый простой вариант, который не требует хакерского дизайна.Кроме того, если вы планируете получить доступ к интерфейсу в другом месте, вам придется использовать конкретные реализации, а не общий суперкласс, что не всегда возможно (хотя зависит от вашего использования).

И естьтакже вариант использования только Java, но я предполагаю, что вы бы предпочли микширование, так как вы уже делаете это.Но, как сказал Майкл , вам следует избегать такого дизайна: это плохой дизайн.Если бы я был тобой, я бы обнародовал это в любом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...