IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

Téléchargement fichier .db, classe AsyncTask


Sujet :

Android

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2013
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2013
    Messages : 139
    Points : 459
    Points
    459
    Par défaut Téléchargement fichier .db, classe AsyncTask
    Bonjour,

    J'essaye de récupérer un fichier .db sur un serveur web, en le téléchargeant puis l'utiliser comme base de donnée locale. L'idée est de récupérer une base de donnée Web pour l'utiliser en local sans connexion internet.

    J'ai déjà réussi, grâce à l'aide d'un membre du forum, à convertir la base de donnée. Le fichier généré est correct, il contient bien mes données.

    Après plusieurs essais et corrections du code , j'ai donc découvert qu'il fallait absolument télécharger depuis une AsyncTask. Je me suis donc lancé dans une classe DownloadHelper qui hérite de AsyncTask.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    public final class DownloadHelper extends AsyncTask
    {
    	protected void onPreExecute(Context context)
    	{
    		downloadDatabase(context);
    	}
     
    	protected Object doInBackground(Object... arg0)
    	{
    		copyServerDatabase(null);
    		return null;
    	}
    	private static boolean downloadDatabase(Context context) 
        {
            try {
                    URL url = new URL("urldusite" + "basesqlite.db");
                    /* Open a connection to that URL. */
                    URLConnection ucon = url.openConnection();
                    /*
                     * Define InputStreams to read from the URLConnection.
                     */
                    InputStream is = ucon.getInputStream();
                    BufferedInputStream bis = new BufferedInputStream(is);
                    /*
                     * Read bytes to the Buffer until there is nothing more to read(-1).
                     */
                    ByteArrayBuffer baf = new ByteArrayBuffer(50);
                    int current = 0;
                    while ((current = bis.read()) != -1) {
                            baf.append((byte) current);
                    }
     
                    /* Convert the Bytes read to a String. */
                    FileOutputStream fos = null;
                    // Select storage location
                    fos = context.openFileOutput("basesqlite.db", Context.MODE_PRIVATE); 
     
                    fos.write(baf.toByteArray());
                    fos.close();
                    Log.d("BTC", "downloaded");
            } 
            catch (IOException e) 
            {
                    Log.e("BTC", "downloadDatabase Error: " , e);
                    return false;
            }  
            catch (NullPointerException e) 
            {
                    Log.e("BTC", "downloadDatabase Error: " , e);
                    return false;
            } 
            catch (Exception e)
            {
                    Log.e("BTC", "downloadDatabase Error: " , e);
                    return false;
            }
            return true;
        }
     
    	@SuppressLint("SdCardPath")
    	private void copyServerDatabase(Context context) 
    	{
    				BtcDb db = new BtcDb(context,"clean.db",null,0);
    	        	// by calling this line an empty database will be created into the default system path
    	        	// of this app - we will then overwrite this with the database from the server
    				db.getReadableDatabase();
    	        	db.close();
     
     
    	            OutputStream os = null;
    	            InputStream is = null;
    	            try {
    	                  // Log.d("BTC", "Copying DB from server version into app");
    	                    is = context.openFileInput("basesqlite.db");
    	                    os = new FileOutputStream("/data/data/com.example.btc_pe/databases/"); 
     
    	                    copyFile(os, is);
    	            } 
    	            catch (Exception e) 
    	            {
    	                    Log.e("BTC", "Server Database was not found - did it download correctly?", e);                          
    	            } 
    	            finally 
    	            {
    	                    try 
    	                    {
    	                            //Close the streams
    	                            if(os != null)
    	                            {
    	                                    os.close();
    	                            }
    	                            if(is != null)
    	                            {
    	                                    is.close();
    	                            }
    	                    } 
    	                    catch (IOException e) 
    	                    {
    	                            Log.e("BTC", "failed to close databases");
    	                    }
    	            }
    	            Log.d("BTC", "Done Copying DB from server");
    	    }
     
     
     
     
    	 private static void copyFile(OutputStream os, InputStream is) throws IOException 
    	 {
    	        byte[] buffer = new byte[1024];
    	        int length;
    	        while((length = is.read(buffer))>0)
    	        {
    	                os.write(buffer, 0, length);
    	        }
    	        os.flush();
    	}
    }
    L'idée, telle que je la conçois, est de télécharger d'abord le fichier dans un évènement, puis le déplacer ensuite dans un second évènement. (J'ai hésité à faire les 2 dans le DoInBackground, mais j'ai peur qu'il tente de déplacer avant même qu'il n'ait fini de télécharger)

    Pour l'anecdote, le fichier .db fait moins de 25Ko.

    Je fais face à plusieurs soucis :
    -AsyncTask me demande obligatoirement d'avoir "protected Object doInBackground(Object... arg0)", sauf que j'ai besoin du context de l'activité dans copyServerDatabase. Si je modifie les arguments de l'évènement, j'me prends une erreur. Comment je peux contourner le problème ?
    -Je ne suis pas tout à fait sur de mon raisonnement sur l'exécution de tout le processus, j'aimerais l'avis de personnes plus expérimentées dans le domaine. Je pense pas faire une tache si peu courante que ça...
    -Pour gérer un téléchargement, y'a pas une solution plus simple que tout manipuler d'une manière aussi bas niveau ? J'imagine que ça doit être assez courant quand même de devoir télécharger un fichier.
    -Pour générer le fichier .db, je dois appeler un script php sur le serveur Web. Y'a une méthode assez simple et courte pour simplement envoyer une requête HTTP toute bête depuis Android ?

    Merci d'avance.

  2. #2
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Sauf contre-indication, un appel de fonction est toujours "bloquant" (les post-conditions de la fonction sont remplies au retour de celle-ci).

    Ainsi la fonction downloadDatabase() ne reviendra qu'une fois le téléchargement effectué. Par contre je ne comprends pas pourquoi catcher toutes les exceptions, et renvoyer true/false... autant laisser les exceptions remonter non ?
    Et attention, les streams ne sont pas bien fermés. Oui c'est fait au "finalize()" de l'objet, mais qui sait quand celui-ci sera appelé....

    Voici pour moi ce que devrait être la fonction "downloadDatabase()"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    private static boolean downloadDatabase(File destFile) throws IOException, ...
    {        
        URLConnection ucon;
        InputStream is = null;
        OutputStream os = null;
        try {
             URL url = new URL("urldusite" + "basesqlite.db");
             ucon = url.openConnection();
             is = ucon.getInputStream();
             os = new FileOutputStream(destFile);
             copy(is,os);
        } finally {
             if (os != null) try { os.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close output stream",ex); }
             if (is != null) try { in.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close input stream",ex); }
             if (ucon != null) try { ucon.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close connection",ex); }
        } 
    }
     
    public static int copy(InputStream input, OutputStream output) throws IOException{
         byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
         int count = 0;
         int n = 0;
         while (-1 != (n = input.read(buffer))) {
             output.write(buffer, 0, n);
             count += n;
         }
         output.flush();
         return count;
     }

    Ensuite... concernant l'AsyncTask, cela ne va carrément pas...

    TOUT (enfin, le maximum non lié à l'UI) doit être fait dans le doInBackground(). C'est cette fonction qui est effectuée dans un thread à part.

    Pour le contexte, il y a deux choix:
    1. L'objet AsyncTask est une classe fille de l'activité... dans ce cas elle connait sont "parent" avec Activity.this
    2. On passe le contexte à la construction de l'AsyncTask
    3. On s'occupe du calcul du File final *avant*
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class DownloadHelper extends AsyncTask<File,Void,Void>
    {
          public Void doInBackground(File ... params)
          {
                 for (File f : params) {
                      try {
                          downloadDatabase(f);
                      } catch (Exception ex) {
                          Log.e("DH","Failed to download database !",ex);
                      }
                 }
          }
    }
    Ou si tu veux conserver l'indépendance:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    public class DownloadHelper extends AsyncTask
    {
        Context context;
     
        public DownloadHelper(Context ctxt)
          { this.context = ctxt; }
     
          public Void doInBackground(Void...params)
          {
                try {
                    downloadDatabase(this.context);
                    copyServerDatabase(this.context);
                } catch (Exception ex) {
                    Log.e("Failed to download database !",ex);
                }
          }
    }
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2013
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2013
    Messages : 139
    Points : 459
    Points
    459
    Par défaut
    Salut,

    Du coup j'ai pas mal exploité ton code, j'en suis arrivé à ce résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    @SuppressLint("SdCardPath")
    public final class DownloadHelper extends AsyncTask<Void,Void,Void>
    {
    	Context context;
    	File cheminBdd = new File("/data/data/com.example.btc_pe/databases/basesqlite.db");
     
        public DownloadHelper(Context ctxt)
          { this.context = ctxt; }
     
    	@Override
    	protected Void doInBackground(Void... params)
    	{
    		// TODO Auto-generated method stub
    		try 
            {
                downloadDatabase(cheminBdd);
                copyServerDatabase(this.context);
            } 
            catch (Exception ex) 
            {
                Log.e("BTC","Failed to download database !",ex);
            }
     
    		return null;
    	}
     
     
    	private static void downloadDatabase(File destFile) throws IOException
    	{        
    	    URLConnection ucon;
    	    InputStream is = null;
    	    OutputStream os = null;
    	    try {
    	         URL url = new URL("adressesite" + "basesqlite.db"); //Je vais éviter de publier l'adresse en clair par contre... Désolé.
    	         ucon = url.openConnection();
    	         is = ucon.getInputStream();
    	         os = new FileOutputStream(destFile);
    	         copy(is,os);
    	    } 
    	    finally 
    	    {
    	         if (os != null) try { os.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close output stream",ex); }
    	         if (is != null) try { is.close(); } catch (Exception ex) { Log.e("BTC","Failed to gracefully close input stream",ex); }
    	    } 
    	}
     
    	public static int copy(InputStream input, OutputStream output) throws IOException
    	{
    	     byte[] buffer = new byte[8192];
    	     int count = 0;
    	     int n = 0;
    	     while (-1 != (n = input.read(buffer))) 
    	     {
    	         output.write(buffer, 0, n);
    	         count += n;
    	     }
    	     output.flush();
    	     return count;
    	 }
     
     
    	@SuppressLint("SdCardPath")
    	private void copyServerDatabase(Context context) 
    	{
    				BtcDb db = new BtcDb(context,"clean.db",null,0);
    	        	// by calling this line an empty database will be created into the default system path
    	        	// of this app - we will then overwrite this with the database from the server
    				db.getReadableDatabase();
    	        	db.close();
     
     
    	            OutputStream os = null;
    	            InputStream is = null;
    	            try {
    	                  // Log.d("BTC", "Copying DB from server version into app");
    	                    is = context.openFileInput("basesqlite.db");
    	                    os = new FileOutputStream("/data/data/com.example.btc_pe/databases/"); 
     
    	                    copyFile(os, is);
    	            } 
    	            catch (Exception e) 
    	            {
    	                    Log.e("BTC", "Server Database was not found - did it download correctly?", e);                          
    	            } 
    	            finally 
    	            {
    	                    try 
    	                    {
    	                            //Close the streams
    	                            if(os != null)
    	                            {
    	                                    os.close();
    	                            }
    	                            if(is != null)
    	                            {
    	                                    is.close();
    	                            }
    	                    } 
    	                    catch (IOException e) 
    	                    {
    	                            Log.e("BTC", "failed to close databases");
    	                    }
    	            }
    	            Log.d("BTC", "Done Copying DB from server");
    	    }
     
     
     
     
    	 private static void copyFile(OutputStream os, InputStream is) throws IOException 
    	 {
    	        byte[] buffer = new byte[1024];
    	        int length;
    	        while((length = is.read(buffer))>0)
    	        {
    	                os.write(buffer, 0, length);
    	        }
    	        os.flush();
    	}
    }
    J'ai du le retoucher un peu pour corriger les erreurs annoncées par Eclipse.

    Du coup je l'appelle dans mon activité comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	    switch (item.getItemId()) 
    	    {
    	        case R.id.action_refresh:
    	            dh.execute();
    	            return true;
    	        default:
    	            return super.onOptionsItemSelected(item);
    	    }
    Quand je teste sur l'application, je n'ai aucune réaction de l'application (enfin de toutes façons il n'est pas sensé avoir de réaction...). Du coup j'ai pas trop idée de comment je peux vérifier si le téléchargement a bien eu lieu... Je suis sur un émulateur et il n'a pas de navigateur de fichiers (ni appstore o/).
    Si je reclique sur le bouton par contre, mon application plante et j'ai le logcat spammé :
    Nom : logcat_btc.png
Affichages : 518
Taille : 69,5 Ko
    Ca me pose problème, puisque l'idée c'est quand même qu'il puisse mettre à jour sa base de donnée à volonté. Et s'il décide de le faire 15x d'affilée, ça devrait fonctionner.

    Du coup, j'aimerais votre avis sur ma classe retouchée, une idée pour vérifier que mon DL a bien eu lieu, et ensuite un petit coup de main pour comprendre ce logcat... A priori il aime pas que je relance une tache déjà effectuée (J'aurais pas achevé la tache de téléchargement ?)

  4. #4
    Membre confirmé
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2013
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2013
    Messages : 139
    Points : 459
    Points
    459
    Par défaut
    Bonjour,

    J'me permets de relancer le sujet, malgré pas mal de recherche de mon coté, je n'arrive pas à trouver la solution au problème :/.

  5. #5
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Salut,

    Est ce que tu pourrais nous donner ton logcat avec l'erreur en cause ?

    Merci.
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

Discussions similaires

  1. un fichier par classe
    Par CaptainChoc dans le forum Général Python
    Réponses: 11
    Dernier message: 20/05/2006, 19h29
  2. Téléchargement/Fichiers Temporaires
    Par ArHacKnIdE dans le forum Autres Logiciels
    Réponses: 10
    Dernier message: 09/03/2006, 14h29
  3. Problème forcer téléchargement fichier
    Par cams dans le forum Langage
    Réponses: 34
    Dernier message: 15/12/2005, 16h42
  4. Réponses: 3
    Dernier message: 02/10/2005, 12h30
  5. execution d'un prog avec des fichiers multi-class
    Par Ice-B dans le forum Général Java
    Réponses: 2
    Dernier message: 05/08/2004, 11h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo