Abbiamo praticamente tutto, non ci resta che salvare l’immagine del profilo dell’utente registrato nel cloud e rifinire qualche dettaglio, dopodiché quest’app potrà definirsi completa.
La rifinitura dei dettagli la lascio a voi, al momento occupiamoci di completare la parte relativa alla creazione dell’account. L’activity completa e modificata a tale scopo avrà il seguente codice:
public class CreateAccountActivity extends AppCompatActivity { private ImageButton avatarPic; private EditText firstNameET; private EditText lastNameET; private EditText emailET; private EditText passwordET; private Button createActBT; private FirebaseDatabase DB; private DatabaseReference DBRef; private FirebaseAuth mAuth; private StorageReference mFBStorage; private final static int GALLERY_CODE = 1; private Uri resultUri = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_create_account); /* * Recupero di istanze e riferimenti necessari da Firebase */ DB = FirebaseDatabase.getInstance(); DBRef = DB.getReference().child("Users"); mAuth = FirebaseAuth.getInstance(); mFBStorage = FirebaseStorage.getInstance().getReference().child("Blog_Profile_Pics"); /* * Istanziazione di tutti i widget presenti all'interno del layout */ firstNameET = (EditText) findViewById(R.id.firstNameAct); lastNameET = (EditText) findViewById(R.id.lastNameAct); emailET = (EditText) findViewById(R.id.emailAct); passwordET = (EditText) findViewById(R.id.passwordAct); createActBT = (Button) findViewById(R.id.createAccountAct); avatarPic = (ImageButton) findViewById(R.id.avatarAct); avatarPic.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Cliccando sull'ImageButton richiamiamo il metodo per l'aggiunta di un avatar addAvatar(); } }); //Setting del listener sul pulsante per avviare la procedura di creazione account createActBT.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { createnewAct(); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { /* * Metodo invocato quando l'utente ha selezionato l'immagine profilo dalla galleria. * Qui dobbiamo prelevare l'immagine e utilizzarla */ super.onActivityResult(requestCode, resultCode, data); //Controlliamo che la richiesta sia andata a buon fine if (requestCode == GALLERY_CODE && resultCode == RESULT_OK){ //Preleviamo l'URI dell'immagine dai dati ricevuti Uri mImageUri = data.getData(); //Crop dell'immagine attraverso l'apposita libreria CropImage.activity(mImageUri) .setAspectRatio(1, 1) .setGuidelines(CropImageView.Guidelines.ON) .start(this); } //Recupero dell'immagine "croppata" if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) { CropImage.ActivityResult result = CropImage.getActivityResult(data); if (resultCode == RESULT_OK) { resultUri = result.getUri(); avatarPic.setImageURI(resultUri); } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) { Exception error = result.getError(); } } } private void addAvatar() { /* * Confezioniamo l'intent per poter aprire la galleria e permettere la selezione di un immagine */ Intent galleryIntent = new Intent(); galleryIntent.setAction(Intent.ACTION_GET_CONTENT); galleryIntent.setType("image/*"); //Predisponiamo l'activity a ricevere dei dati da quella chiamata startActivityForResult(galleryIntent, GALLERY_CODE); } private void createnewAct() { /* * Recupero delle informazioni inserite all'interno delle EditText */ final String name = firstNameET.getText().toString().trim(); final String lName = lastNameET.getText().toString().trim(); String eMail = emailET.getText().toString().trim(); String pwd = passwordET.getText().toString().trim(); //Controllo che tutti i campi siano stati compilati if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(lName) && !TextUtils.isEmpty(eMail) && !TextUtils.isEmpty(pwd)){ //Creazione dell'account tramite apposito metodo, con listener sull'esito mAuth.createUserWithEmailAndPassword(eMail, pwd).addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { if (authResult != null){ /* * Se la creazione dell'account ha avuto successo, si memorizzano tutti i * dati dell'utente all'interno del database e si direziona l'utente * verso l'activity con la lista di post */ //Generiamo il path dell'immagine profilo da salvare StorageReference imagePath = mFBStorage.child(resultUri.getLastPathSegment()); //Salviamo l'immagine e monitoriamo l'esito dell'operazione imagePath.putFile(resultUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { String userID = mAuth.getCurrentUser().getUid(); DatabaseReference currentUserDBRef = DBRef.child(userID); currentUserDBRef.child("firstName").setValue(name); currentUserDBRef.child("lastName").setValue(lName); currentUserDBRef.child("avatar").setValue(resultUri.toString()); Intent intent = new Intent(CreateAccountActivity.this, PostListActivity.class); //Aggiungiamo un flag all'intent che non fa altro che porre l'activity //destinataria nuovamente in cima allo stack, se già avviata, piuttosto che //avviarne un'altra istanza, terminando contestualmente tutte le altre activity intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); } }); } } }); }else{ //ToDo: codice per gestire il mancato inserimento di tutti i dati } } }
A quello che già avevamo abbiamo aggiunto un field dedicato per un’oggetto StorageReference, che, come abbiamo già visto, è quello che contiene il riferimento allo storage del cloud di Firebase. Per ottenere questo riferimento abbiamo quindi recuperato l’istanza, il riferimento allo spazio di archiviazione e quello ad un suo elemento figlio, che sarà la cartella in cui memorizzeremo le immagini. All’interno dello spazio di storage avremo quindi due cartelle, una dedicata alle immagini dei post, l’altra alle immagini profilo.
Fatto ciò abbiamo modificato il metodo di creazione account. Piuttosto che salvare direttamente tutti i dati nel database, nel caso in cui la creazione dell’account abbia successo, ci premuriamo per prima cosa di caricare l’immagine nel cloud. Per farlo generiamo il path dell’immagine, aggiungendo un elemento figlio (che avrà l’ultima parte dell’URI del file) al path generale creato prima. Otterremo così il riferimento alla specifica immagine.
Dopo di ciò possiamo salvare l’immagine all’interno di questo riferimento richiamando il metodo “putFile()” e passandovi come parametro l’URI dell’immagine croppata. Aggiungiamo un listener in cascata per monitorare l’esito di questa operazione. Se avrà successo, salveremo tutti i dati all’interno del database. Il codice di questa parte è identico a quello utilizzato precedentemente, tranne che per il nodo relativo all’avatar, in cui adesso salviamo la stringa dell’URI dell’immagine.
Se vi è sfuggito qualcosa, confrontate questa versione del file con quella precedente, così da avere a vista le modifche effettuate.
Conclusioni
L’app ora è completa e funzionante, mancano svariati dettagli, se spulciate all’interno del codice noterete infatti una serie di commenti “ToDo”. Se volete continuare ad esercitarvi, sta a voi completare l’app, ad esempio gestendo tutte le situazioni in cui l’esito delle varie operazioni effettuate non va a buon fine.
Potete aggiungere un’activity di dettaglio per i post, infatti se ricordate abbiamo collegato anche un listener alle view della RecyclerView.
Un altro spunto potrebbe essere quello di gestire la situazione in cui l’utente non aggiunge un avatar nel momento in cui si registra. La modalità più semplice potrebbe essere quella di caricare un’immagine apposita ed effettuare un controllo sull’ImageButton, così da salvare il riferimento all’immagine profilo di default all’interno del database. Altrimenti potete ricavare l’URI dell’immagine risorsa settata sull’ImageView e caricare quella nel caso l’utente non ne avesse scelto una propria; questa modalità però presenta un’inefficienza, verrà caricata sempre la stessa immagine, erodendo spazio inutilmente.
Anche i layout non sono il massimo, ad esempio immagini troppo grandi vengono gestite male, quindi potete giocare un po’ con le proprietà per sistemare il tutto.
Abbiamo finito con questo lungo capitolo dedicato a Firebase. Ovviamente Firebase offre anche molto altro e sarebbe necessario un blog apposito solo per lui. Abbiamo imparato però ad utilizzarlo, quindi non dovrebbe essere difficile, col supporto della documentazione, implementare anche le altre feature.
Dal prossimo articolo passeremo ad altro e nello specifico ci dedicheremo a Google Maps e quindi alla localizzazione.