2016-09-01 2 views
1

Ich habe Probleme mit Looper und Realm.Realm and Looper shenanigans

ich eine Activity haben, die seine Presenter in onCreate instanziiert() und dann einer seiner öffentlichen Methode aufrufen initFirstLaunch():

RealmChangeListener<CourseDetailed> listener = new RealmChangeListener<CourseDetailed>() { 
    @Override 
    public void onChange(CourseDetailed element) { 
     Log.i("renaud", "courseDetailed.addChangeListener onChange"); 
     computeTableOfContent(element); 
     Log.i("renaud", "1"); 
     playerViewContract.initWithCourseDetails(element); 
     Log.i("renaud", "2"); 
    } 
}; 

public void initFirstLaunch() { 

    courseDetailed = realm.where(CourseDetailed.class).contains("_id", courseId).findFirst(); 

    if (courseDetailed == null) { 
     courseDetailed = realm.createObject(CourseDetailed.class, courseId); 
    } 

    courseDetailed.addChangeListener(listener); 

    Api.getInstance().backend.getCourse(courseId).enqueue(new CustomRetrofitCallBack<CourseDetailed>(playerViewContract) { 
     @Override 
     public void onResponseReceived(final CourseDetailed response) { 

      Realm.getDefaultInstance().executeTransactionAsync(new Realm.Transaction() { 
       @Override 
       public void execute(Realm realm) { 
        realm.copyToRealmOrUpdate(response); 
       } 
      }); 
     } 
    }); 
} 

zur Kenntnis, dass playerViewContract meine Tätigkeit in diesem Zusammenhang ist.

Mein Problem ist, dass onChange() ist manchmal genannt, und wenn es blockiert mein UI Thread (und provoques eventualy eine OutOfMemoryError). Meine Vermutung war, dass ich nicht in einem Looper-Thread war, aber wenn ich Looper.prepare() irgendwo anrufe, stürzt es ab, sagend, dass ich bereits in einem bin.

Was passiert?

Dank


Edit: Bearbeiten initWithCourseDetailed Code

@Override 
public void initWithCourseDetails(final CourseDetailed detailed) { 

    Log.i("renaud", "initWithCourseDetails"); 

    mDrawer.post(new Runnable() { 
     @Override 
     public void run() { 

      String title = detailed.getName(); 
      String subtitle = detailed.getCompany().getName(); 

      if (detailed.getThumbnail() != null) { 

       String picUrl = AppConstants.SERVER_URL + "/api/" + detailed.getThumbnail(); 

       final LinearLayout l = (LinearLayout) mNavigationView.findViewById(R.id.layout); 
       Picasso.with(ModulePlayerActivity.this) 
         .load(picUrl) 
         .config(Bitmap.Config.RGB_565) 
         .into(new Target() { 
          @Override 
          public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { 
           l.setBackground(new BitmapDrawable(getResources(), bitmap)); 
          } 

          @Override 
          public void onBitmapFailed(Drawable errorDrawable) { 
          } 

          @Override 
          public void onPrepareLoad(Drawable placeHolderDrawable) { 

          } 
         }); 
      } 

      TextView nameTv = (TextView) mNavigationView.findViewById(R.id.drawer_header_name); 
      nameTv.setText(title); 

      TextView jobTv = (TextView) mNavigationView.findViewById(R.id.drawer_header_job); 
      jobTv.setText(subtitle); 

      supportInvalidateOptionsMenu(); 

     } 
    }); 
} 

Hinzufügen: Korrektur

Api.getInstance().backend.getCourse(courseId).enqueue(new CustomRetrofitCallBack<CourseDetailed>(playerViewContract) { 
      @Override 
      public void onResponseReceived(final CourseDetailed response) { 

       //TEST 
       Realm realm = null; 
       try { 
        realm = Realm.getDefaultInstance(); 
        realm.executeTransactionAsync(new Realm.Transaction() { 
         @Override 
         public void execute(Realm realm) { 
          realm.copyToRealmOrUpdate(response); 
         } 
        }); 
       } finally { 
        if (realm != null) { 
         realm.close(); 
        } 
        realm = null; 
       } 

      } 
     }); 

Antwort

1

Der UI-Thread ist ein Looper Thread (den Looper hat Looper.getMainLooper()), was bedeutet, dass es autoupdate hat. Auto-Update bedeutet jedoch, dass der ChangeListener, den Sie zu Ihrem RealmObject hinzufügen, immer dann aufgerufen wird, wenn die zugrunde liegende Tabelle geändert wird, und nicht nur einmal.

(Und ich soll auch zu beachten, dass RealmChangeListener s mit schwachen Verweise von Realm zurückgehalten werden Context und so ist die RealmObject, so to keep the autoupdate and the change listener intact even through GC, it has to be kept as a field reference.

Obwohl es auch ist erwähnenswert, dass findFirst() null zurück, wenn das Element nicht gefunden nach ID, sonst gibt das Element sofort zurück.)

So scheint es mir, dass was immer playerViewContract.initWithCourseDetails(element); tut, es tut es immer wieder und schließlich stürzt ab.

Ich hoffe irgendwie, dass ich Ihre Frage beantwortet habe?

+0

Die Dinge sind mir noch nicht klar. Ich protokolliere den Aufruf von 'initWithCourseDetails', und es springt meistens nicht, manchmal sehe ich 1 Protokoll. Ich protokolliere auch den 'OnChange'-Aufruf, der immer einmal aufgerufen wird. Ich verstehe, dass es jedes Mal aufgerufen wird, wenn mein "RealmModel" aktualisiert wird, das ist das Verhalten, nach dem ich suche. Ich verstehe nicht, warum der Aufruf von 'initWithCourseDetails' meinen Modellwechselgedanken betrifft, es ist eine reine Ansichtsmethode. (Ich füge 'initWithCourseDetails' Code hinzu) –

+0

Ich habe gerade Ihren 'RealmChangeListener' Punkt bekommen, ich habe ihn geändert, um ein Feld meines Presenters zu sein. Könntest du mir einfach nochmal erklären warum du denkst dass 'onChange' infinit mal heißt? Und ich merke, dass ich nicht danke für die Beantwortung von mir gesagt habe, das ist sehr geschätzt Ich versichere Ihnen –

+0

Nun technisch, wenn Sie die Tabelle nur einmal ändern, dann sollte es nur einmal aufgerufen werden. Wenn es jedoch nur einmal aufgerufen wird, sollte Ihr Code nicht abstürzen, es sei denn, Ihr 'computeTableOfContent (Element);' oder 'initWithCourseDetails' hängt irgendwie in einer Schleife fest ...' createObject() 'sollte nicht funktionieren, außer Sie ' In einer Transaktion bin ich ein wenig unzufrieden mit diesem Code. Kann ich Ihnen empfehlen, meinen [Artikel] zu lesen (http: // medium.com/@ Zhuinden/how-to-use-Realm-für-Android-wie-ein-Champ-und-wie-sagen-wenn-du-tun-es-falsch-ac4f66b7f149) auf Realm-Nutzung? – EpicPandaForce