Blog >Comunicación con servidor > Enviar Tweet desde aplicación Android
Continuamos con el apartado
Mi aplicación Android con Twitter, vamos a ver como generar un
Tweet desde nuestra aplicación.
Mandar un tweet desde nuestra aplicación Android
El proyecto que os expongo tiene las librerías y las clases necesarias para poder mandar un tweet sin Twitter instalado en el dispositivo, es decir desde esta aplicación se verifica la aplicación que previamente se ha instalado en twitter y que se comenta en este post.
La función de esta aplicación va permitirnos conectarnos realizar una conexión http a twitter mandando las claves que previamente teníamos en la cabecera de la petición.
1. Instalar librerías y permiso a la app de internet
Tendremos que darle a la aplicación permisos para que pueda conectarse a Internet.
Nos va a hacer falta usar varias librerias, unas que tienen que ver con el framework de twitter, otras para la autentificación y otra para la conexión http :
O también os he preparado un rar con todas ellas juntas que podreis encontrar aquí.
2. Creación de interfad, inicio sesión configuración clases y conexión a Twitter
Creamos un proyecto nuevo, y vamos a darle la interfaz de usuario, pero antes agregamos estos recursos :
Carpeta values...
colores.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="negro" >#000000</color>
<color name="blanco">#ffffff</color>
<color name="colorTweet">#908686</color>
<color name="colorFace">#3b5997</color>
<color name="colorTwitter">#1ab2e8</color>
<color name="RojoError">#e81a29</color>
</resources>
Carpeta drawable...
botontwitter : Apariencia del botón al enviar tweets
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true">
<shape>
<!-- color de fondo -->
<solid android:color="@android:color/white"/>
<!-- curvatura esquinas -->
<corners android:radius="12dp"/>
<!-- padding para separar entre elementos contenidos y el borde -->
<padding android:left="10dp"
android:right="10dp"
android:top="10dp"
android:bottom="10dp"/>
</shape>
</item>
twitter_check : recurso xml que cambia de forma automática la imagen del checkbox
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:state_window_focused="true"
android:state_enabled="true"
android:drawable="@drawable/twitter_cnn" />
<item
android:state_checked="false"
android:state_window_focused="true"
android:state_enabled="true"
android:drawable="@drawable/twitter_desc" />
</selector>
Este ultimo recurso usa 2 imágenes que hay que arrastrar al proyecto, así que cada uno se lo personalice como quiera,y una vez tenemos esto, vamos con el activity_main.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/TWITTTEAR"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<CheckBox
android:id="@+id/twitterCheckConnection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="Conectado" />
<CheckBox
android:id="@+id/twitterCheck"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:clickable="true"
android:focusable="true"
android:text="Conectado usuario"
android:textColor="@color/colorTwitter"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:orientation="vertical" >
<EditText
android:id="@+id/tweet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="3"
android:textColor="@color/colorTweet" >
<requestFocus />
</EditText>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp" >
<TextView
android:id="@+id/contarCaracteresTwitter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:text="0"
android:textColor="@color/colorTwitter"
android:textSize="20sp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="@+id/enviarTweet"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginBottom="5dp"
android:layout_marginRight="10dp"
android:background="@drawable/botontwitter"
android:text="Enviar"
android:textColor="@color/blanco" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="280dp"
android:layout_alignParentLeft="false"
android:layout_alignParentTop="false"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:orientation="vertical" >
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
</RelativeLayout>
Y este es nuestro main de momento :
public class MainActivity extends Activity {
//CLAVES
private static final String twitter_consumer_key = "AQUI TU CONSUMER_KEY";
private static final String twitter_secret_key = "AQUI TU TWITTER_SECRET_KEY";
//Elementos
private CheckBox connectionCheck;
private CheckBox userCheck;
private ListView lista;
private Button BotonEnviarTweet;
private EditText tweet;
private TextView Ncaracteres;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//INSTANCIAMOS ELEMENTOS
instanciarElementos();
//INICIAMOS VARIABLES
mTwitter = new TwitterApp(this, twitter_consumer_key,twitter_secret_key);
mTwitter.setListener(mTwLoginDialogListener);
//BOTON PARA ENVIAR TWEETS
BotonEnviarTweet.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
//CHECKBOX CONECTAR
registerCheck.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
//CHECKBOX USER
connectionCheck.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
public void instanciarElementos(){
//Elementos
registerCheck = (CheckBox) findViewById(R.id.twitterCheckConnection);
connectionCheck = (CheckBox) findViewById(R.id.twitterCheck);
lista = (ListView) findViewById(R.id.listViewTweets);
BotonEnviarTweet = (Button) findViewById(R.id.enviarTweet);
tweet = (EditText) findViewById(R.id.tweet);
Ncaracteres =(TextView) findViewById(R.id.contarCaracteresTwitter);
}
}
Seguimos con otra clase : TwitterSession.
Esta clase contiene los datos de registro en twitter, como la gestión de las preferencias para guardar los datos para identificarte en Twitter.
public class TwitterSession {
private SharedPreferences sharedPref;
private Editor editor;
private static final String TWEET_AUTH_KEY = "auth_key";
private static final String TWEET_AUTH_SECRET_KEY = "auth_secret_key";
private static final String TWEET_USER_NAME = "user_name";
private static final String SHARED = "Twitter_Preferences";
public TwitterSession(Context context) {
sharedPref= context.getSharedPreferences(SHARED, Context.MODE_PRIVATE);
editor= sharedPref.edit();
}
public void storeAccessToken(AccessToken accessToken, String username) {
editor.putString(TWEET_AUTH_KEY, accessToken.getToken());
editor.putString(TWEET_AUTH_SECRET_KEY, accessToken.getTokenSecret());
editor.putString(TWEET_USER_NAME, username);
editor.commit();
}
public void resetAccessToken() {
editor.putString(TWEET_AUTH_KEY, null);
editor.putString(TWEET_AUTH_SECRET_KEY, null);
editor.putString(TWEET_USER_NAME, null);
editor.commit();
}
public String getUsername() {
return sharedPref.getString(TWEET_USER_NAME, "");
}
public AccessToken getAccessToken() {
String token = sharedPref.getString(TWEET_AUTH_KEY, null);
String tokenSecret = sharedPref.getString(TWEET_AUTH_SECRET_KEY, null);
if (token != null && tokenSecret != null)
return new AccessToken(token, tokenSecret);
else
return null;
}
}
Ahora vamos a insertar una nueva clase : TwitterApp.
En ella vemos como se gestiona la llamada http, el registro mediante la cabecera en Twitter y la recogida de la respuesta.
//CLASE CON LOS PARAMETROS PARA CONECTAR EN TWITTER
public class TwitterApp {
private Twitter mTwitter;
private TwitterSession mSession;
private AccessToken mAccessToken;
private CommonsHttpOAuthConsumer mHttpOauthConsumer;
private OAuthProvider mHttpOauthprovider;
private String mConsumerKey;
private String mSecretKey;
private ProgressDialog mProgressDlg;
private TwDialogListener mListener;
private Context context;
private boolean mInit = true;
public static final String CALLBACK_URL = "twitterapp://connect";
private static final String TAG = "TwitterApp";
//CONSTRUCTOR
public TwitterApp(Context context, String consumerKey, String secretKey) {
this.context= context;
//INSTANCIA TWITTER
mTwitter = new TwitterFactory().getInstance();
mSession= new TwitterSession(context);
mProgressDlg= new ProgressDialog(context);
mProgressDlg.requestWindowFeature(Window.FEATURE_NO_TITLE);
//DATOS ACCESO TWITTER
setmConsumerKey(consumerKey);
setmSecretKey(secretKey);
//REALIZAMOS LA CONEXION CON RESPUESTA
mHttpOauthConsumer = new CommonsHttpOAuthConsumer(getmConsumerKey(), getmSecretKey());
mHttpOauthprovider = new DefaultOAuthProvider("https://api.twitter.com/oauth/request_token ",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize");
mAccessToken= mSession.getAccessToken();
configureToken();
}
//DEVUELVE EL LISTENER PARA EL ALERTDIALOG
public void setListener(TwDialogListener listener) {
mListener = listener;
}
//funcion para iniciar sesion la primera vez
private void configureToken() {
if (mAccessToken != null) {
if (mInit) {
mTwitter.setOAuthConsumer(getmConsumerKey(), getmSecretKey());
mInit = false;
}
mTwitter.setOAuthAccessToken(mAccessToken);
}
}
public boolean estasConectado() {
if(mAccessToken == null){
return false;
}
return true;
}
public void resetAccessToken() {
if (mAccessToken != null) {
mSession.resetAccessToken();
mAccessToken = null;
}
}
public String getUsername() {
return mSession.getUsername();
}
public void updateStatus(String status) throws Exception {
try {
mTwitter.updateStatus(status);
} catch (TwitterException e) {
throw e;
}
}
public void authorize() {
mProgressDlg.setMessage("Initializing ...");
mProgressDlg.show();
//NUEVO HILO CON EL ALERT PARA QUE SE ABRA LA VENTANA
new Thread() {
@Override
public void run() {
String authUrl = "";
int what = 1;
try {
//hacemos la llamada al navegador
authUrl = mHttpOauthprovider.retrieveRequestToken(mHttpOauthConsumer, CALLBACK_URL);
what = 0;
Log.d(TAG, "Request token url " + authUrl);
} catch (Exception e) {
//EL PROCESO HA FALLADO
Log.d(TAG, "Failed to get request token");
e.printStackTrace();
}
mHandler.sendMessage(mHandler.obtainMessage(what, 1, 0, authUrl));
}
}.start();
}
//
public void processToken(String callbackUrl) {
mProgressDlg.setMessage("Finalizing ...");
mProgressDlg.show();
final String verifier = getVerifier(callbackUrl);
new Thread() {
@Override
public void run() {
int what = 1;
try {
mHttpOauthprovider.retrieveAccessToken(mHttpOauthConsumer, verifier);
mAccessToken = new AccessToken(mHttpOauthConsumer.getToken(), mHttpOauthConsumer.getTokenSecret());
Log.d(TAG, "Token: " + mAccessToken.getToken());
configureToken();
User user = mTwitter.verifyCredentials();
mSession.storeAccessToken(mAccessToken, user.getName());
what = 0;
} catch (Exception e){
Log.d(TAG, "Error getting access token");
e.printStackTrace();
}
mHandler.sendMessage(mHandler.obtainMessage(what, 2, 0));
}
}.start();
}
//RECOJEMOS LA RESPUESTA
@SuppressWarnings("deprecation")
private String getVerifier(String callbackUrl) {
String verifier = "";
try {
callbackUrl = callbackUrl.replace("twitterapp", "http");
URL url = new URL(callbackUrl);
String query = url.getQuery();
String array[] = query.split("&");
for (String parameter : array) {
String v[] = parameter.split("=");
if (URLDecoder.decode(v[0]).equals(oauth.signpost.OAuth.OAUTH_VERIFIER)) {
verifier = URLDecoder.decode(v[1]);
break;
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return verifier;
}
private void showLoginDialog(String url) {
final TwDialogListener listener = new TwDialogListener() {
@Override
public void onComplete(String value) {
processToken(value);
}
@Override
public void onError(String value) {
mListener.onError("Failed opening authorization page");
}
};
new TwitterDialog(context, url, listener).show();
}
public String getmConsumerKey() {
return mConsumerKey;
}
public void setmConsumerKey(String mConsumerKey) {
this.mConsumerKey = mConsumerKey;
}
public String getmSecretKey() {
return mSecretKey;
}
public void setmSecretKey(String mSecretKey) {
this.mSecretKey = mSecretKey;
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mProgressDlg.dismiss();
if (msg.what == 1) {
if (msg.arg1 == 1)
mListener.onError("Error getting request token");
else
mListener.onError("Error getting access token");
} else {
if (msg.arg1 == 1)
showLoginDialog((String) msg.obj);
else
mListener.onComplete("");
}
}
};
public interface TwDialogListener {
public void onComplete(String value);
public void onError(String value);
}
}
Esta clase también usa una interfad como listener, esto es para que cuando esté abierto el WebView dentro del dialog, podamos interactuar con ella posteriormente de forma automática vuelve el foco a la activity.
La clase TwitterDialog, que usa un alertDialog y se introduce un webView dentro, personaliza la cabecera del dialog y usa de apoyo una clase que hereda de WebViewClient, que es la que nos vale para interactuar con el webView que hay dentro del dialog.
public class TwitterDialog extends Dialog {
static final FrameLayout.LayoutParams FILL = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
static final int MARGIN = 4;
static final int PADDING = 2;
private String mUrl;
private TwDialogListener mListener;
private ProgressDialog mDialog;
private WebView mWebView;
private LinearLayout mContent;
private TextView mTitulo;
private static final String TAG = "Twitter-WebView";
public TwitterDialog(Context context, String url, TwDialogListener listener) {
super(context);
mUrl= url;
mListener=listener;
}
@SuppressWarnings("deprecation")
@Override
//ESTA CLASE CARGA UN WEBVIEW EN UN DIALOG
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialog = new ProgressDialog(getContext());
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setMessage("Cargando...");
mContent = new LinearLayout(getContext());
mContent.setOrientation(LinearLayout.VERTICAL);
setUpTitle();
setUpWebView();
Display display = getWindow().getWindowManager().getDefaultDisplay();
Point outSize= new Point();
int width= 0;
int height= 0;
double[] dimensions = new double[2];
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(outSize);
width = outSize.x;
height = outSize.y;
} else {
width = display.getWidth();
height = display.getHeight();
}
if (width < height) {
dimensions[0] = 0.87 * width;
dimensions[1] = 0.82 * height;
} else {
dimensions[0] = 0.75 * width;
dimensions[1] = 0.75 * height;
}
addContentView(mContent, new FrameLayout.LayoutParams((int) dimensions[0], (int) dimensions[1]));
}
//QUITA EL TITULO DEL DIALOG Y CONFIGURA UN TEXTVIEW
//QUE APARECERÁ COMO TÍTULO
private void setUpTitle() {
requestWindowFeature(Window.FEATURE_NO_TITLE);
Drawable icon = getContext().getResources().getDrawable(R.drawable.twitter_desc);
mTitulo = new TextView(getContext());
mTitulo.setText("Twitter");
mTitulo.setTextColor(Color.WHITE);
mTitulo.setTypeface(Typeface.DEFAULT_BOLD);
mTitulo.setBackgroundColor(0xFFbbd7e9);
mTitulo.setPadding(MARGIN + PADDING, MARGIN, MARGIN, MARGIN);
mTitulo.setCompoundDrawablePadding(MARGIN + PADDING);
mTitulo.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
mContent.addView(mTitulo);
}
@SuppressLint("SetJavaScriptEnabled")
private void setUpWebView() {
CookieSyncManager.createInstance(getContext());
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
mWebView = new WebView(getContext());
mWebView.setVerticalScrollBarEnabled(false);
mWebView.setHorizontalScrollBarEnabled(false);
mWebView.setWebViewClient(new TwitterWebViewClient());
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadUrl(mUrl);
mWebView.setLayoutParams(FILL);
mContent.addView(mWebView);
}
//CLASE QUE HEREDA DE WEBVIEWCLIENT Y LLEVA LA GESTION DE LA WEBVIEW SW CREDENCIALES
private class TwitterWebViewClient extends WebViewClient {
//METODO PARA CARGAR LA WEB
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d(TAG, "Redirecting URL " + url);
if (url.startsWith(TwitterApp.CALLBACK_URL)) {
mListener.onComplete(url);
TwitterDialog.this.dismiss();
return true;
} else if (url.startsWith("authorize")) {
return false;
}
return true;
}
//SI LA PAGINA DA ERROR
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Log.d(TAG, "Page error: " + description);
super.onReceivedError(view, errorCode, description, failingUrl);
mListener.onError(description);
TwitterDialog.this.dismiss();
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d(TAG, "Loading URL: " + url);
super.onPageStarted(view, url, favicon);
mDialog.show();
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
String title = mWebView.getTitle();
if (title != null && title.length() > 0) {
mTitulo.setText(title);
}
mDialog.dismiss();
}
}
}
Y ahora implementamos en el main 2 funciones, que dependiendo si se está registrado o no, saca el dialog con el webview para insertar las credenciales, o por otro lado si se está registrado, se prepara para enviar el tweet.
private void onTwitterClick() {
//SI YA ESTAS CONECTADO A TWITTER
if (mTwitter.estasConectado()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
//MESAJE CON LA CONFIRMACION DE LA DESCONEXION
builder.setMessage("Delete current Twitter connection?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@SuppressLint("ResourceAsColor")
public void onClick(DialogInterface dialog, int id) {
mTwitter.resetAccessToken();
//ACTUALIZAMOS CHECKBOX
registerCheck.setChecked(false);
registerCheck.setText(" Not connected ");
registerCheck.setTextColor(R.color.colorTweet);
}
})
//EN EL CASO DE QUE SE PULSE NO, VOLVEMOS A LA PRIMERA PANTALLA
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
registerCheck.setChecked(true);
}
});
final AlertDialog alert = builder.create();
alert.show();
//SINO ESTAS CONECTADO MANDAMOS A AUTHORIZE, DONDE APARECE
//PARA ENVIAR LAS CREDENCIALES DE AUTENTIFICACION
} else {
registerCheck.setChecked(false);
//Cargamos loading... mas credenciales de twitter
mTwitter.authorize();
}
}
@SuppressLint("ResourceAsColor")
private final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
@Override
public void onComplete(String value) {
//YA CONECTADO PIDE EL NOMBRE A LA RESPUESTA HTTP
String username = mTwitter.getUsername();
username= (username.equals("")) ? "No Name" : username;
registerCheck.setText(" Conectado (" + username + ")");
registerCheck.setChecked(true);
registerCheck.setTextColor(R.color.colorTweet);
Toast.makeText(MainActivity.this, "Connected to Twitter as " + username, Toast.LENGTH_LONG).show();
//startActivity(new Intent(MainActivity.this, TestPost.class));
}
@Override
public void onError(String value) {
registerCheck.setChecked(false);
Toast.makeText(MainActivity.this, "Twitter connection failed", Toast.LENGTH_LONG).show();
}
};
///////Y AHORA DENTRO DEL ONCLICK DEL CHECKBOX, LLAMAR A LA FUNCION
onTwitterClick();
Con esto debería funcionar, según se ejecuta el main, pulsamos sobre el checkbox y como resultado nos dará un dialog en el que se ha incrustado el webView, y un par de dialogs mas,además de haber personalizado la cabecera, ahí es donde tenemos que introducir nuestras credenciales.
Y si no hay problemas de conexión, este es el resultado :
Bien, lo bueno de que se manejen preferencias, es que ahora si nos salimos de la aplicación y volvemos a entrar, abrá que repetir todo el proceso de autentificación, aunque los datos personales de la cuenta ya están almacenados, entonces hay que optimizar eso, aprobechando el hilo del onCreate después de las instancias al botón y los checkbox, ponemos una condición :
//SI HAY CONEXION SE PULSA EL CHECKBOX
if (mTwitter.estasConectado()) {
registerCheck.setChecked(true);
String username = mTwitter.getUsername();
username= (username.equals("")) ? "Unknown" : username;
//Se actualiza el estado con el nombre
registerCheck.setText(" Twitter (" + username + ")");
registerCheck.setTextColor(Color.WHITE);
}else{
onTwitterClick();
}
Así, si ejecutas el proyecto otra vez, saltas el paso de las credenciales y se autentifica automáticamente
Sólo si están guardadas con anterioridad. Por supuesto como en el propio twitter, al quitar el check, te va a preguntar si quieres desconectar, que a efectos prácticos es como el cerrar sesión del twitter normal, se borran las preferencias y listo.
Como hemos tocado el código varias veces de la actividad principal, lo pongo entero para que no haya lugar a dudas :
public class MainActivity extends Activity {
private TwitterApp mTwitter;
private CheckBox mTwitterBtn;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//INICIAMOS VARIABLES
mTwitter = new TwitterApp(this, twitter_consumer_key,twitter_secret_key);
mTwitter.setListener(mTwLoginDialogListener);
//Checkbox para conectar A TWITTER
mTwitterBtn = (CheckBox) findViewById(R.id.twitterCheck);
mTwitterBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onTwitterClick();
}
});
//AÑADI LAS LINEAS A UNA FUNCIÓN
ConectarPorDefecto()
Button goBtn = (Button) findViewById(R.id.button1);
goBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, TestPost.class));
}
});
}
private void ConectarPorDefecto(){
//SI HAY CONEXION SE PULSA EL CHECKBOX
if (mTwitter.estasConectado()) {
registerCheck.setChecked(true);
String username = mTwitter.getUsername();
username= (username.equals("")) ? "Unknown" : username;
//Se actualiza el estado con el nombre
registerCheck.setText(" Twitter (" + username + ")");
registerCheck.setTextColor(Color.WHITE);
}else{
onTwitterClick();
}
}
private void onTwitterClick() {
//SI YA ESTAS CONECTADO A TWITTER
if (mTwitter.estasConectado()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
//MESAJE CON LA CONFIRMACION DE LA DESCONEXION
builder.setMessage("Delete current Twitter connection?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@SuppressLint("ResourceAsColor")
public void onClick(DialogInterface dialog, int id) {
mTwitter.resetAccessToken();
//ACTUALIZAMOS CHECKBOX
mTwitterBtn.setChecked(false);
mTwitterBtn.setText(" Not connected ");
mTwitterBtn.setTextColor(R.color.colorTweet);
}
})
//EN EL CASO DE QUE SE PULSE NO, VOLVEMOS A LA PRIMERA PANTALLA
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
mTwitterBtn.setChecked(true);
}
});
final AlertDialog alert = builder.create();
alert.show();
//SINO ESTAS CONECTADO MANDAMOS A AUTHORIZE, DONDE APARECE
//PARA ENVIAR LAS CREDENCIALES DE AUTENTIFICACION
} else {
mTwitterBtn.setChecked(false);
//Cargamos loading... mas credenciales de twitter
mTwitter.authorize();
}
}
private final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
@Override
public void onComplete(String value) {
String username = mTwitter.getUsername();
username = (username.equals("")) ? "No Name" : username;
mTwitterBtn.setText(" Conectado como (" + username + ")");
mTwitterBtn.setChecked(true);
mTwitterBtn.setTextColor(Color.WHITE);
Toast.makeText(MainActivity.this, "Connected to Twitter as " + username, Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, TestPost.class));
}
@Override
public void onError(String value) {
mTwitterBtn.setChecked(false);
Toast.makeText(MainActivity.this, "Twitter connection failed", Toast.LENGTH_LONG).show();
}
};
}
3. Validar nuestro Tweet a enviar
Vamos ya a lo que es, escribir el tweet. Tenemos que meter una etiqueta en el inputText para asegurarnos que si se quiere twittear, siempre se marque la etiqueta, y por otra parte en nuestro TextView, el que tiene la funcionalidad de contar los caracteres, para validar el tweet, ya que no puede estar a 0 o pasarse de 140 caracteres en total.
El conteo de los caracteres es regresivo, es decir, no empieza en 0, sino en 140 y se va restando el numero de caracteres que cuando sea inferior a 0, tomará un color rojo.
En nuestro onCreate, al final del todo :
Y en el onclick del botón azul de enviartweet :
tweet.addTextChangedListener(new TextWatcher() {
int caracteres=0;
@SuppressLint("ResourceAsColor") @Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
caracteres=140-(tweet.getText().length() );
Ncaracteres.setText(String.valueOf(caracteres));
if(caracteres < 0){
Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.RojoError));
}else{ Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.colorTwitter));
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
Añadimos en nuestra función instanciarElementos :
// YA METO TEXTO EN EL INPUTTEXT
tweet.setText(" #thebestandroide");
//APAREZCA EL NUMERO CARACTERES POR DEFECTO
Ncaracteres.setText(String.valueOf(140-(tweet.getText().length()) ) );
Y en el onclick del botón azul de enviartweet :
if(validarTweet(String.valueOf(tweet.getText()))){
Toast.makeText(MainActivity.this, "Hasta dentro!",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this, "Tweet incorrecto",Toast.LENGTH_SHORT).show();
}
Si quereis ver más claro el tema de contar caracteres de un EditText, podeis verlo en este antiguo
post.
4. Posteando un tweet
Ya sólo nos queda conectarnos y enviar el tweet, ya que aunque tengamos la session abierta, hace falta conectar con Twitter para enviar el Tweet. Está misión la lleva a cabo el método authorize() de la clase TwitterApp.
Ya que esta todo dispuesto, he cambiado
uno de los checkbox por un textview porque así es más sencillo, pongo la clase main entera para que no haya lugar a dudas :
public class MainActivity extends Activity {
//CLAVES
private static final String twitter_consumer_key = "tu_consumer_key";
private static final String twitter_secret_key = "tu__secret_key";
//Elementos
private CheckBox registerCheck;
private ListView lista;
private Button BotonEnviarTweet;
private EditText tweet;
private TextView Ncaracteres;
private TextView Conectado;
//VARIABLES
private TwitterApp mTwitter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//INSTANCIAMOS ELEMENTOS
instanciarElementos();
//INICIAMOS VARIABLES
mTwitter = new TwitterApp(this, twitter_consumer_key,twitter_secret_key);
mTwitter.setListener(mTwLoginDialogListener);
//BOTON PARA ENVIAR TWEETS
BotonEnviarTweet.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(validarTweet(String.valueOf(tweet.getText()))){
if (mTwitter.estasConectado()){
Twittear(String.valueOf(tweet.getText()));
}else{
mTwitter.authorize();
Conectado.setText(" Conectando...");
Toast.makeText(MainActivity.this, "Estamos conectando, por favor reenvie!",Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(MainActivity.this, "Tweet incorrecto",Toast.LENGTH_SHORT).show();
}
}
});
//CHECKBOX CONECTAR
registerCheck.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onTwitterClick();
}
});
tweet.addTextChangedListener(new TextWatcher() {
int caracteres=0;
@SuppressLint("ResourceAsColor")
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
caracteres=140-(tweet.getText().length() );
Ncaracteres.setText(String.valueOf(caracteres));
if(caracteres < 0){
Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.RojoError));
}else{
Ncaracteres.setTextColor(Ncaracteres.getContext().getResources().getColor(R.color.colorTwitter));
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
//CONECTAMOS POR DEFECTO
ConectarPorDefecto();
}
private boolean validarTweet(String tweet){
if(tweet.length()>140){
return false;
}else if(tweet.compareTo("")==0){
return false;
}else{
return true;
}
}
private void ConectarPorDefecto(){
//SI HAY CONEXION SE PULSA EL CHECKBOX
if (mTwitter.estasConectado()) {
registerCheck.setChecked(true);
String username = mTwitter.getUsername();
username= (username.equals("")) ? "Unknown" : username;
//Se actualiza el estado con el nombre
registerCheck.setText(" Twitter (" + username + ")");
}else{
onTwitterClick();
}
}
//FUNCION QUE HACE UN HILO PARA CONECTAR CON TWITTER Y POSTEAR EL TWEET
private void Twittear(final String review) {
new Thread() {
@Override
public void run() {
int what = 0;
try {
mTwitter.updateStatus(review);
} catch (Exception e) {
what = 1;
Log.e("Error Tweet NO Enviado!! excepcion"+e, "FAIL");
}
mHandler.sendMessage(mHandler.obtainMessage(what));
}
}.start();
}
//HANDLER QUE RECOGE EL MENSAJE
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String text = (msg.what == 0) ? "Posted to Twitter" : "Post to Twitter failed";
Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
}
};
//CONEXION A TWITTER
private void onTwitterClick() {
//SI YA ESTAS CONECTADO A TWITTER
if (mTwitter.estasConectado()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
//MESAJE CON LA CONFIRMACION DE LA DESCONEXION
builder.setMessage("Delete Twitter Session?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@SuppressLint("ResourceAsColor")
public void onClick(DialogInterface dialog, int id) {
mTwitter.resetAccessToken();
//ACTUALIZAMOS CHECKBOX
registerCheck.setChecked(false);
registerCheck.setText(" Not connected ");
registerCheck.setTextColor(R.color.colorTweet);
}
})
//EN EL CASO DE QUE SE PULSE NO, VOLVEMOS A LA PRIMERA PANTALLA
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
registerCheck.setChecked(true);
}
});
final AlertDialog alert = builder.create();
alert.show();
//SINO ESTAS CONECTADO MANDAMOS A AUTHORIZE, DONDE APARECE
//PARA ENVIAR LAS CREDENCIALES DE AUTENTIFICACION
} else {
registerCheck.setChecked(false);
//Cargamos loading... mas credenciales de twitter
mTwitter.authorize();
}
}
@SuppressLint("ResourceAsColor")
private final TwDialogListener mTwLoginDialogListener = new TwDialogListener() {
@Override
public void onComplete(String value) {
//YA CONECTADO PIDE EL NOMBRE A LA RESPUESTA HTTP
String username = mTwitter.getUsername();
username= (username.equals("")) ? "No Name" : username;
Conectado.setText(" "+username);
registerCheck.setText(" Conectado");
registerCheck.setChecked(true);
registerCheck.setTextColor(R.color.colorTweet);
Toast.makeText(MainActivity.this, "Connected to Twitter as " + username, Toast.LENGTH_LONG).show();
//startActivity(new Intent(MainActivity.this, TestPost.class));
}
@Override
public void onError(String value) {
registerCheck.setChecked(false);
Toast.makeText(MainActivity.this, "Twitter connection failed", Toast.LENGTH_LONG).show();
}
};
public void instanciarElementos(){
//Elementos
registerCheck = (CheckBox) findViewById(R.id.twitterCheckConnection);
lista = (ListView) findViewById(R.id.listViewTweets);
BotonEnviarTweet = (Button) findViewById(R.id.enviarTweet);
tweet = (EditText) findViewById(R.id.tweet);
Ncaracteres =(TextView) findViewById(R.id.contarCaracteresTwitter);
Conectado =(TextView) findViewById(R.id.conectado);
Conectado.setText(" No user");
// YA METO TEXTO EN EL INPUTTEXT
tweet.setText(" @BestAndroide");
//APAREZCA EL NUMERO CARACTERES POR DEFECTO
Ncaracteres.setText(String.valueOf(140-(tweet.getText().length()) ) );
}
}
Aquí vemos el resultado :
Para conectarte con las credenciales :
Para escribir un tweet :
Y si entramos de nuevo, no se nos demandará que ingresemos las credenciales si hemos dejado la session abierta, de lo contrario sí.
Podeis descargar el código fuente de thebestandroide con sólo compartir en facebook,twitter,linkedin o suscribirte a nuestro canal RSS más abajo.