main thread in run methode (beantwortet)

  • 11 Antworten
  • Letztes Antwortdatum
C

cederick

Neues Mitglied
0
Ich habe den Fehler gefunden, damit ist der Thread beantwortet es ist aber eine folge Frage entstanden die hier:
while Schleife macht Probleme im neuen Thread
zu finden ist.


Ich habe einen Fehler der scheinbar kein fehler ist...
Ich habe einen ViewFlipper der in und out animationen hat die in animationen bekommen ein Listener zugewiesen:

Code:
    @Override
    public void onAnimationEnd(Animation animation) {
        int child = vf.getDisplayedChild();
            Integer index_of_last = vf.indexOfChild(findViewById(R.id.end_of_vf));
            if ( child == index_of_last) {
                setContentView(MainActivity.this.fl);
                if (!MainActivity.this.fl.getChildAt(0).equals(surf_view)) {
                    MainActivity.this.fl.addView(surf_view, 0);
                }
            }
            if (child == 4 && !started) {
                started = true;
                start_sv(true);
            }
            if (child == 3 || child == 1) {
                vf.showNext();
            }
    }
Wenn jetzt der ladebildschirm (child 4) angezeigt wird, wird die Surface_view gestartet, das bedeutet eine weitere Klasse wird initialisiert und in dieser Klasse wird sofort ein Thread gestartet:

Code:
    public void surf_view_resume() {
        isrunning=true;
        this_thread = new Thread(this);
        this_thread.start();
    }
dann startet diese run metode:
Code:
    @Override
    public void run() {
        int i=0;
        while(i<=1000000000){
            i++;
        }
        h.post(new Runnable() {
            @Override
            public void run() {
                running_listener.onisrunning(isrunning);
calc.calc_resume();
            }
        });
        while (isrunning) {
            if (holder.getSurface().isValid()&& !calc.isStartcalc()) {
                calc.setStartcalc(true);
                Canvas canvas = holder.lockCanvas();
                setcanvas(canvas);
                holder.unlockCanvasAndPost(canvas);
            }
        }
    }
Die while schleife ist nur um das laden von Daten zu simmulieren, "running_listener.onisrunning(isrunning);" startet im main Thread den nächsten schritt (text wird angezeigt und view wird clickable).

Um jetzt endlich zu meinem Problem zu kommen, wenn der Thread gestartet wird scheint in 7 von 10 Fällen der mainthread beschäftigt zu sein, ich habe das herausgefunden in dem ich nach
" if (child == 4 && !started) {
started = true;
start_sv(true);
", einen Dialog gestartet habe und dieser ist erst nach einer Zeit, die der Zeit die für die while-schleife benötigt wird, aufgetaucht. Außerdem wird in diesen 7 von 10 fällen ein schwarzer Bildschirm angezeigt obwohl der Ladebildschirm einen weißen background hat, erst wenn auch der Text angezeigt werden soll (nach der while-schleife) wird auch der Ladebildschirm richtig angezeigt. Der Mainthread hat während der Ladezeit nichts zu tun außer den Ladebildschirm sichtbar zu machen, dann wartet er auf das Signal (durch "running_listener.onisrunning(isrunning);") um die schrift auf dem Ladebildschirm anzuzeigen und die View Clickable zu machen usw.

Mir ist klar das OnanimationEnd zu früh ausgelöst wird und es deshalb einen schwarzen Bildschirm gibt. Das Problem ist nur das dieser so lange angezeigt wird.
Nachdem der Text angezeigt wurde funktioniert übrigens alles wieder und in den 3 von 10 Fällen funktioniert die App auch normal.
 
Zuletzt bearbeitet:
Dein Code ist sehr schwer lesbar, bitte halte dich an die Java Nomenklatur, damit es für andere leichter ist, nur als Tipp wenn man Hilfe möchte in Zukunft.

Deiner Beschreibung ist auch nur schwer zu folgen. Bitte angeben welche While schleife wann gemeint ist.

Ich sehe nur :
1. While schleife zählt einfach bis x(wahrscheinlich soll diese die Daten laden simulieren...warum nicht einfach ein sleep?)
2. wird ein neuer Thread gestartet mit 1 MEthode und einer Funktion die aufgerufen werden nacheinander.
3. Zum Schluss nehme ich an das in der 3. While Schleife versucht wird eine "calc" zu starten und der Bildschirm wird gemalt.

verstehe jetzt den Sinn davon nciht bzw. die Logik dahinter müsstest du nochmal genau erklären.
 
  • Danke
Reaktionen: cederick
Sry, ich bringe mir das momentan alles selbst bei mithilfe google^^, deshalb ist das vll nicht so strukturiert.
Ich will auch nicht soviel hier rein posten denn dann könnte das lesen noch schwieriger werden bzw. länger dauern.
hier nochmal der Ablauf:
1. nach einem tippen auf einen Button startet eine Animation (fade in)
2. wenn die Animation abgelaufen ist, wird der Ladebildschirm angezeigt
3. der Ladebildschirm ist das 5. child deshalb wird hier :
cederick schrieb:
@override
public void onAnimationEnd(Animation animation) {
int child = vf.getDisplayedChild();//vf=ViewFlipper
Integer index_of_last = vf.indexOfChild(findViewById(R.id.end_of_vf));//vf=ViewFlipper
if ( child == index_of_last) {
setContentView(MainActivity.this.fl);//fl=Framelayout
if (!MainActivity.this.fl.getChildAt(0).equals(surf_view)) {//fl=Framelayout
MainActivity.this.fl.addView(surf_view, 0);//fl=Framelayout
}
}
if (child == 4 && !started) {
started = true;
start_sv(true);
}
if (child == 3 || child == 1) {
vf.showNext();
}
}
"start_sv(true);" gecalled
4. diese metode sieht so aus:
Code:
        if (first) {
//temporaer leer^^
        } else {
            // irrelevant
        }
        if (first) {
            this.surf_view = new surf_view(this,this, sls, this,fl,slot);
        }

5. wie du siehst wird hier "surf_view" initialisiert der contructor sieht dann so aus:
Code:
    public surf_view(Context context,error_msg_interface errorListener ,save_load_sys sls, OnisrunningListener listener, ViewGroup vg, Integer save_slot) {
        super(context);
        this.context=context;
        this.errorListener=errorListener;//interface callback
        this.vg=vg;//viewgroup
        this.sls=sls;//saveloadsystem
        this.running_listener = listener;//interface callback
        this.slot = save_slot;//eine Integer
        setFocusable(true);
        this.holder = getHolder();
        if(!init){
            init_it();// hier werden views und canvas vorbereitet
        }
        //resume it (last)
        h=new Handler();
        surf_view_resume();
    }
6. "surf_view_resume();" startet einen neuen Thread:
cederick schrieb:
public void surf_view_resume() {
isrunning=true;
this_thread = new Thread(this);
this_thread.start();
}
7. der Thread sieht so aus:
cederick schrieb:
@override
public void run() {
int i=0;
while(i<=1000000000){
i++;
}
h.post(new Runnable() {
@override
public void run() {
running_listener.onisrunning(isrunning);
calc.calc_resume();
}
});
while (isrunning) {
if (holder.getSurface().isValid()&& !calc.isStartcalc()) {
calc.setStartcalc(true);
Canvas canvas = holder.lockCanvas();
setcanvas(canvas);
holder.unlockCanvasAndPost(canvas);
}
}
}
Ich hoffe das hilft dir wenigstens ein bisschen, jetzt muss ich aber fragen hast du die Frage überhaupt verstanden?

Thread.sleeptime(); war das oder ?... naja das war ja nur um es zu testen und mir fiel die Schleife eben als erstes ein.
 
Ich habe die Frage scon verstanden denke ich mal.

was ist das mit den Methoden des calc objektes?

Sieht mir nach einer Racecondition aus.

Der Canvas wird nur gezeichnet wenn "!calc.isStarted()"
Wenn ich richtgi vermute setzt ein call zur Methode calc_resume() des clac objektes den "started"-member(oder wie auch immer der heißt bei dir) des calcsebenfalls auf true so dass du in der 2. Whileschleife ein true zurückbekommst beim Prüfen ob schon gestartet und daurch dann nciht gezeichnet wird.
 
... naja nicht so ganz calc ist auch ein objekt mit einem Thread der eine Schleife beinhaltet.
Die Abfrage soll nur dafür sorgen das es synchron abläuft sonst kann es passieren das einer von beiden Threads
ein zweites mal startet und dadurch wichtig Zeit verloren geht.

aber wichitger ist das es nichts mit dem Problem zu tun hat ... naja vll muss ich doch mehr posten:
cederick schrieb:
running_listener.onisrunning(isrunning);
-dieser listener führt zu dieser Methode:
Code:
@Override
    public void onisrunning(Boolean isrunning) {
        loading_screen.continue_it();
    }
-das loading_screen Objekt behandelt alles was mit dem ladebildschirm zu tun hat aber hier steht nur:
Code:
    public void continue_it(){
        but.setClickable(true);
        but.setText("tippe zum fortfahren");

    }
Deshalb dachte ich es wäre irrelevant aber vll ist es ganz nützlich um es zu verstehen.
Also der Ladebildschirm wird nicht in der SurfaceView gezeichnet, wäre auch ziemlich blöd weil bevor sie gezeichnet wird wird ja alles geladen. Damit würde ich es ja erst nach dem Laden sehen.
Aber das macht den MainThread um so wichtiger weil während geladen wird soll ja tortzdem etwas auf dem Bildschirm passieren.
 
Zuletzt bearbeitet:
Wo wird der Lade Bildschirm denn sonst gezeichnet?
 
du siehst ja oben das das in continue_it(); angepasst wird also ist der Ladebildschirm logischerweise im Layout schon enthalten also in diesem Fall im ViewFlipper deshalb auch die Onanimation metode.

cederick schrieb:
1. nach einem tippen auf einen Button startet eine Animation (fade in)
2. wenn die Animation abgelaufen ist, wird der Ladebildschirm angezeigt
3. der Ladebildschirm ist das 5. child deshalb wird hier :
cederick schrieb:
@override
public void onAnimationEnd(Animation animation) {
int child = vf.getDisplayedChild();
Integer index_of_last = vf.indexOfChild(findViewById(R.id.end_of_vf));
if ( child == index_of_last) {
setContentView(MainActivity.this.fl);
if (!MainActivity.this.fl.getChildAt(0).equals(surf_view)) {
MainActivity.this.fl.addView(surf_view, 0);
}
}
if (child == 4 && !started) {
started = true;
start_sv(true);
}
if (child == 3 || child == 1) {
vf.showNext();
}
}
... usw.
Ich hätte das hier vll etwas präziser machen können aber ich meine natürlich das 5. child eines ViewFlippers.
 
Das Surfaceview hast du aber nicht im Viewflipper drin oder?! Die vertragen sich nciht weil man SurfaceView nciht als normale View sehen darf...

edit: ok das ganze framelayout ist da im Viewflipper....ne du darfst die Sutrfaceview und deinen Viewflipper nciht zusammen verwenden...

KAnnst du eine Referenz deines Ladebildschirmes mal implementieren und es in der vodergrund bringen. Kann sein dass du die ganze Zeit Pech hast und sich die Surfaceview in den Vordergrund schiebt weil diese erstspäter addiert wird ud sich spät aufbaut erst....
 
siehe hier:
cederick schrieb:
@override
public void onAnimationEnd(Animation animation) {
int child = vf.getDisplayedChild();
Integer index_of_last = vf.indexOfChild(findViewById(R.id.end_of_vf));
if ( child == index_of_last) {
setContentView(MainActivity.this.fl);
if (!MainActivity.this.fl.getChildAt(0).equals(surf_view)) {
MainActivity.this.fl.addView(surf_view, 0);
}
}
if (child == 4 && !started) {
started = true;
start_sv(true);
}
if (child == 3 || child == 1) {
vf.showNext();
}
}
nachdem continue_it(); wird durch ein oncllick event das if Statemant mit true beantwortet und dann wird ein FrameLayout mit dem surf_view mit setContentView sichtbar gemacht aber auch das kann nicht das Problem sein, weil das erst sichtbar gemacht wird nachdem der Fehler schon vorbei ist.

Ich glaube du hast das Problem doch noch nicht ganz verstanden.
Nachdem ich den Thread in der surf_view gestartet habe scheint der MainThread auch für eine gewisse Zeit in dem Thread zu sein deshalb beendet er die Animation nicht und damit wird mein Ladebildschirm nicht angezeigt bis das Laden schon vorbei ist.
Denn dann scheinen MainThread und der neue Thread wieder getrennt zu agieren.
D.h. die Schrift wird angezeigt und vorallem die Animation wird vollendet.

Ich habe schon probiert mit dem Handler früher auf den MainThread zuzugreifen und das komische war, dann wurde die animation weitergeführt also hatte ich dann einen grauen Bildschirm (Mischung aus weiß und schwarz) aber das kann ja nicht die Lösung sein vorrallem wenn ich später noch mehr in der Ladezeit machen will.

Und wie gesagt scheint der Fehler auch nicht immer aufzutreten nur in 7 von 10 Fällen.
[DOUBLEPOST=1442599837,1442599681][/DOUBLEPOST]Es kann also nur daran liegen das die Animation aus i-einem Grund nicht vollendet wird oder wie gesagt der MainThread aus i-einem Grund beschäftigt ist.
 
Tut mir Leid wenn ich dir nicht helfen konnte.
Denke einfach daran das SurfaceView kein normales View ist und nicht animiert werden kann. Von daher kann man denen auch in keinem ViewFlipper einf+gen auch nciht später im Code.
Versuche Raceconditions zwischen Threads aufzulösen.
Stelle Sicher dass dein Ladebildschirm im Vordergrund angezeigt wird. Das Framelayout ist Z geordnet, jede View die geaddet wird schiebt sich dabei in den Vordergrund.
Verscuhe manuell ein Neuzeichnen deiner Lade View zu erzwingen mit der invalidate() methode.
Benutze LogCat ausgaben um den Fehler auf bestimmte Stellen zu lokalisieren, Mutmaßungen bringen nichts.

Ansonsten Viel Erfolg

Jaiel out...
 
  • Danke
Reaktionen: cederick
Ich habe deswegen hier auch einmal eine Frage erstellt gehabt da war das meine Lösung(Im Fall Surface nicht in ViewFlipper).
Wie gesagt die warten aufeinander.
Der Ladebildschirm wird im ViewFlipper nicht im Framelayout angezeigt und man kann die View auch als 0tes child adden, dann ist sie im Hintergrund.
Habe ich jetzt Probiert funktioniert leider auch nicht -.- .
Das Problem ist das ich wohl schlechte vorraussetzungen habe, mein PC ist ziemlich schlecht und das starten des emulators kann durchaus mal einen halben Tag dauern xD wenn es überhaupt lädt. Ich habe auch ein Tablet was sich allerding mit Windows 7 zu beißen scheint... das zeigt sich durch freezen des explorers wenn ich auf Computer gehe und Bluescreen wenn ich den PC anschließend herunterfahre trotz extra von der Herrsteller Seite installierter Software.
Deshalb kann ich Bridge auch vergessen.
Ich muss mich aber trotzdem bedanken das du dir die Zeit genommen hast und immer wieder schnell geantwortet hast.
 
<<--- in meinem Profil befindet sich ein Wortwitz ^^

Ich habe jetzt herausgefunden das die While Schleife tatsächlich das Problem darstellt, denn nachdem ich es jetzt zu Thread.sleep(10000); geändert habe funktioniert es in 20 von 20 Fällen Ich habe jetzt also das Problem ausgemacht weiß aber immernoch nicht warum das so ist.
Ich werde einen neuen Thread erstellen damit man nicht alles durch lesen muss um die Warum frage zu beantworten.
Ich schreibe das auch oben Rein damit man es sieht.
 
Zurück
Oben Unten