Añadir view Activity android java

Blog >Lista Soluciones > Insertar View en Activity




Añadir View a activity

En esta ocasión añadiremos una vista en la que hemos guardado un recurso.xml y la insertaremos mediante código java en nuestra activity al pulsar sobre un botón, posteriormente haremos que con sólo tocar la pantalla, desaparezca. 
 
Como la idea es una pizarra donde puedan escribir ofertas, vamos a bajarnos esta fuente que se parece a la escritura con una tiza, y en nuestro proyecto, añadimos la carpeta sino la tenemos : assets/fonts.

Ahora nuestra fuente la insertamos en esa carpeta y añadimos esta imágen al proyecto, descargàndola y añadiendola a la carpeta res/drawable.





Bien, ahora esa imágen la vamos a usar creando un nuevo recurso.xml que quedaría de esta manera :


PIZARRA.XML

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:orientation="vertical"
     >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:background="@drawable/pizarra"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="35dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Oferta"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:textColor="@android:color/white"
                android:textSize="30sp" />

        </LinearLayout>

    </LinearLayout>

</RelativeLayout>

Como veis, vamos ajustando los layouts con márgenes para una mejor apariencia,y ya hemos echo uso de nuestro recurso con la imagen poniéndolo como background de un layout, vamos a ver como queda el main :

MAIN

@Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  //aqui se pone antes porque sino da error
  setContentView(R.layout.activity_main);
  context=this;
  instanciarElementos();
  altas();
  listado=listaTotal();
  layout = (ViewGroup) findViewById(R.id.layoutPrncipalMain); 
  
  
  
  sansation = Typeface.createFromAsset(getAssets(),"fonts/Sansation_Bold.ttf");
  
  
  
  bPruebas=(Button) findViewById(R.id.bofertaPrueba);
  bPruebas.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View v) { 
    seEstaMostrando=1;   
    addOferta();
   }
   
  });

 }

    private void addOferta()
    {
        LayoutInflater inflater = LayoutInflater.from(this);
        //RECOJEMOS ID DEL CONTENEDOR
        int id = R.layout.pizarra;
        //FUENTE Y TEXTO
        TextView Oferta;
     Typeface TIZA;
     
     TIZA = Typeface.createFromAsset(getAssets(),"fonts/Rudiment.ttf");
        RelativeLayout relativeLayout = (RelativeLayout) inflater.inflate(id, null, false);
        //AÑADIMOS VISTA
        layout.addView(relativeLayout);  
        
        
  Oferta=(TextView) findViewById(R.id.offfert);
  Oferta.setText("THEBESTANDROIDE.BLOGSPOT.COM, THEBESTANDROIDE.BLOGSPOT.COM, THEBESTANDROIDE.BLOGSPOT.COM, THEBESTANDROIDE.BLOGSPOT.COM, THEBESTANDROIDE.BLOGSPOT.COM");
  Oferta.setTypeface(TIZA);
         
    }



Ahora al pulsar el botón, esta vista aparecerá y ya de ahí no se moverá :



Bien ahora le vamos a añadir el gesto para que al tocar la pantalla se quite, consiguiendo un efecto de ventana de quita y pon.

ahora hacemos que la clase herede de
implements OnGesturePerformedListener

Para poder insertar estos métodos, que uno nos le imponen y otro le necesitamos, y ya está completado, sólo queda jugar con la variable seEstaMostrando para cuando queramos mostrarlo u ocultarlo :
 @Override
 public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
  
 }
 
    @Override
 public boolean onTouchEvent(MotionEvent event) {
  // TODO Auto-generated method stub
  if (seEstaMostrando==1){
  System.out.println("TOCO TOCO TOCOOOOOOO");
   VistaOferta.setVisibility(View.GONE);
   seEstaMostrando=0;
  }
  return super.onTouchEvent(event);
 }




Compartir Compartir Compartir Compartir



Aplicacion android con orientacion vetical (portrait) solo

Blog >Lista Soluciones > Orientación sólo vertical (Portrait)

Vamos a configurar nuestra aplicación android para que se ejecute sólo con orientación vertical o portrait.






Esto se hace de una forma muy sencilla, vamos a nuestro AndroidManifiest.xml y añadimos esta línea:


<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application>
        <activity android:name="mi.paquete.MiActivity"
                  android:screenOrientation="portrait" />
    </application>
</manifest>

Pero oJoOoOo !! También se puede hacer desde la clase java de la actividad, en el onCreate : 


setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);


Y ya está, esta función podemos implementarla también si queremos en alguna ocasión manejar algo en el cambio de orientación :



@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
 
    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}







Más info, en el sitio oficial aquí.



Compartir Compartir Compartir Compartir



Mi aplicación Android con Twitter : Escribir un tweet

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.




Compartir Compartir Compartir Compartir



Mi aplicación Android con Twitter : Feed de twitter

Blog >Comunicación con servidor > Feed de Tweets en Android





Continuamos con el post numero dos de la sección Mi Aplicación Android con Twiter , en este caso tenemos aquí un feed de twitt´s con la palabra que introduzcamos en nuestra aplicación.


Mi aplicación Android con twitter : 
Feed de una etiqueta.

Twitter es uno de esos servicios, con diferentes APIs para acceder a los tweets y los distintos apartados de su plataforma. Vamos a capturar la entrada del usuario y crear el URL para su uso en una solicitud HTTP a la URL de búsqueda de Twitter :



Antes de seguir, he de decir que me ha costado bastante sacar este código, no todo es mío, he de agradecer la aportación de varios colegas en Gilthub, que no tenía mucha fé en esta plataforma pero resulta super útil.

El tratamiento es complicadillo y se requiere tiempo para estudiar el código, sino se tienen conocimientos avanzados de Java, será imposible tratar el código de manera correcta.También hay que decir que antes de estar liado con esto,hay que saber si se tienen las claves de autentificación en Twitter, 
¿Cómo las conseguimos? 
Aquí.



Voy a comentar brevemente la función de la aplicación : 

Nosotros tenemos un EditText donde introduciremos la etiqueta que queremos buscar, y al darle al botón realizará las operaciones necesarias para poder conectarnos a Twitter con nuestras CUSTOM_KEY y SECRET_KEY, una vez autentificados, tendremos los privilegios necesarios para poder listar los tweets mediante un objeto JSON de una determinada etiqueta. 

Antes de nada hay que descargarse bastantes librerías, importarlas al proyecto y parsearlas al mismo mediante Java Build Path (botón derecho sobre el proyecto, propiedades). Estas librerías son las que necesitamos para usar JSON y otras para interactuar con el framework de Twitter. Destaco que estoy en la version Android 5.


Las he comprimido en un .rar y las podeis descargar desde aquí.

DESCARGAR LIBRERIAS PARA JSON DESDE AQUI  Y AQUI







También hay que dar permisos de Internet a la aplicación.


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



<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.tweetfeed.MainActivity" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/intro_txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Twitter search term"
            android:textSize="20sp"
            android:textStyle="italic" />

        <EditText
            android:id="@+id/search_edit"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:background="#ffff66"
            android:hint="Search..."
            android:inputType="text"
            android:padding="10dp" >

            <requestFocus />
        </EditText>

        <Button
            android:id="@+id/busqueda"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="5dp"
            android:onClick="searchTwitter"
            android:text="Buscar" />

        <ListView
            android:id="@+id/list"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </ListView>

    </LinearLayout>

</RelativeLayout>



Y de momento en el onCreate() hacemos referencia a los objetos como de costumbre :

 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  act = this;
  listalist = (ListView) findViewById(R.id.list);

      palabra = (EditText) findViewById(R.id.search_edit);
         buscar= (Button) findViewById(R.id.busqueda);
         buscar.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {

     TERMINO=palabra.getText().toString();
     LISTA = new ArrayList();
    }
         });
 }


Si ejecutamos el proyecto veremos que no ocurre nada, ya que ahora vamos a implementar una serie de clases necesarias para lograr nuestro objetivo : Un feed de tweets.

También agregamos otros recursos, como el item_twitter para la apariencia de cada tweet : En la carpeta drawable :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- color de fondo -->
    <solid android:color="#ffffff"/>
    <!-- curvatura esquinas  -->
    <corners android:radius="10dp"/>
    <!-- padding para separar entre elementos contenidos y el borde -->
    <padding android:left="8dp"
        android:right="8dp"
        android:top="4dp"
        android:bottom="8dp"/>
    <!-- borde -->
    <stroke
        android:width="3dp"
        android:color="@color/colorTwitter"/>
</shape>

Y en la carpeta layout, la fila que insertaremos con datos distintos :

<?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="wrap_content"
    android:background="@drawable/cuadrotwitter"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/contenedorTwitter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff" >

        <ImageView
            android:id="@+id/JSONAvatar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:src="@drawable/ic_launcher" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/JSONusertwitter"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="User"
                android:textColor="@color/colorTwitter" />

            <TextView
                android:id="@+id/JSONTweet"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="tweet"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="@color/colorTweet" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>


TwitterUser : Clase con parámetros identicos a los que nos dan, complementa a la siguiente clase Tweet, que toma también parámetros de twitter, lo que pasa que esta última se centra un poco más en parámetros del sistema, a diferencia con la anterior, que está definida para los parámetros de cada usuario.

public class TwitterUser {

 @SerializedName("screen_name")
 private String screenName;
 
 @SerializedName("name")
 private String name;
 
 @SerializedName("profile_image_url")
 private String profileImageUrl;

 public String getProfileImageUrl() {
  return profileImageUrl;
 }

 public String getScreenName() {
  return screenName;
 }

 public void setProfileImageUrl(String profileImageUrl) {
  this.profileImageUrl = profileImageUrl;
 }

 public void setScreenName(String screenName) {
  this.screenName = screenName;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}

public class Tweet {

 @SerializedName("created_at")
 private String DateCreated;

 @SerializedName("id")
 private String Id;

 @SerializedName("text")
 private String Text;

 @SerializedName("in_reply_to_status_id")
 private String InReplyToStatusId;

 @SerializedName("in_reply_to_user_id")
 private String InReplyToUserId;

 @SerializedName("in_reply_to_screen_name")
 private String InReplyToScreenName;

 @SerializedName("user")
 private TwitterUser User;

 public String getDateCreated() {
  return DateCreated;
 }
 
 public String getId() {
  return Id;
 }

 public String getInReplyToScreenName() {
  return InReplyToScreenName;
 }

 public String getInReplyToStatusId() {
  return InReplyToStatusId;
 }

 public String getInReplyToUserId() {
  return InReplyToUserId;
 }

 public String getText() {
  return Text;
 }

 public void setDateCreated(String dateCreated) {
  DateCreated = dateCreated;
 }

 public void setId(String id) {
  Id = id;
 }

 public void setInReplyToScreenName(String inReplyToScreenName) {
  InReplyToScreenName = inReplyToScreenName;
 }
 
 public void setInReplyToStatusId(String inReplyToStatusId) {
  InReplyToStatusId = inReplyToStatusId;
 }
 
 public void setInReplyToUserId(String inReplyToUserId) {
  InReplyToUserId = inReplyToUserId;
 }
 
 public void setText(String text) {
  Text = text;
 }

 public void setUser(TwitterUser user) {
  User = user;
 }

 public TwitterUser getUser() {
  return User;
 }

 @Override
 public String  toString(){
  return getText();
 }
}


Clase Twitter : Esta clase nos sirve de apoyo para recoger los valores que nos va a devolver el objeto JSON

public class Twitter extends ArrayList {
 private static final long serialVersionUID = 1L;
}


Clase Authenticated : Es la que nos va guardar las variables de conexión necesarias para twitter :

public class Authenticated {
 String token_type;
 String access_token;
}


Vamos ahora con el tema "complicadillo"; A partir de la versión 3 de Android, las operaciones como recoger datos desde internet, se consideran operaciones costosas, entonces Android dió por echo que necesitábamos hacer uso de otro hilo, para que la aplicación no se quedase colgada. 

He echo este programa con 3 formas de hilos, uno para autentificarnos en Twitter y parsear mediante JSON los datos, otro para insertarlos en el ListView y otro en el propio adapter para que mediante la URL del avatar de twitter, se descarguen las fotos y se muestren
Se puede hacer sin el hilo para insertar los datos en el adapter, pero lo he puesto para ser más técnico :






//FUNCION QUE ENCAPSULA TODOS LOS DATOS Y SE LLAMA EN EL ONCLICK DEL BOTÓN QUE ANTERIORMENTE HEMOS PUESTO EN EL onCreate()
 public void downloadTweets() {
  ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
  
  if (networkInfo != null && networkInfo.isConnected()) {
   new DownloadTwitterTask(act).execute(TERMINO);
  } else {
   Log.v(LOG_TAG, "No network connection available.");
  }
 }

//HILO PARA AGREGAR LOS ITEMS AL ADAPTADOR
private class CargarListViewTask extends AsyncTask{
    Activity a;
 
 public CargarListViewTask(Activity a) {
  // TODO Auto-generated constructor stub
  this.a=a;
 }
 protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
    }
 @Override
 protected BaseAdapter doInBackground(Void... params) {
  TweetItemAdapter adaptador = new TweetItemAdapter(LISTA,a);
  return adaptador;
 }
 @Override
 protected void onPostExecute(BaseAdapter adaptador) {
  super.onPostExecute(adaptador);
  listalist.setAdapter(adaptador);
        //pDialog.dismiss();
 }
 
 
}
 //Usamos ASINCTASK PARA OBTENER LOS TWETTS
 private class DownloadTwitterTask extends AsyncTask {
  final static String CONSUMER_KEY = "AQUI TU CONSUMER_KEY";
  final static String CONSUMER_SECRET = "AQUI TU CONSUMER_SECRET";

  final static String TwitterTokenURL = "https://api.twitter.com/oauth2/token";
  final static String TwitterStreamURL = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=";
  Activity activity;
  public DownloadTwitterTask(Activity actividad) {
   this.activity=actividad;
  }

  @Override
  protected String doInBackground(String... screenNames) {
   String result = null;
   if (screenNames.length > 0) {
    result = getTwitterStream(screenNames[0]);
   }
   return result;
  }
  // AQUI ES DONDE CONVERTIMOS LOS DATOS DEL JSON EN ARRAYLIST
  @Override
  protected void onPostExecute(String result) {
   Twitter twits = jsonToTwitter(result);
   
   for (Tweet tweet : twits) {
    Log.i("DATOS", tweet.getText());
    Tweet NEWtWitt=tweet;
    //INSERTAMOS EN LISTA
    LISTA.add(NEWtWitt);
   }
   System.out.println("LISTA CONTENIDO, numero tweets : "+LISTA.size());
   new CargarListViewTask(activity).execute();
  }

  // FUNCION DE APOYO QUE CONVIERTE EL STRING ENTERO POR REGISTRO EN DATOS DE UN ARRAYLIST
  private Twitter jsonToTwitter(String result) {
   Twitter twits = null;
   if (result != null && result.length() > 0) {
    try {
     Gson gson = new Gson();
     twits = gson.fromJson(result, Twitter.class);
    } catch (IllegalStateException ex) {
     // just eat the exception
    }
   }
   return twits;
  }

  // FUNCION DE APOYO QUE CONVIERTE LA AUTENTIFICACION JSON EN AUTENTIFICACION TIPO AUTHENTICATED
  private Authenticated jsonToAuthenticated(String rawAuthorization) {
   Authenticated auth = null;
   if (rawAuthorization != null && rawAuthorization.length() > 0) {
    try {
     Gson gson = new Gson();
     auth = gson.fromJson(rawAuthorization, Authenticated.class);
    } catch (IllegalStateException ex) {
     // just eat the exception
    }
   }
   return auth;
  }
  //FUNCION DE APOYO QUE HACE UNA PETICION HTTP PARA QUE PUEDA LEER JSON
  private String getResponseBody(HttpRequestBase request) {
   StringBuilder sb = new StringBuilder();
   try {
    DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams());
    HttpResponse response = httpClient.execute(request);
    int statusCode = response.getStatusLine().getStatusCode();
    String reason = response.getStatusLine().getReasonPhrase();

    if (statusCode == 200) {

     HttpEntity entity = response.getEntity();
     InputStream inputStream = entity.getContent();

     BufferedReader bReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
     String line = null;
     while ((line = bReader.readLine()) != null) {
      sb.append(line);
     }
    } else {
     sb.append(reason);
    }
   } catch (UnsupportedEncodingException ex) {
   } catch (ClientProtocolException ex1) {
   } catch (IOException ex2) {
   }
   return sb.toString();
  }
 //FUNCION DE APOYO PARA REALIZAR LA PETICION POST CON SU RESPECTIVA AUTENTIFICACION Y DESPUÉS LA GET PARA 
 //OBTENER LOS DATOS EN JSON
  private String getTwitterStream(String screenName) {
   String results = null;

   // CONECTAMOS CON LAS CLAVES
   try {
    String urlApiKey = URLEncoder.encode(CONSUMER_KEY, "UTF-8");
    String urlApiSecret = URLEncoder.encode(CONSUMER_SECRET, "UTF-8");
    // COMBINAMOS LAS CLAVES PARA SU USO
    String combined = urlApiKey + ":" + urlApiSecret;
    // Base64 encode the string
    String base64Encoded = Base64.encodeToString(combined.getBytes(), Base64.NO_WRAP);
    //OBTENEMOS EL OBJETO token
    HttpPost httpPost = new HttpPost(TwitterTokenURL);
    httpPost.setHeader("Authorization", "Basic " + base64Encoded);
    httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
    httpPost.setEntity(new StringEntity("grant_type=client_credentials"));
    String rawAuthorization = getResponseBody(httpPost);
    Authenticated auth = jsonToAuthenticated(rawAuthorization);
    // Applications should verify that the value associated with the
    // token_type key of the returned object is bearer
    if (auth != null && auth.token_type.equals("bearer")) {
     // NOS AUTENTIFICAMOS Y HACEMOS LA PETICION GET
     HttpGet httpGet = new HttpGet(TwitterStreamURL + screenName);
     // CONSTRUIMOS UN HTTP NORMAL Y LE INSERTAMOS LA AUTORIZACION REQUERIDA POR TWITTER
     httpGet.setHeader("Authorization", "Bearer " + auth.access_token);
     httpGet.setHeader("Content-Type", "application/json");
     // update the results with the body of the response
     results = getResponseBody(httpGet);
    }
   } catch (UnsupportedEncodingException ex) {
   } catch (IllegalStateException ex1) {
   }
   return results;
  }
 }
}


Ya sólo nos queda el adapter, que es un adapter sencillo, sólo que hemos extendido un hilo para que como anteriormente he comentado cargar las imágenes a través de una URL :

public class TweetItemAdapter extends BaseAdapter {
 
 private ArrayList tweets;
 private Activity a;

 public TweetItemAdapter(ArrayList tweets,Activity actividad) {
  super();
  this.tweets = tweets;
  this.a=actividad;
 }

 @SuppressLint("NewApi") @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  
  View v = convertView;
  if (v == null) {
   LayoutInflater vi = (LayoutInflater)a.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   v = vi.inflate(R.layout.tweet_item, null);
  }

  Tweet tweet = (Tweet) tweets.get(position);
   
   if (tweet != null) {
    TextView user = (TextView) v.findViewById(R.id.JSONusertwitter);
    TextView mensaje = (TextView) v.findViewById(R.id.JSONTweet);
    ImageView image = (ImageView) v.findViewById(R.id.JSONAvatar);
    
    if (user != null) {
     user.setText(tweet.getUser().getName());
    }
    if(mensaje != null) {
     mensaje.setText(tweet.getText().toString());
    }
    if(image != null) {
     new DownloadImageTask(image).execute(tweet.getUser().getProfileImageUrl());

     
    }
   }

   return v;
 }

 @Override
 public int getCount() {
  // TODO Auto-generated method stub
  return tweets.size();
 }

 @Override
 public Object getItem(int position) {
  // TODO Auto-generated method stub
  return position;
 }

 @Override
 public long getItemId(int position) {
  // TODO Auto-generated method stub
  return 0;
 }
 
class DownloadImageTask extends AsyncTask {
  ImageView bmImage;

  public DownloadImageTask(ImageView bmImage) {
   this.bmImage = bmImage;
  }

  @Override
  protected Bitmap doInBackground(String... urls) {
   String urldisplay = urls[0];
   Bitmap mIcon11 = null;
   try {
    InputStream in = new java.net.URL(urldisplay).openStream();
    mIcon11 = BitmapFactory.decodeStream(in);
   } catch (Exception e) {
    Log.e("Error", e.getMessage());
    e.printStackTrace();
   }
   return mIcon11;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   bmImage.setImageBitmap(result);
  }
 }
}


Y vamos con ello, el resultado lo podreis ver aquí :








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.

NOTA : Hay que pasar por el primer post para conseguir las claves.




Compartir Compartir Compartir Compartir