Skip to main content
ƚnase a nosotros en TDX, San Francisco o en Salesforce+ del 5 al 6 de marzo en la conferencia de desarrolladores para la era del agente de la IA. Regƭstrese ahora.

Modificar la aplicaciĆ³n forcedroid nativa

Objetivos de aprendizaje

DespuƩs de completar esta unidad, podrƔ:

  • Modificar la aplicaciĆ³n de plantilla Android nativa para personalizar la pantalla de lista.
  • Controlar una respuesta REST.
  • Eliminar un registro de Salesforce mediante una solicitud REST.

PersonalizaciĆ³n de la pantalla de lista

Como ha visto anteriormente, la aplicaciĆ³n de plantilla Android nativa muestra una lista de contactos o cuentas de la organizaciĆ³n de Salesforce del usuario. En la actualidad, es una lista de solo lectura creada a partir de una consulta SOQL SELECT sencilla que se procesa mediante clases de REST de Mobile SDK. Vamos a ampliar la capacidad de modificaciĆ³n mediante la adiciĆ³n de una acciĆ³n de eliminaciĆ³n al gesto de pulsaciĆ³n prolongada. Cuando el usuario toca de forma continua un nombre de contacto en la vista de lista, la nueva acciĆ³n de eliminaciĆ³n intenta eliminar el registro de Salesforce asociado. Si el intento tiene Ć©xito, la aplicaciĆ³n elimina permanentemente la fila de la vista de lista de contactos en la aplicaciĆ³n. Si la solicitud genera un error, la aplicaciĆ³n indica al usuario el motivo del error y restablece la fila de la vista de lista.

Acerca del proceso de escucha de clic prolongado

La implementaciĆ³n del proceso de escucha de clic prolongado es sencilla. Sin embargo, decidir cĆ³mo crear la clase de proceso de escucha de clic prolongado, es algo un poco mĆ”s difĆ­cil. Si analiza las distintas opciones de codificaciĆ³n, lo primero que descubre es que no se escuchan los clics en el nivel de vista de lista. En su lugar, se escuchan en el nivel de elemento de lista. Por suerte, la implementaciĆ³n de procesos de escucha no es una tarea compleja gracias a la interfaz OnItemLongClickListener de Android. Esta interfaz define un Ćŗnico proceso de escucha asociado a la vista de lista y que responde a las pulsaciones prolongadas de cualquier elemento de la lista. Cree una instancia de esta clase mediante la implementaciĆ³n de una interfaz pĆŗblica en su clase de vista.

El siguiente reto es determinar quĆ© clase de vista implementa el proceso de escucha de clic prolongado. En el caso de los objetos ListView, especifique un objeto de datos que proporcione la informaciĆ³n mostrada en la lista. La aplicaciĆ³n de plantilla de Mobile SDK crea un objeto ArrayAdapter<Cadena> con este fin y, a continuaciĆ³n, lo asocia a ListView.

listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new 
ArrayList<String>());
((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);

Sin embargo, ArrayAdapter<String> es un objeto de datos y no una vista, Āæverdad? SĆ­, y mucho mĆ”s. ArrayAdapter crea en la vista de lista de contactos un objeto AdapterView para cada elemento del conjunto de datos de la lista. Dado que estas vistas de adaptador representan los objetos de interĆ©s, use la clase AdapterView para implementar OnItemLongClickListener. A continuaciĆ³n, asocie el objeto de proceso de escucha con el objeto ListView, el cual recibe todas las notificaciones de sus elementos secundarios. Esta asociaciĆ³n limita OnItemLongClickListener a la interacciĆ³n solo con los elementos de la vista de lista de la aplicaciĆ³n de plantilla. Por Ćŗltimo, implemente su comportamiento de eliminaciĆ³n en el mĆ©todo de interfaz Ćŗnica.

Un detalle final que solucionar: ĀæDĆ³nde se incluye este cĆ³digo de proceso de escucha de clic prolongado? Mobile SDK proporciona los siguientes mĆ©todos de devoluciĆ³n de llamada de punto de entrada:

public abstract void onResume(RestClient client);
@Override
protected void onCreate(Bundle savedInstanceState);
@Override 
public void onResume();

Podemos eliminar uno de ellos: onCreate(Bundle savedInstanceState). Este mĆ©todo configura la actividad y controla los flujos de autenticaciĆ³n antes de que se creen instancias de las vistas. Las vistas entran en escena en el mĆ©todo onResume(). Por lo tanto, este mĆ©todo parecer ser la opciĆ³n mĆ”s probable. La llamada al mĆ©todo onResume(RestClient client) se realiza mediante la superclase en el inicio de sesiĆ³n para capturar el objeto RestClient, que vamos a dejar como estĆ”. Por lo tanto, ya tenemos los resultados. Agregue el cĆ³digo de proceso de escucha de clic prolongado a onResume().

ImplementaciĆ³n de un proceso de escucha de clic prolongado

En este caso, vamos a empezar por el cĆ³digo. En Android Studio, abra la clase MainActivity y examine el mĆ©todo onResume().
  1. En Android Studio, abra el archivo MainActivity.java.
  2. Busque el mƩtodo onResume().
    @Override 
    public void onResume() {
        // Hide everything until we are logged in
        findViewById(R.id.root).setVisibility(View.INVISIBLE);
        // Create list adapter
        listAdapter = new ArrayAdapter<String>(this, 
            android.R.layout.simple_list_item_1, new ArrayList<String>());
        ((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);			
        // ADD CODE HERE!
        super.onResume();
    }
    Vamos a empezar con la codificaciĆ³n segĆŗn el marcado (es decir, despuĆ©s establecer listAdapter para ListView, pero antes de la llamada super.onResume().
  3. Declare y asigne una variable ListView adecuada que haga referencia a la vista de lista de contactos. Use el mƩtodo Activity.findViewById() para buscar el recurso de la vista de lista.
    ((ListView) findViewById(R.id.contacts_list)).setAdapter(listAdapter);	
    ListView lv = ((ListView) findViewById(R.id.contacts_list));
    super.onResume();
  4. Con la variable lv, llame al mĆ©todo AdapterView.setOnItemLongClickListener() para configurar un proceso de escucha para los eventos de clic prolongado. En el caso del parĆ”metro del proceso de escucha, crea una instancia de cĆ³digo auxiliar en lĆ­nea de la interfaz AdapterView.OnItemLongClickListener.
    ListView lv = ((ListView) findViewById(R.id.contacts_list));
    lv.setOnItemLongClickListener(
        new AdapterView.OnItemLongClickListener() {
            @Override
    	 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                return false;
            }
        });
    
    Observe que Android Studio ordena el cĆ³digo auxiliar en el mĆ©todo de interfaz virtual Ćŗnica por usted. Ā”Muy Ćŗtil!
  5. (Opcional) Si obtiene un error porque falta una importaciĆ³n, agregue import android.widget.AdapterView a sus importaciones de clases.
  6. En el cuerpo AdapterView.OnItemLongClickListener, sustituya la declaraciĆ³n return reutilizable por cĆ³digo que presente un mensaje emergente.
    ListView lv = ((ListView) findViewById(R.id.contacts_list));
    lv.setOnItemLongClickListener (new AdapterView.OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view,
            int position, long id) {
            Toast.makeText(getApplicationContext(),
                "Long press received", Toast.LENGTH_SHORT).show();
            return true;
            }
    });
  7. Cree la aplicaciĆ³n y ejecĆŗtela.
  8. Cuando inicie sesiĆ³n en la aplicaciĆ³n, haga clic en Fetch Contacts (Obtener contactos).
  9. Toque una entrada de la lista de contactos y mantenga la pulsaciĆ³n durante un par de segundos. Si todo es correcto, se muestra el mensaje emergente.

AdiciĆ³n de solicitudes REST de Mobile SDK

Ya casi estamos listos para agregar elementos de Mobile SDK. En el mĆ©todo onItemLongClick(), cree una solicitud REST para eliminar el registro de Salesforce asociado a la fila tocada. A continuaciĆ³n, envĆ­e la solicitud a Salesforce. Antes de profundizar en el cĆ³digo, revise estos aspectos importantes.

ObtenciĆ³n de una instancia de RestClient

Recuerde que los objetos RestClient nunca se deben crear directamente. Mobile SDK crea uno y lo devuelve a MainActivity mediante el mƩtodo onResume(RestClient client). Esta instancia de RestClient se autentica con el token de acceso del usuario actual. Para su uso, el mƩtodo onResume(RestClient client) asigna esta instancia a la variable de clase client.

CreaciĆ³n de una solicitud REST

Para crear la solicitud REST para este ejercicio, llame al mĆ©todo de generador RestRequest para la eliminaciĆ³n de un registro:

public static RestRequest getRequestForDelete(String apiVersion, String objectType, String objectId);

ĀæDĆ³nde se obtienen los valores de argumento? Consulte esta tabla.

ParƔmetro Valor
apiVersion Se define en los recursos de la aplicaciĆ³n: getString(R.string.api_version)
objectType ā€œContactoā€ (codificado de forma rĆ­gida)
objectId ??
El parĆ”metro objectId es un elemento complejo. Requiere un valor de Salesforce que la aplicaciĆ³n forcedroid sin procesar no reconoce. ĀæPor quĆ© no lo tiene y quĆ© puede hacer para obtenerlo? Las respuestas son sencillas:
  • No tiene estos Id. porque las solicitudes REST originales (que completan las listas) no los solicitan.
  • Para obtener el Id. cambie la solicitudes REST.

Ajuste de la solicitud SOQL de la aplicaciĆ³n de plantilla

La clase MainActivity genera dos solicitudes REST: una para contactos y otra para cuentas. Cada solicitud contiene una declaraciĆ³n SOQL. Dado que no vamos a usar cuentas, vamos a actualizar la solicitud de registros de contacto para devolver valores de Id.

  1. En Android Studio, abra el archivo MainActivity.java.
  2. Busque el mƩtodo onFetchContactsClick().
    public void onFetchContactsClick(View v) throws UnsupportedEncodingException
    {
       sendRequest("SELECT Name FROM Contact");
    }
    
  3. Cambie la consulta SOQL para seleccionar los campos Name e Id. AsegĆŗrese de usar la ortografĆ­a con distinciĆ³n entre mayĆŗsculas y minĆŗsculas del nombre de campo de Id. Los nombres de campo distinguen entre mayĆŗsculas y minĆŗsculas.
    public void onFetchContactsClick(View v) throws UnsupportedEncodingException
    {
       sendRequest("SELECT Name, Id FROM Contact");
    }

Ahora que estĆ” preparado para recibir los valores de Id. en la respuesta REST, ĀæcuĆ”l es la mejor ubicaciĆ³n para almacenarlos? La aplicaciĆ³n de plantilla solo copia el valor de nombre para cada registro en una fila de la vista de lista, pero no almacena en cachĆ© los valores de Id. Para activar las bĆŗsquedas en el controlador de pulsaciĆ³n prolongada, debe almacenar los Id. en el Ć”mbito de clase.

AdaptaciĆ³n del mĆ©todo sendRequest() de la aplicaciĆ³n de plantilla

DesplĆ”cese al mĆ©todo sendRequest(String soql), que es a donde llega la respuesta obtenida. Este mĆ©todo es una demostraciĆ³n clara de cĆ³mo funciona el mecanismo REST de Mobile SDK. Veamos rĆ”pidamente cĆ³mo funciona. Primero, el mĆ©todo llama a un mĆ©todo de generador RestRequest que define una solicitud REST para una consulta SOQL determinada:
RestRequest restRequest = RestRequest.getRequestForQuery(
    ApiVersionStrings.getVersionNumber(this), soql);

A continuaciĆ³n, envĆ­a el nuevo objeto RestRequest a Salesforce en la llamada client.sendAsync().

client.sendAsync(restRequest, new AsyncRequestCallback() {
    @Override
    public void onSuccess(RestRequest request, final RestResponse result) {
        result.consumeQuietly(); // consume before going back to main thread
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    listAdapter.clear();
                    JSONArray records = result.asJSONObject().getJSONArray("records");
                    for (int i = 0; i < records.length(); i++) {
                        listAdapter.add(records.getJSONObject(i).getString("Name"));
                    }
                } catch (Exception e) {
                    onError(e);
                }
            }
        });
    }
 
    @Override
    public void onError(final Exception exception) {
        runOnUiThread(new Runnable() {
        @Override
            public void run() {
                Toast.makeText(MainActivity.this,
                    MainActivity.this.getString(
                        R.string.sf__generic_error, 
                        exception.toString()),
                    Toast.LENGTH_LONG).show();
            }
        });
    }
});

AdemĆ”s del objeto RestRequest, la llamada sendAsync() requiere una implementaciĆ³n de la interfaz AsyncRequestCallback de Mobile SDK. El mĆ©todo onSuccess() de esta interfaz recibe la respuesta REST de forma asĆ­ncrona mediante una devoluciĆ³n de llamada. La implementaciĆ³n AsyncRequestCallback predeterminada controla solo las consultas SOQL definidas en la aplicaciĆ³n forcedroid.

Este mĆ©todo onSuccess() ya hace lo que necesitamos. Contiene el cĆ³digo que extrae los registros devueltos por la respuesta REST y los asigna a la variable records local. Vamos a mover esta variable al Ć”mbito de clase. Para ello, se vuelve a declarar fuera del cuerpo del mĆ©todo.
  1. Junto a la parte superior de la definiciĆ³n de clase MainActivity, declare JSONArray records como una variable privada con las siguientes declaraciones de variable de clase existentes:
    public class MainActivity extends SalesforceActivity {
        private RestClient client;
        private ArrayAdapter<String> listAdapter;
        private JSONArray records;
       ā€¦.
  2. En el mĆ©todo onSuccess(), elimine la declaraciĆ³n de tipo para la variable records:
    public void onSuccess(RestRequest request, final RestResponse result) {
        result.consumeQuietly(); // consume before going back to main thread
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    listAdapter.clear();
                    records = result.asJSONObject().getJSONArray("records");
                    for (int i = 0; i < records.length(); i++) {
                        listAdapter.add(records.getJSONObject(i).getString("Name"));
                    }
                } catch (Exception e) {
                    onError(e);
                }
            }
        });
    }

FinalizaciĆ³n del mĆ©todo onItemLongClick()

Ya estƔ preparado para finalizar el mƩtodo onItemLongClick(). El algoritmo bƔsico es el siguiente:

  1. Obtenga un objeto de ā€œsolicitud de eliminaciĆ³nā€ mediante la llamada a un mĆ©todo de generador RestRequest de Mobile SDK apropiado. Dado que todos los mĆ©todos RestRequest devuelven excepciones, asegĆŗrese de incluir la llamada en un bloque try...catch.
  2. EnvĆ­e el objeto de ā€œsolicitud de eliminaciĆ³nā€ a Salesforce mediante el objeto RestClient generado.
  3. Controle el resultado de REST en mĆ©todos de devoluciĆ³n de llamada.

Obtener un objeto RestRequest

  1. Vuelva a desplazarse al mƩtodo onItemLongClick() en el mƩtodo onResume().
  2. DespuƩs de la llamada Toast.makeText(), declare un objeto local RestRequest llamado restRequest. Inicialƭcelo como null.
    RestRequest restRequest = null;
  3. Agregue una construcciĆ³n try...catch vacĆ­a.
    RestRequest restRequest = null;
    try {
    } catch (Exception e) {
     
    }
  4. En el bloque try, llame a un mĆ©todo de generador que obtenga un objeto de solicitud REST para una operaciĆ³n de eliminaciĆ³n. SUGERENCIA: Use el mĆ©todo estĆ”tico RestRequest.getRequestForDelete().
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
                   // arguments?
                );
    } catch (Exception e) {
     
    }
  5. Para el primer parĆ”metro, recupere la versiĆ³n de la API de Salesforce especificada en los recursos del Mobile SDK de su proyecto.
    RestRequest restRequest = null;
    try {
         restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), //...);
    } catch (Exception e) {
    }
  6. Para el parĆ”metro objectType, especifique ā€œContactā€.
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), "Contact", //...);
    } catch (Exception e) {
    }
  7. Pase a RestRequest.getRequestForDelete() el Id. de la entrada de la matriz de registros que coincide con la posiciĆ³n de vista de lista actual. AsĆ­ es como puede recuperar el Id.:
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), "Contact",
            records.getJSONObject(position).getString("Id"));
        // Send the request
        // ...
    } catch (Exception e) {
    }
  8. En el bloque catch, llame a printStackTrace() en el argumento Exception.
    RestRequest restRequest = null;
    try {
        restRequest = RestRequest.getRequestForDelete(
            getString(R.string.api_version), "Contact",
            records.getJSONObject(position).getString("Id"));
        // Send the request
        // ...
    } catch (Exception e) {
        e.printStackTrace();
    }

Una vez que obtenga el objeto de ā€œsolicitud de eliminaciĆ³nā€, envĆ­elo a Salesforce y controle el resultado en mĆ©todos de devoluciĆ³n de llamada.

Agregar el mƩtodo RestClient.sendAsync()

Ā”Ya casi ha terminado! La Ćŗltima pieza del puzle es el envĆ­o de la solicitud mediante el mĆ©todo RestClient.sendAsync(). Este mĆ©todo requiere que implemente la interfaz AsyncRequestCallback. Como sabe, Mobile SDK envĆ­a las respuestas REST a los mĆ©todos AsyncRequestCallback.

  1. En onItemLongClick(), despuĆ©s de la llamada getRequestForDelete(), copie y peque el cĆ³digo RestClient.sendAsync() del mĆ©todo sendRequest().
  2. Elimine el cĆ³digo interno de la rama try del mĆ©todo onSuccess(). No elimine la rama catch, ya que solo llama a un controlador de errores.
  3. Mantenga la implementaciĆ³n de sustituciĆ³n onError(), ya que es lo bastante genĆ©rica para funcionar con cualquier respuesta de Salesforce.

Esta es la llamada de cĆ³digo auxiliar a RestClient.sendAsync().

restRequest = RestRequest.getRequestForDelete(
        getString(R.string.api_version), "Contact",
        records.getJSONObject(position).getString("Id"));
client.sendAsync(restRequest, new AsyncRequestCallback() {
    @Override
    public void onSuccess(RestRequest request, final RestResponse result) {
        result.consumeQuietly();
        runOnUiThread(new Runnable() { 
            @Override
            public void run() {
                // Network component doesnā€™t report app layer status.
                // Use Mobile SDK RestResponse.isSuccess() method to check
                // whether the REST request itself succeeded.
                if (result.isSuccess()) {
                    try {
                    } catch (Exception e) {
                        onError(e);
                    }
                }
            }
        });
    }
    @Override
    public void onError(final Exception exception) {
        runOnUiThread(new Runnable() {
        @Override
            public void run() {
                Toast.makeText(MainActivity.this,
                        MainActivity.this.getString(R.string.sf__generic_error, exception.toString()),
                        Toast.LENGTH_LONG).show();
            }
        });
    }
});

Implementar el mĆ©todo de devoluciĆ³n de llamada onSuccess()

En el mƩtodo onSuccess() de AsyncRequestCallback(), haga lo siguiente:
  1. AsegĆŗrese de que la operaciĆ³n de eliminaciĆ³n es correcta mediante la prueba del estado HTTP. Esta comprobaciĆ³n es necesaria, ya que el componente de red subyacente solo indica errores de la capa de transporte y no errores de solicitud.
  2. Si la operaciĆ³n es correcta, elimine el elemento de la posiciĆ³n correspondiente de la vista de lista.
  3. Publique un mensaje de resultado correcto.
Use la variable de clase listAdapter para eliminar la fila. Puede llamar a ArrayAdapter.remove(T object) con el valor de posiciĆ³n pasado al mĆ©todo onItemLongClick() para obtener el objeto. Por ejemplo:
listAdapter.remove(listAdapter.getItem(position));
Si agrega este cĆ³digo, se genera un problema de Ć”mbito. Dado que estĆ” trabajando en un contexto de implementaciĆ³n de interfaz, no puede usar la variable position local del contexto onItemLongClick(). En su lugar, puede agregar una variable de clase y asignarle la variable de posiciĆ³n.
  1. En la parte superior de la clase, declare e inicialice una variable de clase privada llamada pos del tipo int.
    public class MainActivity extends SalesforceActivity {
        private RestClient client;
        private ArrayAdapter<String> listAdapter;
        private JSONArray records;
        private int pos = -1;
  2. En la primera lƭnea del mƩtodo onItemLongClick(), capture el valor position:
    public boolean onItemLongClick(AdapterView<?> parent, View view,
    	int position, long id) {
    	pos = position;
    	...
  3. En el mĆ©todo onSuccess() de su implementaciĆ³n de AsyncRequestCallback, desplĆ”cese hacia abajo algunas lĆ­neas hasta el bloque auxiliar if.
    if (result.isSuccess()) {
        try {
        } catch (Exception e) {
            onError(e);
        }
    }
  4. Si result.isSuccess() es verdadero, elimine la fila mediante la llamada al mƩtodo listAdapter.remove(). Use pos en lugar de position para eliminar la fila:
    if (result.isSuccess()) {
        listAdapter.remove(listAdapter.getItem(pos));
    }
  5. DespuƩs de eliminar un elemento de lista, llame a sendRequest(request) para actualizar la lista reordenada y mantenerla en sincronƭa con su matriz records local:
    if (result.isSuccess()) {
        listAdapter.remove(listAdapter.getItem(pos));
        sendRequest(ā€SELECT Name, Id FROM Contactā€);
    }
  6. Por Ćŗltimo, publique un cuadro de alerta para mostrar un mensaje de resultado correcto. En caso contrario, indique el mensaje de error correspondiente.
    if (result.isSuccess()) {
        listAdapter.remove(listAdapter.getItem(pos));
        sendRequest(ā€SELECT Name, Id FROM Contactā€);
        AlertDialog.Builder b = new AlertDialog.Builder(findViewById(R.id.contacts_list).getContext());
        b.setMessage("Record successfully deleted!");
        b.setCancelable(true);
        AlertDialog a = b.create();
        a.show();
    } else {
       Toast.makeText(MainActivity.this,
             MainActivity.this.getString(R.string.sf__generic_error, result.toString()),
             Toast.LENGTH_LONG).show();
    }

Este es el mƩtodo onItemLongClick() completado.

@Override
public boolean onItemLongClick(AdapterView<?> parent, 
        View view, int position, long id) {
    pos = position;
    Toast.makeText(getApplicationContext(),
        "Long press detected", Toast.LENGTH_SHORT).show();
    RestRequest restRequest = null;
    try {
       RestRequest request = RestRequest.getRequestForDelete(
           getString(R.string.api_version), "Contact", 
               records.getJSONObject(position).getString("Id"));
       client.sendAsync(request, new AsyncRequestCallback() {
            @Override
            public void onSuccess(RestRequest request, final RestResponse result) {
                result.consumeQuietly();
                runOnUiThread(new Runnable() { 
                    @Override
                    public void run() {
                        try {
                            // Network component doesnā€™t report app layer status.
                            // Use Mobile SDK RestResponse.isSuccess() method to check
                            // whether the REST request itself succeeded. 
                            if (result.isSuccess()) {                                        
                                listAdapter.remove(listAdapter.getItem(pos));
                                sendRequest(ā€SELECT Name, Id FROM Contactā€);
                                AlertDialog.Builder b = 
                                    new AlertDialog.Builder(findViewById
                                        (R.id.contacts_list).getContext());
                                b.setMessage("Record successfully deleted!");
                                b.setCancelable(true);
                                AlertDialog a = b.create();
                                a.show();
                            } else {
                                Toast.makeText(MainActivity.this,
                                    MainActivity.this.getString(
                                        R.string.sf__generic_error, 
                                        result.toString()),
                                    Toast.LENGTH_LONG).show(); 
                            }   
                        } catch (Exception e) {
                            onError(e);
                        }
                    }});
                }
                @Override
                public void onError(final Exception exception) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {		          
                            Toast.makeText(MainActivity.this,
                                MainActivity.this.getString(
                                    R.string.sf__generic_error, 
                                    exception.toString()),
                                Toast.LENGTH_LONG).show();
                        }
                    });
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    return true;
}

Limpieza final y tiempo de ejecuciĆ³n

Parte de la limpieza final consiste en eliminar el botĆ³n Fetch Accounts (Obtener cuentas). Dado que la vista de lista se comparte entre Fetch Contacts (Obtener contactos) y Fetch Accounts (Obtener cuentas), el controlador de pulsaciĆ³n prolongada se aplica a ambos por igual. No obstante, este controlador no es vĆ”lido para las cuentas, ya que el Id. usado para eliminar el registro solo se aplica a un contacto. De forma alternativa y como ā€œventaja adicionalā€, puede aplicar lo que ha aprendido y adaptar el controlador de pulsaciĆ³n prolongada para eliminar contactos y cuentas. Sin embargo, en este tutorial, vamos a eliminar el cĆ³digo relacionado con las cuentas.

Elimine los siguientes elementos de los archivos indicados:

Archivo AcciĆ³n
MainActivity.java Elimine el mƩtodo onFetchAccountsClick(View v).
res/layout/Main.xml Realice una de las siguientes acciones:
  • En Graphical Layout (Formato grĆ”fico), elimine el botĆ³n ā€œFetch Accountsā€ (Obtener cuentas).
  • En la vista XML, elimine el nodo <Button> con el Id. "@+id/fetch_accounts".
res/values/strings.xml Realice una de las siguientes acciones:
  • En la ficha Resources (Recursos): seleccione ā€œfetch_accounts_button (String)ā€ y haga clic en Remove (Eliminar).
  • En la vista XML: elimine el nodo <string> con el nombre ā€œfetch_accounts_buttonā€.

Al fin, su aplicaciĆ³n estĆ” terminada y lista para su ejecuciĆ³n.

  1. En Android Studio, haga clic en Run | Run ā€˜appā€™ (Ejecutar | Ejecutar ā€˜aplicaciĆ³nā€™).
  2. Seleccione un emulador o dispositivo conectado compatible con Mobile SDK.
  3. Cuando la aplicaciĆ³n se estĆ© ejecutando, inicie sesiĆ³n en su organizaciĆ³n de Salesforce y, a continuaciĆ³n, haga clic en Fetch Contacts (Obtener contactos) para ver la lista. Toque cualquier elemento de la lista y mantenga la pulsaciĆ³n hasta que se muestre un mensaje emergente para confirmar la pulsaciĆ³n prolongada.

Observe que obtiene una respuesta de error al intentar eliminar cualquier contacto predeterminado de la base de datos de Developer Edition. Estos errores se producen porque cada contacto que viene empaquetado previamente de una organizaciĆ³n de Developer Edition es el elemento principal de otros registros. Para prepararse para las pruebas, inicie sesiĆ³n en su organizaciĆ³n de Developer Edition y cree uno o varios contactos de prueba que no tengan otros registros en propiedad. Si la eliminaciĆ³n es correcta, se muestra un mensaje para indicar que el registro se ha eliminado.

Comparta sus comentarios de Trailhead en la Ayuda de Salesforce.

Nos encantarƭa saber mƔs sobre su experiencia con Trailhead. Ahora puede acceder al nuevo formulario de comentarios en cualquier momento en el sitio de Ayuda de Salesforce.

MĆ”s informaciĆ³n Continuar a Compartir comentarios