Aplicación Android (curso 21-22)
App que se comunica con el API Rest creado en Laravel
Aplicación Android
¿Esquema de la red?
ApiRestClient.java
public class ApiRestClient { private static ApiService API_SERVICE; public static final String BASE_URL = "https://todo.alumno.me/"; public static synchronized ApiService getInstance() { if (API_SERVICE == null) { OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS); Gson gson = new GsonBuilder() .setDateFormat("dd-MM-yyyy") .create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .client(okHttpBuilder.build()) .build(); API_SERVICE = retrofit.create(ApiService.class); } return API_SERVICE; } }
ApiService.java
public interface ApiService { @FormUrlEncoded @POST("api/register") Call<RegisterResponse> register( @Field("name") String name, @Field("email") String email, @Field("password") String password, @Field("confirm_password") String confirmPassword); //@POST("api/register") //Call<RegisterResponse>register(@Body User user); @FormUrlEncoded @POST("api/login") Call<LoginResponse> login( @Field("email") String email, @Field("password") String password); //@POST("api/login") //Call<LoginResponse>login(@Body User user); }
ApiTokenRestClient.java
public class ApiTokenRestClient { private static ApiTokenService API_SERVICE; public static final String BASE_URL = "https://todo.alumno.me/"; public static synchronized ApiTokenService getInstance(final String token) { if (API_SERVICE == null) { Interceptor interceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request newRequest = chain.request().newBuilder() .addHeader("Accept", "application/json") .addHeader("authorization", "Bearer " + token) .build(); return chain.proceed(newRequest); } }; OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS) .addInterceptor(interceptor); Gson gson = new GsonBuilder() .setDateFormat("dd-MM-yyyy") .create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .client(okHttpBuilder.build()) .build(); API_SERVICE = retrofit.create(ApiTokenService.class); } return API_SERVICE; } public static void deleteInstance() { API_SERVICE = null; } }
ApiTokenService
public interface ApiTokenService { @POST("api/logout") Call<LogoutResponse> logout( //@Header("Authorization") String token ); @GET("api/tasks") Call<GetTasksResponse> getTasks( //@Header("Authorization") String token ); @POST("api/tasks") Call<AddResponse> createTask( //@Header("Authorization") String token, @Body Task task); @PUT("api/tasks/{id}") Call<AddResponse> updateTask( //@Header("Authorization") String token, @Body Task task, @Path("id") int id); @DELETE("api/tasks/{id}") Call<DeleteResponse> deleteTask( //@Header("Authorization") String token, @Path("id") int id); @POST("api/email") Call<EmailResponse> sendEmail(@Body Email email); }
SharedPreferencesManager
public class SharedPreferencesManager { //public static final String APP = "MyApp"; //public static final String EMAIL = "email"; //public static final String PASSWORD = "password"; //public static final String TOKEN = "token"; SharedPreferences sp; SharedPreferences.Editor spEditor; public SharedPreferencesManager(Context context){ sp = context.getSharedPreferences(MainActivity.APP, Context.MODE_PRIVATE); spEditor = sp.edit(); } public void save (String email, String password){ spEditor.putString(MainActivity.EMAIL, email); spEditor.putString(MainActivity.PASSWORD, password); spEditor.apply(); } public void save (String email, String password, String token){ spEditor.putString(MainActivity.EMAIL, email); spEditor.putString(MainActivity.PASSWORD, password); spEditor.putString(MainActivity.TOKEN, token); spEditor.apply(); } public void saveEmail(String key, String value){ spEditor.putString(key, value); spEditor.apply(); } public String getEmail(){ return sp.getString(MainActivity.EMAIL, ""); } public void savePassword(String key, String value){ spEditor.putString(key, value); spEditor.apply(); } public String getPassword(){ return sp.getString(MainActivity.PASSWORD, ""); } public void saveToken(String key, String value){ spEditor.putString(key, value); spEditor.apply(); } public String getToken(){ return sp.getString(MainActivity.TOKEN, ""); } }
Login en el MainActivity
private void loginByServer() { progressDialog = new ProgressDialog(this); progressDialog.setIndeterminate(true); progressDialog.setMessage("Login ..."); progressDialog.setCancelable(false); progressDialog.show(); binding.login.setEnabled(false); String email = binding.email.getText().toString(); String password = binding.password.getText().toString(); Call<LoginResponse> call = ApiRestClient.getInstance().login(email, password); //User user = new User(name, email, password); call.enqueue(new Callback<LoginResponse>() { @Override public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) { StringBuilder message = new StringBuilder(); progressDialog.dismiss(); binding.login.setEnabled(true); //onRegisterSuccess(); LoginResponse loginResponse = response.body(); if (response.isSuccessful()) { if (loginResponse.getSuccess()) { Log.d("onResponse", "" + response.body()); //showMessage(response.body().getToken()); //guardar token en shared preferences preferences.save(binding.email.getText().toString(), binding.password.getText().toString(), loginResponse.getData().getToken()); startActivity(new Intent(getApplicationContext(), PanelActivity.class)); finish(); } else { showMessage("Error in login: " + loginResponse.getMessage()); } } else { message.append("Error in login: "); if (response.body() != null) message.append("\nBody\n" + response.body()); if (response.errorBody() != null) try { message.append("\nError\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<LoginResponse> call, Throwable t) { progressDialog.dismiss(); binding.login.setEnabled(true); String message = "Failure in the communication\n"; if (t != null) { Log.d("onFailure", t.getMessage()); message += t.getMessage(); } showMessage(message); binding.register.setEnabled(true); } }); }
Registro en RegisterActivity
private void sendToServer(String name, String email, String password, String confirmPassord) { progressDialog = new ProgressDialog(this); progressDialog.setIndeterminate(true); progressDialog.setMessage("Creating Account ..."); progressDialog.setCancelable(false); progressDialog.show(); binding.register.setEnabled(false); Call<RegisterResponse> call = ApiRestClient.getInstance().register(name, email, password, confirmPassord); //User user = new User(name, email, password); call.enqueue(new Callback<RegisterResponse>() { @Override public void onResponse(Call<RegisterResponse> call, Response<RegisterResponse> response) { progressDialog.dismiss(); //onRegisterSuccess(); binding.register.setEnabled(true); if (response.isSuccessful()) { RegisterResponse registerResponse = response.body(); if (registerResponse.getSuccess()) { //Log.d("onResponse", "" + registerResponse.getData().getToken()); //enviar al Login para entrar después de validar el email binding.register.setEnabled(true); Intent resultIntent = new Intent(); resultIntent.putExtra("email", email); resultIntent.putExtra("password", password); //guardar el token en shared preferences resultIntent.putExtra("token", registerResponse.getData().getToken()); setResult(RESULT_OK, resultIntent); finish(); } else { showMessage("Error in registration " + registerResponse.getMessage()); } } else { StringBuilder message = new StringBuilder(); message.append("Download error: " + response.code()); if (response.body() != null) message.append("\n" + response.body()); if (response.errorBody() != null) try { message.append("\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<RegisterResponse> call, Throwable t) { progressDialog.dismiss(); String message = "Failure in the communication\n"; if (t != null) { Log.d("onFailure", t.getMessage()); message += t.getMessage(); } showMessage(message); binding.register.setEnabled(true); } }); }
Adapter en TodoAdapter
public class TodoAdapter extends RecyclerView.Adapter<TodoAdapter.MyViewHolder> { private ArrayList<Task> tasks; public TodoAdapter(){ this.tasks = new ArrayList<>(); } // Provide a direct reference to each of the views within a data item // Used to cache the views within the item layout for fast access public class MyViewHolder extends RecyclerView.ViewHolder { private ItemViewBinding binding;//Name of the item_contact.xml in camel case + "Binding" public MyViewHolder(ItemViewBinding b) { super(b.getRoot()); binding = b; } } @Override public TodoAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ return new MyViewHolder(ItemViewBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); } // Involves populating data into the item through holder @Override public void onBindViewHolder(MyViewHolder holder, int position) { // Get the data model based on position Task task = tasks.get(position); holder.binding.description.setText(task.getDescription()); } @Override public int getItemCount() { return tasks.size(); } public int getId(int position){ return this.tasks.get(position).getId(); } public void setTasks(ArrayList<Task> tasks) { this.tasks = tasks; notifyDataSetChanged(); } public Task getAt(int position){ Task task; task = this.tasks.get(position); return task; } public void add(Task task) { this.tasks.add(task); notifyItemInserted(tasks.size() - 1); notifyItemRangeChanged(0, tasks.size() - 1); } public void modifyAt(Task task, int position) { this.tasks.set(position, task); notifyItemChanged(position); } public void removeAt(int position) { this.tasks.remove(position); notifyItemRemoved(position); notifyItemRangeChanged(0, tasks.size() - 1); } }
Respuesta para convertir el JSON
public class GetTasksResponse { @SerializedName("success") @Expose private Boolean success; @SerializedName("data") @Expose private ArrayList<Task> data = null; @SerializedName("message") @Expose private String message; public Boolean getSuccess() { return success; } public void setSuccess(Boolean success) { this.success = success; } public ArrayList<Task> getData() { return data; } public void setData(ArrayList<Task> data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
GetTasksData
public class GetTasksData { @SerializedName("id") @Expose private Integer id; @SerializedName("description") @Expose private String description; @SerializedName("created_at") @Expose private String createdAt; @SerializedName("updated_at") @Expose private String updatedAt; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getCreatedAt() { return createdAt; } public void setCreatedAt(String createdAt) { this.createdAt = createdAt; } public String getUpdatedAt() { return updatedAt; } public void setUpdatedAt(String updatedAt) { this.updatedAt = updatedAt; } }
DowloadTasks() en PanelActivity
private void downloadTasks() { progreso = new ProgressDialog(this); progreso.setProgressStyle(ProgressDialog.STYLE_SPINNER); progreso.setMessage("Connecting . . ."); progreso.setCancelable(false); progreso.show(); //Call<ArrayList<Site>> call = ApiRestClient.getInstance().getSites("Bearer " + preferences.getToken()); Call<GetTasksResponse> call = ApiTokenRestClient.getInstance(preferences.getToken()).getTasks(); call.enqueue(new Callback<GetTasksResponse>() { @Override public void onResponse(Call<GetTasksResponse> call, Response<GetTasksResponse> response) { progreso.dismiss(); if (response.isSuccessful()) { GetTasksResponse getTasksResponse = response.body(); if (getTasksResponse.getSuccess()) { adapter.setTasks(getTasksResponse.getData()); showMessage("Tasks downloaded ok"); } else { showMessage("Error downloading the tasks: " + getTasksResponse.getMessage()); } } else { StringBuilder message = new StringBuilder(); message.append("Download error: " + response.code()); if (response.body() != null) message.append("\n" + response.body()); if (response.errorBody() != null) try { message.append("\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<GetTasksResponse> call, Throwable t) { progreso.dismiss(); String message = "Failure in the communication\n"; if (t != null) message += t.getMessage(); showMessage(message); } }); }
Añadir una nueva tarea en AddActivity
private void connection(Task task) { progreso = new ProgressDialog(this); progreso.setProgressStyle(ProgressDialog.STYLE_SPINNER); progreso.setMessage("Connecting . . ."); progreso.setCancelable(false); progreso.show(); //Call<Site> call = ApiRestClient.getInstance().createSite("Bearer " + preferences.getToken(), s); Call<AddResponse> call = ApiTokenRestClient.getInstance(preferences.getToken()).createTask(task); call.enqueue(this); } @Override public void onResponse(Call<AddResponse> call, Response<AddResponse> response) { progreso.dismiss(); if (response.isSuccessful()) { AddResponse addResponse = response.body(); if (addResponse.getSuccess()) { Intent i = new Intent(); Bundle bundle = new Bundle(); bundle.putInt("id", addResponse.getData().getId()); bundle.putString("description", addResponse.getData().getDescription()); i.putExtras(bundle); setResult(OK, i); finish(); showMessage("Task created ok"); } else { String message = "Error creating the task"; if (!addResponse.getMessage().isEmpty()) { message += ": " + addResponse.getMessage(); } showMessage(message); } } else { StringBuilder message = new StringBuilder(); message.append("Download error: "); if (response.body() != null) message.append("\n" + response.body()); if (response.errorBody() != null) try { message.append("\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<AddResponse> call, Throwable t) { progreso.dismiss(); if (t != null) showMessage("Failure in the communication\n" + t.getMessage()); }
Actualizar una tarea
Eventos click y longClick
//manage click binding.recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, binding.recyclerView, new ClickListener() { @Override public void onClick(View view, final int position) { showMessage("Single Click on task with id: " + adapter.getAt(position).getId()); modify(adapter.getAt(position)); positionClicked = position; } @Override public void onLongClick(View view, int position) { showMessage("Long press on position :" + position); confirm(adapter.getAt(position).getId(), adapter.getAt(position).getDescription(), position); } }));
Lanzar UpdateActivity
private void modify(Task task) { Intent i = new Intent(this, UpdateActivity.class); i.putExtra("task", task); startActivityForResult(i, UPDATE_CODE); }
conectarse al API en UpdateActivity
private void connection(Task task) { showMessage(task.getId() + ""); progreso = new ProgressDialog(this); progreso.setProgressStyle(ProgressDialog.STYLE_SPINNER); progreso.setMessage("Connecting . . ."); progreso.setCancelable(false); progreso.show(); //Call<Site> call = ApiRestClient.getInstance().createSite("Bearer " + preferences.getToken(), s); Call<AddResponse> call = ApiTokenRestClient.getInstance(preferences.getToken()).updateTask(task, task.getId()); call.enqueue(this); } @Override public void onResponse(Call<AddResponse> call, Response<AddResponse> response) { progreso.dismiss(); if (response.isSuccessful()) { AddResponse addResponse = response.body(); if (addResponse.getSuccess()) { Intent i = new Intent(); Bundle bundle = new Bundle(); bundle.putInt("id", addResponse.getData().getId()); bundle.putString("description", addResponse.getData().getDescription()); i.putExtras(bundle); setResult(OK, i); finish(); showMessage("Task updated ok: " + addResponse.getData().getDescription()); } else { String message = "Error updating the task"; if (!addResponse.getMessage().isEmpty()) { message += ": " + addResponse.getMessage(); } showMessage(message); } } else { StringBuilder message = new StringBuilder(); message.append("Download error: "); Log.e("Error:", response.errorBody().toString()); if (response.body() != null) message.append("\n" + response.body()); if (response.errorBody() != null) try { message.append("\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<AddResponse> call, Throwable t) { progreso.dismiss(); if (t != null) showMessage("Failure in the communication\n" + t.getMessage()); }
Eliminar una tarea en PanelActivity
private void confirm(final int idTask, String description, final int position) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(description + "\nDo you want to delete?") .setTitle("Delete") .setPositiveButton("Confirm", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); connection(position); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); } }); builder.show(); }
conexión al API en PanelActivity para eliminar una tarea
private void connection(final int position) { //Call<ResponseBody> call = ApiRestClient.getInstance().deleteSite("Bearer " + preferences.getToken(), adapter.getId(position)); Call<DeleteResponse> call = ApiTokenRestClient.getInstance(preferences.getToken()).deleteTask(adapter.getId(position)); progreso.setProgressStyle(ProgressDialog.STYLE_SPINNER); progreso.setMessage("Connecting . . ."); progreso.setCancelable(false); progreso.show(); call.enqueue(new Callback<DeleteResponse>() { @Override public void onResponse(Call<DeleteResponse> call, Response<DeleteResponse> response) { progreso.dismiss(); if (response.isSuccessful()) { DeleteResponse deleteResponse = response.body(); if (deleteResponse.getSuccess()) { adapter.removeAt(position); showMessage("Task deleted OK"); } else showMessage("Error deleting the task"); } else { StringBuilder message = new StringBuilder(); message.append("Error deleting a site: " + response.code()); if (response.body() != null) message.append("\n" + response.body()); if (response.errorBody() != null) try { message.append("\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<DeleteResponse> call, Throwable t) { progreso.dismiss(); if (t != null) showMessage("Failure in the communication\n" + t.getMessage()); } }); }
Enviar un email en EmailActivity
private void connection(Email e) { progreso = new ProgressDialog(this); progreso.setProgressStyle(ProgressDialog.STYLE_SPINNER); progreso.setMessage("Connecting . . ."); progreso.setCancelable(false); progreso.show(); Call<EmailResponse> call = ApiTokenRestClient.getInstance(preferences.getToken()).sendEmail(e); call.enqueue(this); } @Override public void onResponse(Call<EmailResponse> call, Response<EmailResponse> response) { progreso.dismiss(); if (response.isSuccessful()) { EmailResponse emailResponse = response.body(); if (emailResponse.getSuccess()) { //Intent i = new Intent(); //setResult(OK, i); showMessage("Email sent ok: " + emailResponse.getMessage()); finish(); } else { String message = "Email not sent"; if (!emailResponse.getMessage().isEmpty()) { message += ": " + emailResponse.getMessage(); } showMessage(message); } } else { StringBuilder message = new StringBuilder(); message.append("Error sending the mail: " + response.code()); if (response.body() != null) message.append("\n" + response.body()); if (response.errorBody() != null) try { message.append("\n" + response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } showMessage(message.toString()); } } @Override public void onFailure(Call<EmailResponse> call, Throwable t) { String message = "Failure sending the email\n"; if (t != null) message += t.getMessage(); showMessage(message); }
Mejoras
- Usar el patrón MVVM en el diseño de la aplicación
- Enviar un email de verificación al registrarse un usuario y comprobar en el login si el usuario está verificado
- Añadir más campos a la tarea (título, fecha límite, observaciones, . . . )
- Devolver los códigos de estado adecuados en los errores (no solo el 404)
Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.