Как обойти final в java?

270
12 мая 2017, 14:49

Надо проверить массив на длину. И если он пустой создать маркеры, а если нет - обновлять их местоположение. Но никак не могу достучаться до массива маркеров. Сволоч объявлен final.

timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        Marker[] marker = new Marker[fullDrivers.size()];
        final Marker[] finalMarker = marker;
        MapsActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (fullDrivers.size()>=1) {
                    for (int i = 0; i < fullDrivers.size(); i++) {
                        if (finalMarker[i]!=null){
                            finalMarker[i].setPosition(transfomation(fullDrivers.get(i).getLatlng()));
                        }
                        finalMarker[i] = mMap.addMarker(new MarkerOptions().position(transfomation(fullDrivers.get(i).getLatlng())));
                    }
                }
            }
        });
    }
},0,6000);

Я вынужден его так делать. Как мне обойти это?

Answer 1

Модификатор final не делает переменную константой, он всего лишь делает константой ссылку на переменную. В случае с примитивами, если ссылка становится константой, то и переменная тоже (не Ваш случай), в случаях с объектами это значит, что переменную нельзя поменять на другую, но параметры текущей можно изменять.

Проблема не в модификаторe final, а в непонимании его сути, но так как Вы не расписали, что значит достучаться, сложно предположить в чем настоящая проблема - ругается компилятор или ошибка в процессе выполнения? Вы везде опираетесь на fullDrivers.size(), особенно в цикле, хотя правильнее было бы опираться на finalMarker.length, вдруг за промежуток времени до выполнения в главном потоке у Вас изменился размер fullDrivers.size() и Вы лезете за пределы массива? runOnUiThread не гарантирует моментальное выполнения в главном потоке, он всего лишь ставит Ваш блок кода в очередь на выполнение в главном потоке.

Могу предложить вариант написания кода без модификатора final у массива маркеров:

final Handler handler = new Handler();
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        Marker[] marker = new Marker[fullDrivers.size()];
        for (int i = 0; i < marker.length; i++) {
            if (marker[i]!=null){
                marker[i].setPosition(transfomation(fullDrivers.get(i).getLatlng()));
            }
            marker[i] = mMap.addMarker(new MarkerOptions().position(transfomation(fullDrivers.get(i).getLatlng())));
        }
        handler.postDelayed(this, 6000);
    }
};
runnable.run();

А когда надо остановите повтор выполнения методом:

handler.removeCallbacks(runnable);

Хотя если почитать документацию, то можно оставить Ваш вариант с таймером без метода runOnUiThread, в документации я не увидел, чтобы TimerTask в Timer выполнялся в другом потоке.

Answer 2
  1. Вы каждый раз пересоздаете массив. Ветка if(finalMarker[i]!=null) никогда не выполнится.
  2. Каждые 6 секунд все маркеры буду двоиться, а потом троиться и так далее.... При всем при этом массив смысла не имеет, код эквивалентен созданию маркеров раз в 6 секунд. Вероятно else пропустили.

Такой вариант:

private Map<Driver, Marker> markers = new HashMap<>();
private Timer timer = new Timer();
void initTimer(){
    timer.scheduleAtFixedRate(new TimerTask(){
        void run(){
            runOnUIThread(new Runnable(){
                void run(){
                    updateMarkers();
                }
            });
        }
    }, 0, 6000);
}
void updateMarkers(){
   for(Driver driver: fullDrivers){
       Marker marker = markers.get(driver);
       if(marker == null){ 
           // добавляем новый маркер
           markers.add(driver, mMap.addMarker(
               new MarkerOptions()
                   .position(transfomation(driver.getLatlng())));
       } else {
           // изменяем существующий
           marker.setPosition(transfomation(driver.getLatlng()));
       }
   }
   //Удаляем лишние маркеры
   if(markers.size() > fullDrivers.size()){
       Iterator<Map.Entry<Driver, Marker>> it = markers.entrySet().iterator();
       while (it.hasNext()){
           Map.Entry<Driver, Marker> entry = it.next();
           if(!fullDrivers.contains(entry.getKey())){
               // Удаляем маркер. Что-то типа
               mMap.removeMarker(entry.getValue());
               it.remove();
           }
       }
   }
}
Answer 3

Вы не можете изменить переменную с модификатором final, это обозначения констант а тут finalMarker[i] = mMap.addMarker(new MarkerOptions().position(transfomation(fullDrivers.get(i).getLatlng()))); вы ей присваиваете новое значения, уберите финал или у вас есть другой массив маркеров. Ну а если уж очень нужно, то вроде рефлекшен может менять все что угодно, то вот сылка: private + final = "Нельзя изменить"

Answer 4
private void updateMarkers() {
    for(FullDriver driver: fullDrivers){
        Marker marker = markers.get(driver);
        if(marker == null){
            // добавляем новый маркер
            markers.put((List<FullDriver>) driver, mMap.addMarker(
                    new MarkerOptions()
                            .position(transfomation(driver.getLatlng()))));
        } else {
            // изменяем существующий
            marker.setPosition(transfomation(driver.getLatlng()));
        }
    }
}

вот и ошибка

05-12 15:43:16.341 3324-3324/xyz.justart.getallandposition E/AndroidRuntime: FATAL EXCEPTION: main
                                                                             Process: xyz.justart.getallandposition, PID: 3324
                                                                             java.lang.ClassCastException: xyz.justart.getallandposition.FullDriver cannot be cast to java.util.List
                                                                                 at xyz.justart.getallandposition.MapsActivity.updateMarkers(MapsActivity.java:207)
                                                                                 at xyz.justart.getallandposition.MapsActivity.access$100(MapsActivity.java:32)
                                                                                 at xyz.justart.getallandposition.MapsActivity$2$1.run(MapsActivity.java:194)
                                                                                 at android.os.Handler.handleCallback(Handler.java:739)
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                 at android.os.Looper.loop(Looper.java:148)
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:7325)
                                                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
READ ALSO
Относительный и абсолютный путь include, PHP

Относительный и абсолютный путь include, PHP

У меня есть такая строчка в файле indexphp

398
Одновременно воспроизводить видео

Одновременно воспроизводить видео

Можно ли сделать так чтобы видео играло одновременно на разных компютерах(браузерах) ?

243
Взгляд со стороны

Взгляд со стороны

Здравствуйте, я совсем новичок, требуется создать форму, при заполнении которой значения будут улетать в БД, наведите на путь правильный...

354
Как на карту leaflet засунуть select используя angular-leaflet-directive?

Как на карту leaflet засунуть select используя angular-leaflet-directive?

На сайте использую angular, появилась необходимость встроить на сайт картуВыбрал leaflet, но офф решений для angular не нашел, однако нашел angular-leaflet-directive

238