Android: Connessione a MySQL usando PHP

Il motivo principale per l’adozione di un linguaggio di scripting come PHP è dovuto all’interazione con i database.

In questo tutorial vi mostrerò come utilizzare PHP e database MySQL per recuperare informazioni dal server. Per effettuare il collegamento a script PHP, utilizzeremo il protocollo HTTP dal sistema android. Inutile dirvi che comunque per implementare questo tutorial si dovrebbe avere una conoscenza di base di come eseguire script PHP e avviare il server. Se parliamo di architettura client-server, il dispositivo client è l’Android e lato server vi è una combinazione di script PHP e MySQL.

Durante il tutorial useremo un formato importantissimo per lo scambio leggero dei dati, ossia il formato JSON (JavaScript Object Notation).

Piccola premessa sul JSON:

Si basa su un sottoinsieme del Linguaggio di Programmazione JavaScriptStandard ECMA-262 Terza Edizione – Dicembre 1999 (testo sito json). JSON è un formato di testo completamente indipendente dal linguaggio di programmazione, ma utilizza convenzioni conosciute dai programmatori di linguaggi della famiglia del C, come C, C++, C#, Java, JavaScript, Perl, Python, e molti altri. Questa caratteristica fa di JSON un linguaggio ideale per lo scambio di dati.

JSON è basato su due strutture:

  • Un insieme di coppie nome/valore. In diversi linguaggi, questo è realizzato come un oggetto, un record, uno struct, un dizionario, una tabella hash, un elenco di chiavi o un array associativo.
  • Un elenco ordinato di valori. Nella maggior parte dei linguaggi questo si realizza con un array, un vettore, un elenco o una sequenza.

Come farà la nostra applicazione ad usare json?

Quando l’applicazione Android effettuerà la richiesta alla pagina PHP e rimarrà in attesa. Lo script PHP, si connetterà al DB, invierà la query, recupererà la risposta, inserirà la risposta in un oggetto json e lo darà come output. Questo output sarà codificato in formato JSON e inviato al dispositivo. L’applicazione Android otterrà questi dati codificati, li analizzerà e li visualizzerà sul dispositivo Android.

Implementiamo il tutto:

In MySQL creare il database TSA_Evolution, creare tabella Stock. Questa tabella consiste di due colonne. In primo luogo è Stock_id, che è auto_increment e primary_key e avere tipo di dati INT. Seconda colonna è Stock_name, che ha tipo di dati VARCHAR (20).

La query sarà: Vogliamo SELEZIONARE il tutti gli IDENTIFICATIVI delle azioni DALLA nostra TABELLA Stock CHE INIZINO con la lettera A (in maiuscolo ho praticamente evidenziato la query che andremo ad effettuare, ossia:

SELECT Stock_id

FROM Stock

WHERE Stock_name= A

)

Il codice PHP sarà molto semplice:

  • connessione al database
  • esecuzione della query SQL, con il WHERE  a seconda dei dati da POST / GET
  • output in formato JSON

Per esempio avremo questa funzionalità in city.php:

<?

/*ci colleghiamo al database(attenti perchè se lavorate in locale 
l'host è 10.0.2.2 e non 127.0.0.1)*/
php mysql_connect("host","username","password"); 
//selezioniamo il db a cui ci vogliamo connettere
mysql_select_db("TSA_Evolution");
//creamo al query
$sql=mysql_query("select Stock_id from Stock where STOCK_name like 'A%'"); 
/*Il metodo "mysql_fetch_assoc" restituisce un array in base alla query 
fatta e incrementa il dato*/
while($row=mysql_fetch_assoc($sql)) 
//inseriamo tutto nella variabile output
$output[]=$row;
/*stampiamo l'oggetto json, miraccomando a non stampare a video altri commenti, 
altrimenti quando andremo ad eseguire l'app android si bloccherà in quanto non 
riconoscerà i commenti come caratteri json*/
 print(json_encode($output)); 
//chiudiamo la connessione
mysql_close();

?>

Nella nostra applicazione Android dobbiamo:

  • usare un HttpPost per ottenere i dati,
  • convertire la risposta alla stringa JSON
  • analizzare i dati e usarli

Il codice per recuperare dati dal server per la nostra applicazione Android sarà:

package com.list; 

import java.io.BufferedReader; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.ArrayList;

import org.apache.http.HttpEntity; 
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair; 
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; 
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;import android.app.ListActivity; 
import android.net.ParseException;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast; 
public class AndroidPhp extends Activity { /*qualcuno qui ha esteso ad una 
ListActivity ma io preferisco gestirmi da me la risposta*/
JSONArray jArray;
String result = null; 
InputStream is = null; 
StringBuilder sb=null; 

@Override
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.android_php);
final TextView textviewDariRicevuti = (TextView) findViewById(R.id.datiRicevuti);
Button buttonInviaDati = (Button) findViewById(R.id.buttonInviaDati);
buttonInviaDati.setOnClickListener(new View.OnClickListener() { 
@Override
public void onClick(View v) {
//invio richiesta
textviewDariRicevuti.setText(inviaDati());
}
});
}
public String inviaDati(){
String result="";
String stringaFinale="";
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
//Sotto scrivo come si chiama il campo che invio(azione1) e il suo valore (1)
nameValuePairs.add(new BasicNameValuePair("Stock_name","azione1"));
/*queste due righe di codice che vedete qui sotto sono un piccolo trucchetto per ovviare
 (solo per il momento
 all'eccezione “NetworkOnMainThreadException", questa eccezione è importantissima in quanto
 ci dice che siccome stiamo effettuando una connessione nel thread principale avremo dei 
problemi in quanto tutto ciò che riguarda le connessioni o tutto ciò che comporta il 
superamento del limite di tempo massimo tra richiesta/risposta superiore a 5secondi la nostra 
applicazione Android la metterà in pausa appunto perchè stiamo programmando per uno smartphone
 e non possiamo attendere processi che impegnino per troppo tempo la nostra app. Ricordatevi
 una volta testato tutto, create nella classe i thread e gestite tutto dal thread.*/
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
//http post 
try { 
HttpClient httpclient = new DefaultHttpClient(); 
HttpPost httppost = new HttpPost("http://10.0.2.2/interroga.php");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
result = EntityUtils.toString(entity, HTTP.UTF_8);
}
catch(Exception e){ 
Log.e("log_tag", "Error in http connection"+e.toString());
} 
//convert response to string 
try{ 
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8); 
sb = new StringBuilder();
sb.append(reader.readLine() + "\n"); 
String line=null; 
while ((line = reader.readLine()) != null) 
{ sb.append(line + "\n");
} 
is.close();
result=sb.toString(); 
}
catch(Exception e){ 
Log.e("log_tag", "Error converting result "+e.toString());
}
//paring data 

try{ 
jArray = new JSONArray(result); 
/*Quando vi dicevo di non inserire commenti nella pagina php era perchè l'app si
 bloccava proprio su questa
riga, in quanto "result" NON comprendeva caratteri json e il parsing non poteva 
essere effettuato */
JSONObject json_data=null;
for(int i=0;i<jArray.length();i++){
Log.i("TEST","id: "+json_data.getInt("Stock_id")+
", name: "+json_data.getString("Stock_name")+
", cliente: "+json_data.getString("Stock_Client_id")+
", industria: "+json_data.getString("Stock_Industry_id")
);
stringaFinale = json_data.getInt("Stock_id")+ ""+ json_data.getString("Stock_name")+
""+ json_data.getString("Stock_Client_id")+
""+ json_data.getString("Stock_Industry_id")+"\n\n";
}
} catch(JSONException e1){ 
Toast.makeText(getBaseContext(), "Titolo Azionario non trovato" ,Toast.LENGTH_LONG).show();
} catch (ParseException e1) { e1.printStackTrace();
}
}
else { //is è null e non ho avuto risposta
}
return stringaFinale;
}
}

Non me ne vogliano i più esperti ma preferisco fornire una guida completa inserendo anche il Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonInviaDati"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Invia dati" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Dati ricevuti:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/datiRicevuti"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Per ora nessun dato ricevuto" />

</LinearLayout>

Non dimenticatevi di inserire il permesso alla connessione internet in AndroidManifest.xml:

<uses-permission android:name=”android.permission.INTERNET”></uses-permission>

Provateci e fatemi sapere come è andata, aspetto i vostri commenti..

😉 Good Luck

Alessio Scannicchio

 

 

Rigenerare classe R progetto Android

Mi è stata posta questa domanda:

Sul mio progetto, dopo aver eseguito un “clean” (uso eclipse), la classe R è stata cancellata.
Come faccio a rigenerarla?

Bene..vi comunico che non c’è nulla di cui preoccuparvi anche se vedete punti esclamativi rossi sul progetto oppure icone rosse con la “X” su ogni attività creata..
Giustamente questi errori vengono generati perché manca la classe R.
Vediamo prima di tutto cosa è la classe R in modo da capire il motivo per il quale eclipse (o il nostro ambiente di sviluppo) riconosce questi errori.

Un applicazione Android è costituita da diversi tipi di componenti che comprendono : codice sorgente Java, documenti XML, icone ed immagini, basi di dati e file binari di altro tipo. Tutti questi componenti vanno in un qualche modo assemblati fra di loro ed in base alla tipologia va inserito in un particolare punto del progetto.

Abbiamo delle risorse XML che definiscono alcune parti dell’applicazione come la GUI oppure dei parametri e valori, ma allo stesso tempo abbiamo il codice java all’interno di un Activity che deve utilizzare queste risorse per l’applicazione.
Come avviene tutto questo?
Il ponte fra questi due tipi i componenti viene gestito dalla “classe R” (da Resurces (All resource IDs are defined in your project’s R class, which the aapt tool automatically generates)) contenuta nella cartella gen/ e che viene generata dal plugin ADT in maniera automatica ogni qualvolta aggiungiamo un elemento alla struttura di un documento XML già esistente oppure ne creiamo uno nuovo.

Per utilizzare le risorse ‘mappate’ in questa classe si utilizzano alcuni metodi implementati nella classe Activity,come per esempio “setContentView(R.layout.main) attraverso cui implementare il layout grafico del main semplicemente richiamandolo attraverso la classe R
Il metodo riceve un intero che deve identificare la risorsa XML dove è definito il layout grafico. Quindi la costante R.layout.main identifica questa risorsa.
Un’altro metodo molto importante è findViewById(R.id.codicerisorsa) che in questo caso ricerca l’elemento in base all’ ID definito nella risorsa XML.

Detto ciò passiamo a come risolvere il problema della scomparsa di tale classe molto importante e senza la quale non sarebbe possibile identificare tutte le risorse della nostra applicazione

Il modo più veloce e immediato per rigenerare la classe R è quella di togliere la spunta da: Menù Project->Build Automatically e successivamente cercare di salvare, oppure andare su tasto dx Progetto(in Project Explorer)->Restore from Local Hystory e dopo tornare a Menù Project->Build Automatically e rimettere il check.
(subito dopo verrà rigenerata la classe automaticamente)

Spero d’esser stato d’aiuto 😉
Grazie
Alessio