Autore Topic: Errata TimerTask?  (Letto 679 volte)

Offline uelfox

  • Nuovo arrivato
  • *
  • Post: 38
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Tablet mediacom 8" MP842M
  • Sistema operativo:
    Win 7
Errata TimerTask?
« il: 02 Maggio 2014, 00:44:46 CEST »
0
Buonasera,
   sto cercando di inserire nel mio codice, la lettura al mio db.
La connessione al db, avviene senza problemi, e pensavo di creare un timer, che con un certa frequenza, andasse a leggere i dati necessari nel db, per poi aggiornare alcune TextView presenti nella main.
Ma ciò non avviene, perchè nel momento che parte il primo tick del timer, la app. va in crash!!
Allego il codice che sto provando, e dalle non chiare informazioni che ho trovato, sembra che io non possa aggiornare la main, quando sono all'interno di un thread.
Mi potere aiutare su come posso risolvere?
Grazie

Codice (Java): [Seleziona]
package com.example.test.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Timer;
import java.util.TimerTask;

import net.sourceforge.jtds.jdbc.*;

public class MainActivity extends Activity {
    private Connection db = null;
    Timer clock;
    TextView testo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testo = (TextView)findViewById(R.id.textView);

        new Test1().execute();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item){
        switch (item.getItemId()){
            case R.id.info:
                new AlertDialog.Builder(this).setTitle("Informazioni").setMessage("\u00A9 Domo versione 0.1").setNeutralButton("Chiudi", null).show();
                return true;
            case R.id.sviluppatore:
                new AlertDialog.Builder(this).setTitle("Sviluppatore").setMessage("Io medesimo\n\nuelfox@hotmail.it").setNeutralButton("Chiudi", null).show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private class Test1 extends AsyncTask<Void, Void, Integer>{
        @Override
        protected Integer doInBackground(Void... params){
            try{
                Class.forName("net.sourceforge.jtds.jdbc.Driver").newInstance();
                db = DriverManager.getConnection("jdbc:jtds:sqlserver://192.168.0.132/namedb;user=sa;password=pass;instanceName=SQLEXPRESS");
                return 1;
            }
            catch (Exception e){
                return 0;
            }
        }

        @Override
        protected void onPostExecute(Integer result){
            if(result == 1){
                Toast.makeText(getApplicationContext(), "Connesso", Toast.LENGTH_LONG).show();
                clock = new Timer();
                clock.scheduleAtFixedRate(new TickClock(), 1000, 2000);
            }
            else
                Toast.makeText(getApplicationContext(),"Errore, nessuna connessione", Toast.LENGTH_LONG).show();
        }
    }

    private class TickClock extends TimerTask{
        @Override
        public void run(){
            LeggiDB();
        }
    }

    private void LeggiDB(){
        testo.setText("Leggo dato");
    }
}

iClaude

  • Visitatore
Re:Errata TimerTask?
« Risposta #1 il: 02 Maggio 2014, 10:44:29 CEST »
0
Premettendo che io utilizzerei un Handler e non un TimerTask, il motivo dell'errore è dovuto probabilmente al fatto che il Timer funziona in un thread separato, e da questo stai tentando di modificare la Gui impostando del testo su una TextView, cosa che non si può fare.

Offline uelfox

  • Nuovo arrivato
  • *
  • Post: 38
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Tablet mediacom 8" MP842M
  • Sistema operativo:
    Win 7
Re:Errata TimerTask?
« Risposta #2 il: 02 Maggio 2014, 11:38:43 CEST »
0
Hai una bozza di come potrei utilizzare un Handler... scusami ma sono alle prime righe di codice in ambiente android!
Come IDE, sto utilizzando StudioAndroid.

Grazie

iClaude

  • Visitatore
Re:Errata TimerTask?
« Risposta #3 il: 02 Maggio 2014, 11:44:29 CEST »
0
Se guardi il mio blog c'è una guida sugli Handler.
Cmq usando il tuo codice prova prima a modificare la GUI usando il metodo Activity.runOnUiThread (Runnable action): come parametro passi un oggetto Runnable con il metodo run che aggiorna la GUI.

Offline uelfox

  • Nuovo arrivato
  • *
  • Post: 38
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Tablet mediacom 8" MP842M
  • Sistema operativo:
    Win 7
Re:Errata TimerTask?
« Risposta #4 il: 03 Maggio 2014, 01:00:27 CEST »
0
Ho apportato queste modifiche:

nel codice onCreate(....)
Codice (Java): [Seleziona]
   
clock = new Timer();
clock.schedule(new TimerTask() {
     @Override
     public void run() {
          runOnUiThread(LeggiDB);
     }
}, 0, 1000);

poi ho aggiunto questo:
Codice (Java): [Seleziona]
private Runnable LeggiDB = new Runnable() {
     @Override
     public void run() {
         if(db != null){
              StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
              StrictMode.setThreadPolicy(policy);
              try {
                   Statement stmt = db.createStatement();
                   ResultSet dati = stmt.executeQuery("select * from Termostato02");
                   dati.next();
                   testo.setText(dati.getString("TempAttuale"));
                   dati.close();
                   stmt.close();
              }
              catch (SQLException e) {
                   Log.w("SQLException", e.getSQLState());
              }
              catch (Exception e) {
                   Log.w("Exception", e.getMessage());
              }
          }
     }
};

Ho dovuto aggiungere queste 2 righe:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

perchè altrimenti si sollevava l'eccezione: NetworkOnMainThreadException

Ora il codice funziona, spero di aver fatto nel modo + pulito...

Un'altra domanda?
Provenendo da c#, nel momento che la app cessava veniva chiusa, gli eventuali timer, si potevano fermare e liberare le risorse, ma in android come funziona la faccenda?
Quali metodi vengono generati se la app viene parcheggiata o viene chiusa, o se volessi interrompere il runnable, come faccio?

Offline gabric

  • Utente senior
  • ****
  • Post: 614
  • Respect: +18
    • Google+
    • Mostra profilo
    • Brancato's site
  • Dispositivo Android:
    Nexus 5 / Tablet mediacom s4
  • Play Store ID:
    Brancato's+app
  • Sistema operativo:
    window7. ubuntu
Re:Errata TimerTask?
« Risposta #5 il: 03 Maggio 2014, 14:52:55 CEST »
0
se usi un async task, puoi aggiornare il thread principale.
hai dato un occhiata qui?
[facile] Aggiornare la UI da una Thread - Android Developers Italia

iClaude

  • Visitatore
Re:Errata TimerTask?
« Risposta #6 il: 04 Maggio 2014, 11:08:32 CEST »
0
Ho apportato queste modifiche:

nel codice onCreate(....)
Codice (Java): [Seleziona]
   
clock = new Timer();
clock.schedule(new TimerTask() {
     @Override
     public void run() {
          runOnUiThread(LeggiDB);
     }
}, 0, 1000);

poi ho aggiunto questo:
Codice (Java): [Seleziona]
private Runnable LeggiDB = new Runnable() {
     @Override
     public void run() {
         if(db != null){
              StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
              StrictMode.setThreadPolicy(policy);
              try {
                   Statement stmt = db.createStatement();
                   ResultSet dati = stmt.executeQuery("select * from Termostato02");
                   dati.next();
                   testo.setText(dati.getString("TempAttuale"));
                   dati.close();
                   stmt.close();
              }
              catch (SQLException e) {
                   Log.w("SQLException", e.getSQLState());
              }
              catch (Exception e) {
                   Log.w("Exception", e.getMessage());
              }
          }
     }
};

Ho dovuto aggiungere queste 2 righe:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

perchè altrimenti si sollevava l'eccezione: NetworkOnMainThreadException

Ora il codice funziona, spero di aver fatto nel modo + pulito...

Un'altra domanda?
Provenendo da c#, nel momento che la app cessava veniva chiusa, gli eventuali timer, si potevano fermare e liberare le risorse, ma in android come funziona la faccenda?
Quali metodi vengono generati se la app viene parcheggiata o viene chiusa, o se volessi interrompere il runnable, come faccio?

E' possibile che funzioni, però il risultato è stato raggiunto nel modo peggiore possibile... ???
RunOnUiThread va usato solo per aggiornare la GUI, non per scaricare dati da internet. Regola fondamentale è: mai scaricare dati da internet nel thread della GUI, perchè così rischi facilmente di bloccare l'interfaccia. Aggirare il problema aggiungendo quelle due righe sullo StrictMode è altamente sconsigliato...

 :-) :-) :-)

Offline uelfox

  • Nuovo arrivato
  • *
  • Post: 38
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Tablet mediacom 8" MP842M
  • Sistema operativo:
    Win 7
Re:Errata TimerTask?
« Risposta #7 il: 04 Maggio 2014, 11:25:26 CEST »
0
E quindi che codice mi consigli di usare?
Come meglio sistemo la faccenda?

iClaude

  • Visitatore
Re:Errata TimerTask?
« Risposta #8 il: 04 Maggio 2014, 11:29:09 CEST »
0
E quindi che codice mi consigli di usare?
Come meglio sistemo la faccenda?

Nel metodo run del TimerTask recuperi i dati da internet.
Poi da lì chiami runOnUiThread e nel metodo run dell'oggetto Runnable aggiorni solo la GUI.

Offline uelfox

  • Nuovo arrivato
  • *
  • Post: 38
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Tablet mediacom 8" MP842M
  • Sistema operativo:
    Win 7
Re:Errata TimerTask?
« Risposta #9 il: 04 Maggio 2014, 17:20:06 CEST »
0
Proverò il tuo suggerimento...
e se invece genero 2 timer: uno che continua a leggere i dati da internet, mentre l'altro aggiorna la GUI; potrebbe funzionare?

iClaude

  • Visitatore
Re:Errata TimerTask?
« Risposta #10 il: 05 Maggio 2014, 10:23:08 CEST »
0
Proverò il tuo suggerimento...
e se invece genero 2 timer: uno che continua a leggere i dati da internet, mentre l'altro aggiorna la GUI; potrebbe funzionare?

Sinceramente non capisco perché complicarsi inutilmente la vita, anche perché i due task sono collegati: recuperi i dati da internet e poi aggiorni la gui.