2012-02-23 13 views
6

Mam narzędzie onClickListener, które wyzwala wywołanie sieciowe, więc chciałbym mieć jakiś sposób, aby pokazać użytkownikowi, że komunikacja jest w toku. Problem, na który napotykam, polega na tym, że nie wydaje mi się, aby wywołać ProgressDialog lub zmienić w jakikolwiek sposób interfejs użytkownika, zanim wywołanie zostanie wykonane wewnątrz programu nasłuchującego onClick. Cały kod działa dobrze, ale zmiany interfejsu nie wchodzą w życie dopiero po uruchomieniu całego kodu w onClickListener.Czy onClickListener nie aktualizuje interfejsu użytkownika, dopóki cały kod w nim nie działa w systemie Android?

Zastanawiam się, czy mój problem polega po prostu na tym, że anonimowa wewnętrzna klasa, taka jak onclicklistener, może zaktualizować interfejs tylko pod koniec swojego biegu? A może mój kod jest po prostu zły.

góry dzięki

Poniżej znajduje się kod dla słuchacza onclick:

 relayButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       cPanel.throwProgress(NCDTCPRelayActivity.this); 

       System.out.println(tvSocketConnection.getText().toString()); 

       if (relayStatusArray[relayNumber] == 0) 
       { 
        if (cPanel.TurnOnRelay(relayNumber, 1) == false) 
        { 
         changeTitleToRed(); 
        }else{ 
         changeTitleToGreen(); 
        } 
       } 
       else { 
        if (cPanel.TurnOffRelay(relayNumber, 1) == false){ 
         changeTitleToRed(); 
        }else{ 
         changeTitleToGreen(); 
        } 
       } 
       cPanel.hideProgress(NCDTCPRelayActivity.this); 
      } 
     }); 

Oto kod na throwProgress i hideProgress odpowiednio (są w podklasie aktywności):

public boolean throwProgress(Context mContext) { 
    System.out.println("INSIDE THROWPROGRESS"); 
    try { 
     tempDialog = ProgressDialog.show(mContext, "Connecting", "Connecting", true); 
    } 
    catch (RuntimeException e) { 
     return false; 
    } 
    return true; 
} 
public boolean hideProgress(Context mContext) { 
    System.out.println("OUTSIDE THROWPROGRESS"); 
    tempDialog.hide(); 
    return true; 
} 

** Edycja Oto nowy kod dla narzędzia onClickListener, w którym umieściłem wersję roboczą:

  public void onClick(View v) { 
       cPanel.throwProgress(NCDTCPRelayActivity.this); 
       System.out.println(tvSocketConnection.getText().toString()); 

       handler.post(new Runnable() { 

        @Override 
        public void run() { 
         // TODO Auto-generated method stub 
         if (relayStatusArray[relayNumber] == 0) 
         { 
          if (cPanel.TurnOnRelay(relayNumber, 1) == false) 
          { 
           changeTitleToRed(); 
          }else{ 
           changeTitleToGreen(); 
          } 
         } 
         else { 
          if (cPanel.TurnOffRelay(relayNumber, 1) == false){ 
           changeTitleToRed(); 
          }else{ 
           changeTitleToGreen(); 
          } 
         } 
         cPanel.hideProgress(NCDTCPRelayActivity.this); 
         relayStatusArray = cPanel.getBankStatus(1); 
         updateButtonText(); 
        } 

       }); 
      } 

Odpowiedz

3

Zmiana interfejsu użytkownika z obsługi kliknięcia powinna działać dobrze. Problem prawdopodobnie polega na tym, że robisz ciężką pracę nad wątkiem interfejsu użytkownika i blokujesz go, aby okno dialogowe nie było naprawdę aktualizowane, dopóki cała ta praca nie zostanie wykonana. Spróbuj przenieść wszystkie ciężkie uniesienia do AsyncTask (przeczytaj this doc, jeśli nie jesteś tego obcy), ukrywając okno dialogowe po zakończeniu zadania i zobacz, czy to naprawi.

+0

Cóż, połączenie sieciowe znajduje się na AsyncTask, ale używam metody AsyncTask(). Execute(). Get(), aby wątek ui czekał na odpowiedź, ponieważ cały program jest używany do uzyskania tych poleceń sieciowych do cel i uzyskiwanie odpowiedzi aresponse. To tylko praca, abyśmy nie dostali wyjątku od sieci w głównym wątku. Czy kod przed wywołaniem nie zostanie wykonany przed kodem za nim? – Poodimizer

+0

Nie wywołuj get() w głównym wątku. Zastąp AsyncTask.onPostExecute() i obsłuż tam odpowiedź. – gngr44

+1

@Poodimizer Nie rób tego! Skutecznie pokonujesz cały cel "AsyncTask", przekształcając go w niepotrzebnie rozbudowane * synchroniczne * zadanie! – Santa

3

Wszystkie aktualizacje interfejsu użytkownika są opóźnione w systemie Android, a także praktycznie na każdej platformie GUI. Zmiany wyglądu widoku nigdy nie są renderowane od razu; zamiast tego, podsystem GUI zaznacza widok jako "potrzebuje przerysowywania" i wywołuje po pewnym czasie draw() w pętli komunikatów.

Jeśli chcesz, aby coś miało miejsce po aktualizacji ekranu, użyj Handler.post(). Kod "ed" post() wykona pewien czas w pętli komunikatów, zwykle później niż w kolejce kodu losowania.

Dodatkowy węzeł: Windows GUI jest szczęśliwym wyjątkiem od tej reguły; możesz może rysować na oknie Windows poza WM_PAINT. Ale na Androida nie możesz.

+0

Próbowałem dodać runnable i umieszczenie w nim połączenia sieciowego, ale nadal nie dostaję pokaz ProgressDialog throwProgressBar. Czy zrobiłem to poprawnie? Dodałem nową sekcję w oryginalnym poście z uruchomionym w nim wpisem. – Poodimizer

Powiązane problemy