Android ofrece su propia galería de imágenes por defecto. En este post se va a mostrar una alternativa a la imagen inferior. Ésta, como podemos observar, se compone de un visor de las imágenes y debajo la imagen ampliada. Un ejemplo podría ser imagen siguiente:
Si este método no os gusta, podéis usar el que se presenta en este post. Si queréis que mediante un "gesto en pantalla", cómo podría ser arrastrar el dedo por ella, pueda cambiar la imagen añadid el siguiente código a vuestro proyecto. A continuación un completo ejemplo:
Contiene la image que se cambiara en la vista.
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/vista_fotos"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical" >
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:scaleType="centerInside" />
</RelativeLayout>
Contiene el código que detecta el movimiento del dedo del usuario. Y posteriormente, ejecuta el cambio de imagen. Esta tiene que implementar un "OnClickListener" porqué así detectamos el contacto del usuario con la vista. En otro caso, no se activaría el "gestureListener".
src/SwypeImagesActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class SwypeImagesActivity extends Activity implements OnClickListener {
// Custom settings
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 30;
private GestureDetector mGestureDetector;
private View.OnTouchListener mGestureListener;
private ImageView mImageView;
private Integer[] mImagesList = { R.drawable.image1, R.drawable.image2,
R.drawable.image3, R.drawable.image4};
private int mPhoto;
private RelativeLayout mView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPhoto = 0;
setContentView(R.layout.main);
mView = (RelativeLayout) findViewById(R.id.vista_fotos);
mImageView = (ImageView) findViewById(R.id.image);
// initialize with the first image
mImageView.setImageResource(mImagesList[mPhoto]);
// Gesture detection
mGestureDetector = new GestureDetector(new MyGestureDetector());
mGestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
};
// prevent the view to be touched
mView.setOnClickListener(this);
mView.setOnTouchListener(mGestureListener);
}
public class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
mPhoto = (mPhoto + 1) % mImagesList.length;
mImageView.setImageResource(mImagesList[mPhoto]);
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
mPhoto = (mPhoto - 1) % mImagesList.length;
if (mPhoto < 0) {
mPhoto = 0;
}
mImageView.setImageResource(mImagesList[mPhoto]);
}
} catch (Exception e) {
Log.e("SwypeImagesActivity", "error on gesture detector");
}
return false;
}
}
@Override
public void onClick(View v) {
// Necessary because the view must have on touch listener
}
}
It works!
Roger Sala,
sábado, 23 de junio de 2012
Personalizar CheckBox
Dependiendo del tipo de aplicaciones que estamos desarrollando podems tener unas necesidades u otras. Una de ellas, y que vamos a ver en este post puede ser: customizar los checkbox que Android nos ofrece. A continuació presento el código para realizarlo:
Esta clase contiene los textos que se van a mostrar en el checkbox.
res/xml/filters_checkbox.xml
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text1"
android:background="#FFFFFF"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:checkMark="@drawable/style_checkboxes"
android:enabled="true"
android:checked="true"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FF0000" />
Esta clase es al vista principal. Contiene la lista de checkboxes.
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listview_filters_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:cacheColorHint="#000000"
android:focusable="false"
android:focusableInTouchMode="false"
android:scrollbars="none" >
</ListView>
</RelativeLayout>
Esta clase une a todas la anteriores. Es donde se muestran los datos.
src/CustomCheckBoxes.java
Roger Sala,
Esta clase contiene los textos que se van a mostrar en el checkbox.
res/xml/filters_checkbox.xml
<filterCheckBox>
<item
description=""
title="CheckBox1">
<item
description=""
title="CheckBox2">
<item
description=""
title="CheckBox3">
<item
description=""
title="CheckBox4">
</item>
</item>
</item>
</item>
</filterCheckBox>
<item
description=""
title="CheckBox1">
<item
description=""
title="CheckBox2">
<item
description=""
title="CheckBox3">
<item
description=""
title="CheckBox4">
</item>
</item>
</item>
</item>
</filterCheckBox>
Esta clase contiene el estilo de los checkboxes. Para ello modificamos la imagen de cuando esta seleccionado o no. (El drawable que se añade son imagenes que estan en su res/drawable/).
res/drawable/style_checkboxes.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/checkbox_checked" android:state_checked="true"/>
<item android:drawable="@drawable/checkbox_unchecked" android:state_checked="false"/>
</selector>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/checkbox_checked" android:state_checked="true"/>
<item android:drawable="@drawable/checkbox_unchecked" android:state_checked="false"/>
</selector>
Esta clase contiene el estilo de cada checkbox. Es aqui donde le aplicamos el estilo anterior.
res/layout/filters_multiple_choice_list.xml<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text1"
android:background="#FFFFFF"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:checkMark="@drawable/style_checkboxes"
android:enabled="true"
android:checked="true"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FF0000" />
Esta clase es al vista principal. Contiene la lista de checkboxes.
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listview_filters_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:cacheColorHint="#000000"
android:focusable="false"
android:focusableInTouchMode="false"
android:scrollbars="none" >
</ListView>
</RelativeLayout>
Esta clase une a todas la anteriores. Es donde se muestran los datos.
src/CustomCheckBoxes.java
import java.io.IOException;
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class CustomCheckBoxes extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// declare variables
ListView checkBoxListView;
String[] checkBoxNameList;
ArrayList<String> checkBoxList;
// get data
checkBoxListView = (ListView) findViewById(R.id.listview_filters_checkbox);
checkBoxList = PrepareListFromXml();
checkBoxNameList = (String[]) checkBoxList.toArray(new String[0]);
// set data to list
checkBoxListView.setAdapter(new ArrayAdapter<String>(
CustomCheckBoxes.this, R.layout.filters_multiple_choice_list,
checkBoxNameList));
checkBoxListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
private ArrayList<String> PrepareListFromXml() {
ArrayList<String> preferenceItems = new ArrayList<String>();
XmlResourceParser preferencelistXml;
preferencelistXml = getResources().getXml(R.xml.filters_checkbox);
int eventType = -1;
while (eventType != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) {
String strNode = preferencelistXml.getName();
if (strNode.equals("item")) {
preferenceItems.add(preferencelistXml.getAttributeValue(
null, "title"));
}
}
try {
eventType = preferencelistXml.next();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return preferenceItems;
}
}
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class CustomCheckBoxes extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// declare variables
ListView checkBoxListView;
String[] checkBoxNameList;
ArrayList<String> checkBoxList;
// get data
checkBoxListView = (ListView) findViewById(R.id.listview_filters_checkbox);
checkBoxList = PrepareListFromXml();
checkBoxNameList = (String[]) checkBoxList.toArray(new String[0]);
// set data to list
checkBoxListView.setAdapter(new ArrayAdapter<String>(
CustomCheckBoxes.this, R.layout.filters_multiple_choice_list,
checkBoxNameList));
checkBoxListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
private ArrayList<String> PrepareListFromXml() {
ArrayList<String> preferenceItems = new ArrayList<String>();
XmlResourceParser preferencelistXml;
preferencelistXml = getResources().getXml(R.xml.filters_checkbox);
int eventType = -1;
while (eventType != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) {
String strNode = preferencelistXml.getName();
if (strNode.equals("item")) {
preferenceItems.add(preferencelistXml.getAttributeValue(
null, "title"));
}
}
try {
eventType = preferencelistXml.next();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return preferenceItems;
}
}
Si ejecutamos el proyecto se nos mostraría la siguiente imagen:
It works!
sábado, 16 de junio de 2012
Realizar una captura de pantalla
En este post vamos a explicar una forma fácil y rápida de añadir esta
funcionalidad a nuestra aplicación. En el código que se muestre se
realiza la captura de toda la pantalla. No obstante, si se desea se
puede realizar de una vista en concreto ya sea un layout contenido por
el layout general de la vista, una imageView, TableView etc...cualquier
elemento del xml (layout/xml). El código es el siguiente:
AndroidManifest.xml (Añadir el siguiente permiso)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_to_capture"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/my_image_capture"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/ic_launcher" />
<Button
android:id="@+id/button_screen_capture"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/my_image_capture"
android:text="capture Screen" />
</RelativeLayout>
src/ScreenCaptureActivity.java
public class ScreenCaptureActivity extends Activity {
private String SCREEN_CAPTURE_PATH = Environment
.getExternalStorageDirectory() + File.separator + "ScreenCaptureFolder";
private RelativeLayout layoutToCapture;
private Button buttonScreenCapture;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
buttonScreenCapture = (Button) findViewById(R.id.button_screen_capture);
layoutToCapture = (RelativeLayout) findViewById(R.id.layout_to_capture);
buttonScreenCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buttonScreenCapture.setVisibility(View.GONE);
captureScreen();
buttonScreenCapture.setVisibility(View.VISIBLE);
}
});
}
private void captureScreen() {
layoutToCapture.setDrawingCacheEnabled(true);
layoutToCapture.buildDrawingCache();
Bitmap croppedBitmap = Bitmap.createBitmap(layoutToCapture
.getDrawingCache());
savePhotoToSDCard(croppedBitmap, false);
layoutToCapture.setDrawingCacheEnabled(false);
}
protected boolean savePhotoToSDCard(Bitmap bitmapToSave, boolean needNumFoto) {
try {
File directory;
if (isSDCARDMounted()) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmapToSave.compress(Bitmap.CompressFormat.PNG, 90, bytes);
directory = new File(SCREEN_CAPTURE_PATH);
directory.mkdirs();
directory.createNewFile();
FileOutputStream fo = null;
fo = new FileOutputStream(directory + "myScreenCapture.png");
fo.write(bytes.toByteArray());
updateGallery();
Toast.makeText(getApplicationContext(), "Photo saved ok",
Toast.LENGTH_LONG).show();
return true;
} else {
Toast.makeText(getApplicationContext(), "no SDCARD found",
Toast.LENGTH_LONG).show();
return false;
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "error processing photo",
Toast.LENGTH_LONG).show();
return false;
}
}
private boolean isSDCARDMounted() {
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED))
return true;
return false;
}
private void updateGallery() {
sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}
}
It works!
Roger Sala,
AndroidManifest.xml (Añadir el siguiente permiso)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_to_capture"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/my_image_capture"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/ic_launcher" />
<Button
android:id="@+id/button_screen_capture"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/my_image_capture"
android:text="capture Screen" />
</RelativeLayout>
src/ScreenCaptureActivity.java
public class ScreenCaptureActivity extends Activity {
private String SCREEN_CAPTURE_PATH = Environment
.getExternalStorageDirectory() + File.separator + "ScreenCaptureFolder";
private RelativeLayout layoutToCapture;
private Button buttonScreenCapture;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
buttonScreenCapture = (Button) findViewById(R.id.button_screen_capture);
layoutToCapture = (RelativeLayout) findViewById(R.id.layout_to_capture);
buttonScreenCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buttonScreenCapture.setVisibility(View.GONE);
captureScreen();
buttonScreenCapture.setVisibility(View.VISIBLE);
}
});
}
private void captureScreen() {
layoutToCapture.setDrawingCacheEnabled(true);
layoutToCapture.buildDrawingCache();
Bitmap croppedBitmap = Bitmap.createBitmap(layoutToCapture
.getDrawingCache());
savePhotoToSDCard(croppedBitmap, false);
layoutToCapture.setDrawingCacheEnabled(false);
}
protected boolean savePhotoToSDCard(Bitmap bitmapToSave, boolean needNumFoto) {
try {
File directory;
if (isSDCARDMounted()) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmapToSave.compress(Bitmap.CompressFormat.PNG, 90, bytes);
directory = new File(SCREEN_CAPTURE_PATH);
directory.mkdirs();
directory.createNewFile();
FileOutputStream fo = null;
fo = new FileOutputStream(directory + "myScreenCapture.png");
fo.write(bytes.toByteArray());
updateGallery();
Toast.makeText(getApplicationContext(), "Photo saved ok",
Toast.LENGTH_LONG).show();
return true;
} else {
Toast.makeText(getApplicationContext(), "no SDCARD found",
Toast.LENGTH_LONG).show();
return false;
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "error processing photo",
Toast.LENGTH_LONG).show();
return false;
}
}
private boolean isSDCARDMounted() {
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED))
return true;
return false;
}
private void updateGallery() {
sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}
}
It works!
Roger Sala,
Refrescar la galería de imágenes
Si estás realizando una aplicación que guarda imágenes en la galería y quieres que el usuario al acceder a ella vea las imágenes sin necesidad de apagar/sincronizar de nuevo el teléfono, ésta es la función que estás buscando:
It works!
Roger Sala,
private void updateGallery() {
sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
It works!
Roger Sala,
Comprobar si la targeta SD está disponible
Algunas aplicaciones es necesario guardar datos en la tarjeta SD. Nunca se puede suponer que estará montada, aunque en la mayoría de las veces es así. Para ello antes de escribir en la SD hay que comprobar que es posible. Primero de todo añadimos los permisos necesarios en nuestro AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Luego podemos usar la siguiente función:
It works!
Roger Sala,
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Luego podemos usar la siguiente función:
private boolean isSDCARDMounted() {
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED))
return true;
return false;
}String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED))
return true;
return false;
It works!
Roger Sala,
Personaliza tus listas (ListView)
En la mayoría de las aplicaciones se requiere de crear listas personalizadas. Android ofrece diferentes layouts que podemos usar, pero cuando estos no son suficientes para nuestro gusto tenemos que implementar nuestro propio layout y BaseAdapter. En este post vamos a ver un ejemplo de ello:
Contiene la lista que se muestra al usuario. Vista principal de la Activity.
res/layout/main.xml
Contiene el formato que tendrá cada elemento de la lista. Usado la clase CustomAdapter.
res/layout/custom_list.xml
Esta clase sirve para rellenar los datos de cada elemento de la lista.
src/CustomAdapter.java
public class CustomAdapter extends BaseAdapter {
private Activity mActivityAct;
private LayoutInflater mInflater;
private ArrayList<Notice> mLItems;
public CustomAdapter(Activity a, ArrayList<Notice> it) {
mActivityAct = a;
mLItems = it;
mInflater = (LayoutInflater) mActivityAct
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public static class VistaH {
public TextView date;
public TextView title;
public TextView description;
}
@Override
public int getCount() {
return mLItems.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
VistaH vh = null;
if (vi == null) {
vi = mInflater.inflate(R.layout.custom_list, null);
vh = new VistaH();
vh.date = (TextView) vi.findViewById(R.id.textView_date);
vh.title = (TextView) vi.findViewById(R.id.textView_title);
vh.description = (TextView) vi
.findViewById(R.id.textView_description);
vi.setTag(vh);
}
vh = (VistaH) vi.getTag();
Notice notice = mLItems.get(position);
vh.date.setText(notice.getDate());
vh.title.setText(notice.getTitle());
vh.description.setText(notice.getDescription());
return vi;
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
if (observer != null) {
super.unregisterDataSetObserver(observer);
}
}
}
Vista principal. Contiene la lista. Modifica el adapter del listView por el CustomAdapter. Le pasamos el contexto y los datos (en este caso Notice (elemento del modelo)).
res/MyActivity.java
public class MyActivity extends Activity {
private ListView mListView;
private ArrayList<Notice> mList = new ArrayList<Notice>();
private Activity mActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mListView = (ListView) findViewById(R.id.listView);
mActivity = this;
getDataFromWebService();
CustomAdapter actualitatAdapter = new CustomAdapter(this, mList);
mListView.setAdapter(actualitatAdapter);
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> av, View view, int index,
long arg3) {
Toast.makeText(mActivity,
"My title is: " + mList.get(index).getTitle(),
Toast.LENGTH_LONG).show();
}
});
}
private void getDataFromWebService() {
// p.e: get Notices from rss
Notice n = new Notice("16/06/2012", "Notice 1",
"This is the description from notice 1");
mList.add(n);
n = new Notice("14/06/2012", "Notice 2",
"This is the description from notice 2");
mList.add(n);
n = new Notice("13/06/2012", "Notice 3",
"This is the description from notice 3");
mList.add(n);
n = new Notice("13/06/2012", "Notice 4",
"This is the description from notice 4");
mList.add(n);
n = new Notice("12/06/2012", "Notice 5",
"This is the description from notice 5");
mList.add(n);
n = new Notice("11/06/2012", "Notice 6",
"This is the description from notice 6");
mList.add(n);
n = new Notice("09/06/2012", "Notice 7",
"This is the description from notice 7");
mList.add(n);
n = new Notice("09/06/2012", "Notice 8",
"This is the description from notice 8");
mList.add(n);
n = new Notice("03/06/2012", "Notice 9",
"This is the description from notice 9");
mList.add(n);
}
}
Elemento del modelo. Contiene los atributos que se muestran en la lista.
res/Notice.java
public Notice(String date, String title, String description) {
this.date = date;
this.title = title;
this.description = description;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Si ejecutamos el proyecto se nos mostraría la siguiente imagen:
It works!
Roger Sala,
Contiene la lista que se muestra al usuario. Vista principal de la Activity.
res/layout/main.xml
<?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="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Contiene el formato que tendrá cada elemento de la lista. Usado la clase CustomAdapter.
res/layout/custom_list.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/linearLayout_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="10dip"
android:orientation="horizontal"
android:paddingTop="7dip" >
<TextView
android:id="@+id/textView_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TextView>
</LinearLayout>
<TextView
android:id="@+id/textView_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/linearLayout_1"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:textSize="15sp"
android:textStyle="bold" >
</TextView>
<TextView
android:id="@+id/textView_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView_title"
android:layout_marginLeft="12dip"
android:layout_marginTop="5dip"
android:textSize="12sp"
android:textStyle="italic" >
</TextView>
</RelativeLayout>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<LinearLayout
android:id="@+id/linearLayout_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="10dip"
android:orientation="horizontal"
android:paddingTop="7dip" >
<TextView
android:id="@+id/textView_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TextView>
</LinearLayout>
<TextView
android:id="@+id/textView_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/linearLayout_1"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:textSize="15sp"
android:textStyle="bold" >
</TextView>
<TextView
android:id="@+id/textView_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView_title"
android:layout_marginLeft="12dip"
android:layout_marginTop="5dip"
android:textSize="12sp"
android:textStyle="italic" >
</TextView>
</RelativeLayout>
Esta clase sirve para rellenar los datos de cada elemento de la lista.
src/CustomAdapter.java
public class CustomAdapter extends BaseAdapter {
private Activity mActivityAct;
private LayoutInflater mInflater;
private ArrayList<Notice> mLItems;
public CustomAdapter(Activity a, ArrayList<Notice> it) {
mActivityAct = a;
mLItems = it;
mInflater = (LayoutInflater) mActivityAct
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public static class VistaH {
public TextView date;
public TextView title;
public TextView description;
}
@Override
public int getCount() {
return mLItems.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
VistaH vh = null;
if (vi == null) {
vi = mInflater.inflate(R.layout.custom_list, null);
vh = new VistaH();
vh.date = (TextView) vi.findViewById(R.id.textView_date);
vh.title = (TextView) vi.findViewById(R.id.textView_title);
vh.description = (TextView) vi
.findViewById(R.id.textView_description);
vi.setTag(vh);
}
vh = (VistaH) vi.getTag();
Notice notice = mLItems.get(position);
vh.date.setText(notice.getDate());
vh.title.setText(notice.getTitle());
vh.description.setText(notice.getDescription());
return vi;
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
if (observer != null) {
super.unregisterDataSetObserver(observer);
}
}
}
Vista principal. Contiene la lista. Modifica el adapter del listView por el CustomAdapter. Le pasamos el contexto y los datos (en este caso Notice (elemento del modelo)).
res/MyActivity.java
public class MyActivity extends Activity {
private ListView mListView;
private ArrayList<Notice> mList = new ArrayList<Notice>();
private Activity mActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mListView = (ListView) findViewById(R.id.listView);
mActivity = this;
getDataFromWebService();
CustomAdapter actualitatAdapter = new CustomAdapter(this, mList);
mListView.setAdapter(actualitatAdapter);
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> av, View view, int index,
long arg3) {
Toast.makeText(mActivity,
"My title is: " + mList.get(index).getTitle(),
Toast.LENGTH_LONG).show();
}
});
}
private void getDataFromWebService() {
// p.e: get Notices from rss
Notice n = new Notice("16/06/2012", "Notice 1",
"This is the description from notice 1");
mList.add(n);
n = new Notice("14/06/2012", "Notice 2",
"This is the description from notice 2");
mList.add(n);
n = new Notice("13/06/2012", "Notice 3",
"This is the description from notice 3");
mList.add(n);
n = new Notice("13/06/2012", "Notice 4",
"This is the description from notice 4");
mList.add(n);
n = new Notice("12/06/2012", "Notice 5",
"This is the description from notice 5");
mList.add(n);
n = new Notice("11/06/2012", "Notice 6",
"This is the description from notice 6");
mList.add(n);
n = new Notice("09/06/2012", "Notice 7",
"This is the description from notice 7");
mList.add(n);
n = new Notice("09/06/2012", "Notice 8",
"This is the description from notice 8");
mList.add(n);
n = new Notice("03/06/2012", "Notice 9",
"This is the description from notice 9");
mList.add(n);
}
}
Elemento del modelo. Contiene los atributos que se muestran en la lista.
res/Notice.java
public class Notice {
private String date;
private String title;
private String description;
private String date;
private String title;
private String description;
public Notice(String date, String title, String description) {
this.date = date;
this.title = title;
this.description = description;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Si ejecutamos el proyecto se nos mostraría la siguiente imagen:
It works!
Roger Sala,
martes, 12 de junio de 2012
Galería de Imágenes
En algunas de mis apps (no publicadas en el market todavía) he tenido que obtener todas las imágenes que hay guardas en la galería del dispositivo. Así que en este post les voy a compartir el código que he usado para ello.
private void getImagesFromGallery() {
// propiedades que queremos hacer la query
String[] projection = new String[] { MediaStore.Images.Media._ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.DATA };
//Donde saco la info
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
// Obtenemos la info
Cursor cur = managedQuery(images, projection, // Which columns to return
"",
null,
""
);
if (cur.moveToFirst()) {
String bucket;
String path;
int bucketColumn = cur
.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
int dataColumn = cur.getColumnIndex(MediaStore.Images.Media.DATA);
// propiedades que queremos hacer la query
String[] projection = new String[] { MediaStore.Images.Media._ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.DATA };
//Donde saco la info
Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
// Obtenemos la info
Cursor cur = managedQuery(images, projection, // Which columns to return
"",
null,
""
);
if (cur.moveToFirst()) {
String bucket;
String path;
int bucketColumn = cur
.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME);
int dataColumn = cur.getColumnIndex(MediaStore.Images.Media.DATA);
do {
bucket = cur.getString(bucketColumn); //nombre de la carpeta donde esta la img
path = cur.getString(dataColumn); // path de la imagen para luego mostrarla
Log.i("imageInfo", "bucket=" + bucket + " path=" +path);
} while (cur.moveToNext());
}
}
bucket = cur.getString(bucketColumn); //nombre de la carpeta donde esta la img
path = cur.getString(dataColumn); // path de la imagen para luego mostrarla
Log.i("imageInfo", "bucket=" + bucket + " path=" +path);
} while (cur.moveToNext());
}
}
Con esta función ya pueden obtener las imágenes. Para decodificarla pueden usar la función que esta disponible en el post de Evitando OOM.
It works!
Roger Sala,
Sensores - Acelerómetro
Algunos dispositivos Android disponen de varios sensores que cómo developers podemos sacar provecho. En este post nos vamos a centrar en el Acelerómetro. Este nos permite detectar con gran sensibilidad los movimientos de desplazamiento y giro que se aplican en el teléfono. A partir, de esta definición podemos empezar a pensar en distintas aplicaciones que podríamos desarrollar.
A continuación les dejo el código base que se podría usar para empezar a sacarle provecho:
}
@Override
protected void onResume() {
super.onResume();
if (isEnabledSensor) {
mSensorManager.registerListener(this, mAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}
}
@Override
protected void onPause() {
super.onPause();
if (isEnabledSensor) {
mSensorManager.unregisterListener(this);
}
}
Como podemos ver, al iniciar la app tenemos que comprobar si esta disponible o no, el acelerómetro en este dispositivo. Igualmente, se tiene que aplicar en las otras funciones (onResume, onPause).
En la función "onSensorChanged" es donde tenemos que realizar la acción que queremos llevar a cabo cuando se produzca el evento deseado.
Roger Sala
A continuación les dejo el código base que se podría usar para empezar a sacarle provecho:
public class MySensor extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private boolean isEnabledSensor = false;
@Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (mAccelerometer != null) {
isEnabledSensor = true;
} else {
Toast.makeText(getApplicationContext(),
"Not accelerometer detected", Toast.LENGTH_SHORT).show();
}
}
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
}
@Override
public final void onSensorChanged(SensorEvent event) {
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private boolean isEnabledSensor = false;
@Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (mAccelerometer != null) {
isEnabledSensor = true;
} else {
Toast.makeText(getApplicationContext(),
"Not accelerometer detected", Toast.LENGTH_SHORT).show();
}
}
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
}
@Override
public final void onSensorChanged(SensorEvent event) {
//event contiene un vector que nos permite obtener las 3 coordenadas
float x_value = event.values[0];
float y_value = event.values[1];
float z_value = event.values[2];float x_value = event.values[0];
float y_value = event.values[1];
}
@Override
protected void onResume() {
super.onResume();
if (isEnabledSensor) {
mSensorManager.registerListener(this, mAccelerometer,
SensorManager.SENSOR_DELAY_NORMAL);
}
}
@Override
protected void onPause() {
super.onPause();
if (isEnabledSensor) {
mSensorManager.unregisterListener(this);
}
}
Como podemos ver, al iniciar la app tenemos que comprobar si esta disponible o no, el acelerómetro en este dispositivo. Igualmente, se tiene que aplicar en las otras funciones (onResume, onPause).
En la función "onSensorChanged" es donde tenemos que realizar la acción que queremos llevar a cabo cuando se produzca el evento deseado.
It works!
Roger Sala
lunes, 11 de junio de 2012
Evitando OOM procesando bitmaps
Cuando trabajamos con el procesamiento de imágenes en Android, uno de los principales problemas que nos encontramos es el ya (para mí) típico: "java.lang.OutOfMemoryError: bitmap size exceeds VM budget". Normalmente, este error suele pasar cuando estamos realizando la siguiente acción:
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o=new BitmapFactory.Options();
o.inSampleSize = 8;
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale /2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Esta función, funciona en la mayoría de los casos y terminales. En caso que tengáis algun problema, se puede solucionar cambiando los valores de los parámetros:
- o.inSampleSize;
- REQUIRED_SIZE;
Roger Sala,
Bitmap bitmap = BitmapFactory.decodeFile(fileName);
Una opción que en mis proyectos ha funcionado es implementar este método de la siguiente forma:private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o=new BitmapFactory.Options();
o.inSampleSize = 8;
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale /2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Esta función, funciona en la mayoría de los casos y terminales. En caso que tengáis algun problema, se puede solucionar cambiando los valores de los parámetros:
- o.inSampleSize;
- REQUIRED_SIZE;
It works!
Roger Sala,
Facebook y Twitter en tus aplicaciones
Twitter y facebook son las 2 redes sociales que no pueden faltar en tu aplicación si quieres que la gente comparta información des de ella. A parte, de la publicidad que se genera de tu app.
En este post voy a mostrar la forma más sencilla de que tu app permita compartir mediante estas dos redes sociales. Conozco y he probado la APIs de Facebook, Twitter y varias librerías, pero la forma más fácil de hacerlo es abriendo la aplicación y añadirle el texto que quieres que se muestre. Puedes pensar, ¿y si no tengo la app instalada? Muy sencillo, se puede abrir un webview directamente a Facebook o Twitter.
No obstante, se que no se puede generalizar pero en este caso es practicamente absurdo no hacerlo, y es que, todo usuario Android que tiene cuenta a Facebook/Twitter tiene su aplicación instalada, entonces, este método pasa a ser el más fácil y rápido de añadir a tu app.
a continuación les dejo el código a añadir:
It works!
Roger Sala,
En este post voy a mostrar la forma más sencilla de que tu app permita compartir mediante estas dos redes sociales. Conozco y he probado la APIs de Facebook, Twitter y varias librerías, pero la forma más fácil de hacerlo es abriendo la aplicación y añadirle el texto que quieres que se muestre. Puedes pensar, ¿y si no tengo la app instalada? Muy sencillo, se puede abrir un webview directamente a Facebook o Twitter.
No obstante, se que no se puede generalizar pero en este caso es practicamente absurdo no hacerlo, y es que, todo usuario Android que tiene cuenta a Facebook/Twitter tiene su aplicación instalada, entonces, este método pasa a ser el más fácil y rápido de añadir a tu app.
a continuación les dejo el código a añadir:
public void shareTwitter(Context context, String what)
{
try {
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setClassName("com.twitter.android",
"com.twitter.android.PostActivity");
sharingIntent.putExtra(Intent.EXTRA_TEXT, what);
context.startActivity(sharingIntent);
} catch (Exception e) {
//web
Intent i = new Intent();
i.putExtra(Intent.EXTRA_TEXT, "Mi primer tweet!");
i.setAction(Intent.ACTION_VIEW);
i.setData(Uri.parse("https://mobile.twitter.com/"));
context.startActivityForResult(i, TWITTER);
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setClassName("com.twitter.android",
"com.twitter.android.PostActivity");
sharingIntent.putExtra(Intent.EXTRA_TEXT, what);
context.startActivity(sharingIntent);
} catch (Exception e) {
//web
Intent i = new Intent();
i.putExtra(Intent.EXTRA_TEXT, "Mi primer tweet!");
i.setAction(Intent.ACTION_VIEW);
i.setData(Uri.parse("https://mobile.twitter.com/"));
context.startActivityForResult(i, TWITTER);
}
}
public static void shareFacebook(Context context, String what)
{
try {
Intent intentF = new Intent(Intent.ACTION_VIEW);
intentF.setType("text/plain")
.setAction("android.intent.action.SEND")
.setFlags(0x3000000)
.setClassName("com.facebook.katana","com.facebook.katana.ShareLinkActivity")
.putExtra(Intent.EXTRA_TEXT, what);
context.startActivity(intentF);
} catch (ActivityNotFoundException ex) {
// web
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri
.parse("http://m.facebook.com/sharer.php?u=" + what)));
}
It works!
Roger Sala,
domingo, 10 de junio de 2012
Testing de la aplicación
Parte del éxito de una aplicación pasa por asegurarse que la aplicación es fiable y robusta. Para publicar nuestra aplicación en Google Play tenemos que estar al 100% seguros que no tiene errores, que no se fuerza el cierre de la aplicación y que está testeada por el máximo de dispositivos Android posibles. Este último punto es el más complicado. ¿Porqué? Actualmente hay más de 800 dispositivos distintos que tienen el sistema operativo Android instalado. A pesar que Android ha intentado crear unos estándares con la resolución de pantalla siempre hay dispositivos que se resisten a estos. ¡Cuántos más hayamos podido probar mejor!
No obstante, cuando no podemos probar todo lo que queríamos la aplicación tenemos que recurrir a otras alternativas. Una de ellas es incorporar la librería BugSense. Esta librería es muy fácil e útil de usar. La gran ventaja es que es totalmente transparente al usuario, con lo cuál los "crashes" de nuestra app se nos informan vía email sin necesidad de la colaboración del usuario. Con ello podemos recibir y solucionar todos los problemas que la aplicación puede generar y que des de nuestros recursos no hemos podido tratar. A parte, entre otras cosas genera estadísticas, agrupa los errores, los podemos clasificar en resueltos/no resueltos.
Su uso está explicado en la web, no obstante la idea principal es:
1.- Crear su propia cuenta de BugSense.
2.- Descargarse el archivo .jar
3.- Incorporarlo al proyecto. (carpeta /libs + configure Build Path + Add to build Path).
4.- Crear nuestra aplicación en la web de BugSense.
5.- Recomendación: Tan pronto como se ejecute la app añadir la linea de código siguiente:
6.- Intentar crear un crash de la app y ver que se recibe el correo.
7.- Preparada para publicar con la tranquilidad que todos los "crashes" podrán ser tratados.
Roger Sala,
No obstante, cuando no podemos probar todo lo que queríamos la aplicación tenemos que recurrir a otras alternativas. Una de ellas es incorporar la librería BugSense. Esta librería es muy fácil e útil de usar. La gran ventaja es que es totalmente transparente al usuario, con lo cuál los "crashes" de nuestra app se nos informan vía email sin necesidad de la colaboración del usuario. Con ello podemos recibir y solucionar todos los problemas que la aplicación puede generar y que des de nuestros recursos no hemos podido tratar. A parte, entre otras cosas genera estadísticas, agrupa los errores, los podemos clasificar en resueltos/no resueltos.
Su uso está explicado en la web, no obstante la idea principal es:
1.- Crear su propia cuenta de BugSense.
2.- Descargarse el archivo .jar
3.- Incorporarlo al proyecto. (carpeta /libs + configure Build Path + Add to build Path).
4.- Crear nuestra aplicación en la web de BugSense.
5.- Recomendación: Tan pronto como se ejecute la app añadir la linea de código siguiente:
BugSenseHandler.setup(this, "ID de la app en BugSense");
6.- Intentar crear un crash de la app y ver que se recibe el correo.
7.- Preparada para publicar con la tranquilidad que todos los "crashes" podrán ser tratados.
It works!
Roger Sala,
Google Analytics
Google Analytics para desarrolladores
es un servicio gratuito que nos proporciona Google que podemos usar
para gestionar/tener estadísticas/controlar los accesos a nuestra
aplicación.
Para añadirlo en nuestra aplicación podemos seguir los siguientes pasos:
1.- Creamos una cuenta de Analytics a partir de nuestra cuenta de gmail.
2.- Una vez creada la cuenta, podemos añadir el nombre de nuestra aplicación. Una vez añadida obtenemos un UID que nos vamos a guardar para añadirlo en nuestra aplicación.
3.- Volviendo a Eclipse... Añadimos el archivo GoogleAnalytics.jar a la carpeta /libs de nuestro proyecto. Click derecho + Configure Build Path + Add to Build Path.
4.- Añadimos los permisos necesarios en el AndroidManifest.xml:
5.- Una vez añadido ya podemos usar el Tracker (método de Google Analytics). A continuación un ejemplo fácil de como hacerlo.
@Override
protected void onPause() {
mTracker.dispatch();
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
mTracker.stopSession();
}
}
Si accedemos ahora a nuestra cuenta de GoogleAnalytics ya podemos ver nuestra página indexada en las estadísticas!
It works!
Roger Sala,
Para añadirlo en nuestra aplicación podemos seguir los siguientes pasos:
1.- Creamos una cuenta de Analytics a partir de nuestra cuenta de gmail.
2.- Una vez creada la cuenta, podemos añadir el nombre de nuestra aplicación. Una vez añadida obtenemos un UID que nos vamos a guardar para añadirlo en nuestra aplicación.
3.- Volviendo a Eclipse... Añadimos el archivo GoogleAnalytics.jar a la carpeta /libs de nuestro proyecto. Click derecho + Configure Build Path + Add to Build Path.
4.- Añadimos los permisos necesarios en el AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
5.- Una vez añadido ya podemos usar el Tracker (método de Google Analytics). A continuación un ejemplo fácil de como hacerlo.
public class Example extends Activity{
GoogleAnalyticsTracker mTracker = GoogleAnalyticsTracker.getInstance();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mtracker.startNewSession(/*UID de Google Analytics*/, this);
mtracker.trackPageView("nombre que aparecerá en las estadísticas");
}public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mtracker.startNewSession(/*UID de Google Analytics*/, this);
mtracker.trackPageView("nombre que aparecerá en las estadísticas");
@Override
protected void onPause() {
mTracker.dispatch();
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
mTracker.stopSession();
}
}
Si accedemos ahora a nuestra cuenta de GoogleAnalytics ya podemos ver nuestra página indexada en las estadísticas!
It works!
Roger Sala,
Enviar correo
Muchas veces des de nuestra aplicación queremos facilitar al usuario la posibilidad de mandar un correo des de nuestra aplicación. Por ejemplo, añadir la opción de contactar y/o sugerirnos mejoras/críticas en nuestra aplicación. Para llevarlo a cabo basta con añadir el siguiente fragmento de código.
Esto es todo!
It works!
Roger Sala,
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("message/rfc822");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{getResources().getString(R.string.contactMail) });
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.mailSubject));
startActivity(Intent.createChooser(emailIntent, getString(R.string.mailSend)));
Esto es todo!
It works!
Roger Sala,
sábado, 2 de junio de 2012
Navigator GPS
Desde nuestra aplicación podemos abrir otras aplicaciones como por ejemplo el correo, facebook, twitter, etc. En este caso vamos a ver como abrir la aplicación Navigator de nuestro dispositivo y mostrar la indicaciones para llegar hasta un punto concreto.
Para ello añadimos el siguiente código ya sea en un OnClickListener de ListView, ImageButton, Button, etc.
startActivity(new Intent(Intent.ACTION_VIEW, Uri
.parse("google.navigation:q=" + siteLatitude + ","
+ siteLongitude)));
Espero que os sirva y a disfrutar!
It works!
Roger Sala
Para ello añadimos el siguiente código ya sea en un OnClickListener de ListView, ImageButton, Button, etc.
startActivity(new Intent(Intent.ACTION_VIEW, Uri
.parse("google.navigation:q=" + siteLatitude + ","
+ siteLongitude)));
Espero que os sirva y a disfrutar!
It works!
Roger Sala
Custom Splash
Android por defecto no añade a sus proyectos una vista de Splash dónde se inicie la aplicación. No obstante, mediante Thread tenemos la posibilidad de implementar nuestra propia vista de Splash. Para ello podemos crear Activity siguiente:
A continuación añadimos en la carpeta de res/layout/splash.xml:
Y ya tenemos nuestra propia vista splash. Obviamente, se puede variar el formato y aprovechar el Splash para cargar la información de los webservices. Esta funcionalidad ya depende de cada uno!
It works!
Roger Sala
public class Splash extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
try {
Thread splashThread = new Thread() {
@Override
public void run() {
try {
int waited = 0;
while (waited < 800) {
sleep(80);
waited += 100;
}
// perquè aixi quan premin back no apareixi aquesta
// vista
finish();
Intent intent = new Intent(Splash.this,
ClassToGo.class);
startActivity(intent);
} catch (InterruptedException e) {
}
}
};
splashThread.start();
} catch (Exception e) {
}
}
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
try {
Thread splashThread = new Thread() {
@Override
public void run() {
try {
int waited = 0;
while (waited < 800) {
sleep(80);
waited += 100;
}
// perquè aixi quan premin back no apareixi aquesta
// vista
finish();
Intent intent = new Intent(Splash.this,
ClassToGo.class);
startActivity(intent);
} catch (InterruptedException e) {
}
}
};
splashThread.start();
} catch (Exception e) {
}
}
A continuación añadimos en la carpeta de res/layout/splash.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white">
<ImageView
android:id="@+id/splash"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:src="@drawable/ic_launcher" />
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white">
<ImageView
android:id="@+id/splash"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:src="@drawable/ic_launcher" />
</RelativeLayout>
Y ya tenemos nuestra propia vista splash. Obviamente, se puede variar el formato y aprovechar el Splash para cargar la información de los webservices. Esta funcionalidad ya depende de cada uno!
It works!
Roger Sala
Suscribirse a:
Entradas (Atom)