Author Archives: admin

PSD to HTML is Dead

[Fuente: http://blog.teamtreehouse.com/psd-to-html-is-dead]

Los tutoriales de PSD a HTML son muchos en la red. De hecho, mucha gente me pregunta porque no hay tutoriales de PSD a HTML en Treehouse. Además de los tutoriales, hay muchas compañias que aceptan un PSD y lo convierten a una página web por  $100 USD.

Sin embargo , aunque es popular , PSD to HTML no es la mejor forma de construir websites.

Si es popular, entonces cómo podemos decir que está muerto? Vamos a explicarlo.

 

Qué es PSD to HTML?

En general, “PSD to HTML” es un workflow. Primero, una página web se diseña en un documento Photoshop (PSD) y entonces se convierte a código (utlizando HTML , CSS y Javascript). Podrías elegir otro editor de imágenes en vez de Photoshop, pero el principio es el mismo. Aquí vemos los pasos en más detalle:

  1. Diseña un mockup al detalle de pixel en Photoshop de exactamente lo que quieres que sea tu web.
  2. Utiliza la Slice Tool de Photoshop para dividir en imágenes de web y exportarlo a web.
  3. Escribe HTML y CSS que utilice las imágenes que exportaste desde Photoshop.

En un primer vistazo , esto puede parecer una buena idea.

Screenshot of the save for web dialog window in Photoshop.

En Photoshop , la herramienta de slices en la ventana de Save for Web es esencial para que los diseñadores saquen assets (recursos de imágenes) desde el PSD. Se hace fácil trocear un diseño y entonces ponerlo en un layout hecho de HTML y CSS.

Con esta idea , muchas compañias han adoptado esta forma de trabajo en sus workflows de trabajo. En otras palabras, un diseñador crea el Photoshop mockup y entonces se lo pasa al programador qye es es el que escribe el código. Hoy en día, el role de un diseñador web tiende a fusionar tanto temas estéticos como de programación HTML y CSS.

Sigue siendo PSD to HTML una buena idea?

Si , el workflow de PSD to HTML solía ser una de las mejores formas de hacer websites. Hat dos buenas razones por las que PSd to HTML sigue teniendo sentido.

  • La primera razón es para hacer assets. Antes de que los navegadores soportaran todas las maravillosas caracteristicas del CSS moderno (drop shadows, rounded corners, gradients, and more) era muy dificil crear efectos cross-browser sin la utilización de imágenes. Los diseñadores creaban sombras u esquinas redondeadas como imágenes, entonces se utilizan truquillos de código para colocar todas estas pequeñas imágenes en el sitio apropiado y que diera el pego. Estos assets por tanto eran necesarios y poder crearlos al mismo tiempo que el mockup ahorraba tiempo.

Screenshot of a sliding doors tab asset.

Prior to the development and widespread adoption of CSS, many websites were a collection of image assets that looked something like this. One of the most innovative techniques of the time was the sliding doors technique to create tabs back in 2003.

  • Segundo (y quizás más importante) , la web sólo se visualizaba eb navegadores de ordenadores desktop  y no era realmente importante que se viera bien en phones y tablets como lo es hoy. Diseñar para una resolución fija de 1024×768 soliá ser una buena solución.

Por estas dos razones, es entendible porque un diseñador elije Photoshop como su principal herramienta. Las image assets son necesaria en todas las resoluciones de pantalla.

Qué es lo que falla ahora en la metodología PSD to HTML?

Estas son las razones principales por las que pienso que PSD to HTML está muerto.

DISEÑO WEB RESPONSIVO

Hoy en día se consulta páginas web de muchas dispositivos y navegadores distintos. No hay un resolución de pantalla en la que el diseñador se puede fijar como la buena. Yendo más alla , ya no se puede hablar de diseño para una resolución de pantalla en concreto.

Screensiz.es provides tables of information about popular hardware devices.

Screensiz.es provides tables of information about popular hardware devices.

Sin entrar en detalle sobre responsive web design or scalable design, la cuestión es que Photoshop está basado en pixeles y ahora las páginas web son fluidas y se tienen que adaptar a los cambios.

DISEÑO CSS

Segundo ,las nuevas características en CSS ahora disponibles. Efectos comunes como sombras , gradientes  y esquinas redondeadas se pueden hacer con CSS y generalmente ni siquiera necesitan estar basados en imagenes.

MADUREZ

Tercero , la industria web ha crecido mucho. Ya en general sabemos lo que funciona y lo que no. La mayoría de las compañias esperan que el diseñador sea el responsable tanto de la estética como de la codificación del HTML y el CSS.

Esto también quiere decir que hay muchas herramientas que soportan los modernos flujos de trabajo.Frameworks CSS (CSS frameworks) como Bootstrap y Foundation hacen más viable el diseño web. Apps como Balsamiq y Omnigraffle te ayudan a hacer wireframes de los sites rápidamente. Aun así , los mockups hechos con papel y el lápiz  han aguantado bien el paso del tiempo.

Does this mean Photoshop is dead?

No! Not even close. Photoshop is still very important to web design. The problem comes in when a powerful tool like Photoshop is used as a catch all solution without thinking of the higher level task (designing websites). Photoshop is awesome for editing and exporting photographs for web usage. There’s also plenty of situations where it still might make sense to generate full detail mockups (in Photoshop, Illustrator, or otherwise) as part of a more complete process. Here are a couple of examples:

  • High fidelity mockups can be a critical communication tool when working with web design clients. It might seem faster to skip a high detail mockup, but it could hurt later on, because many clients aren’t going to understand how a wireframe will translate to a web browser. A high fidelity mockup can serve as a discussion tool before writing lots of code (only to discover it’s not what the client wanted).
  • High fidelity mockups can be very important when working in medium to large sized teams. We often will create high res mockups at Treehouse when planning new courses or designing new features of our site, because it’s a powerful way to sync everyone’s mental model of what a feature will look like or how a project might look once it’s finished.

These two examples have a key difference from the PSD to HTML way of thinking. High detail mockups are still sometimes generated, but not so that they can be “tossed over the fence” to a team of developers or sliced up into code. Rather, Photoshop mockups can be used as a visual aid to discuss ideas. In a PSD to HTML workflow, the Photoshop document represents the final site and it’s expected to look exactly the same in the browser. This is a subtle but important difference.

Different Strokes

Everyone’s workflow is different and nobody knows how to make the perfect website. You should always do whatever is most effective for you and your colleagues. Pushing pixels around in Photoshop is a ton of fun, but I can admit to many occasions when I’ve pushed the pixels too far. The key is to know yourself and what makes you perform at your best. If you have any questions or opinions, I’d love to hear about them in the comments!

Android: Custom ArrayAdapter for a ListView

[Fuente: http://devtut.wordpress.com/2011/06/09/custom-arrayadapter-for-a-listview-android/]

For work, I needed to come up with a nice way to display information from multiple objects, and have the ability to format each individual part of that information.

I decided to use a ListView. Since I had an ArrayList of the objects I created, this ListView needed to extend ArrayAdapter.

For this simple example to work, you are going to need 3 Java classes (MainActivity, Item, ItemAdapter), 2 XML files (main, list_item), and of course, the Android Manifest.

To get a get visual on what we’re creating here, take a look at the screenshot below:

Custom Adapter Example

So first off, you’ll need to create your Item class. The one in the example is simple, three fields and their getters/setters. Here is the code if you’d like to take a look:

Item

package com.doctororeo.examples;

public class Item {
	private String details;
	private String name;
	private int price;

	public Item(){

	}

	public Item(String i, String d, int p){
		this.details = d;
		this.name = i;
		this.price = p;
	}

	public String getDetails() {
		return details;
	}

	public void setDetails(String details) {
		this.details = details;
	}

	public String getName() {
		return name;
	}

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

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}

}

If you’re unsure of what this code does, please read further on creating classes/objects in the Sun API – the documentation is adequate for beginners.

The next step is where things get a bit hairy. What we’re going to need to do is make our ItemAdapter class – this class will extend the ArrayAdapter class. When we extend a class, the child class inherits all of the parent class’ attributes.

Ok – skip to the code. I’ve commented it fairly well, but you’re welcome to ask if anything confuses you.

ItemAdapter

package com.doctororeo.examples;

import java.util.ArrayList;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class ItemAdapter extends ArrayAdapter<Item> {

	// declaring our ArrayList of items
	private ArrayList<Item> objects;

	/* here we must override the constructor for ArrayAdapter
	* the only variable we care about now is ArrayList<Item> objects,
	* because it is the list of objects we want to display.
	*/
	public ItemAdapter(Context context, int textViewResourceId, ArrayList<Item> objects) {
		super(context, textViewResourceId, objects);
		this.objects = objects;
	}

	/*
	 * we are overriding the getView method here - this is what defines how each
	 * list item will look.
	 */
	public View getView(int position, View convertView, ViewGroup parent){

		// assign the view we are converting to a local variable
		View v = convertView;

		// first check to see if the view is null. if so, we have to inflate it.
		// to inflate it basically means to render, or show, the view.
		if (v == null) {
			LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			v = inflater.inflate(R.layout.list_item, null);
		}

		/*
		 * Recall that the variable position is sent in as an argument to this method.
		 * The variable simply refers to the position of the current object in the list. (The ArrayAdapter
		 * iterates through the list we sent it)
		 * 
		 * Therefore, i refers to the current Item object.
		 */
		Item i = objects.get(position);

		if (i != null) {

			// This is how you obtain a reference to the TextViews.
			// These TextViews are created in the XML files we defined.

			TextView tt = (TextView) v.findViewById(R.id.toptext);
			TextView ttd = (TextView) v.findViewById(R.id.toptextdata);
			TextView mt = (TextView) v.findViewById(R.id.middletext);
			TextView mtd = (TextView) v.findViewById(R.id.middletextdata);
			TextView bt = (TextView) v.findViewById(R.id.bottomtext);
			TextView btd = (TextView) v.findViewById(R.id.desctext);

			// check to see if each individual textview is null.
			// if not, assign some text!
			if (tt != null){
				tt.setText("Name: ");
			}
			if (ttd != null){
				ttd.setText(i.getName());
			}
			if (mt != null){
				mt.setText("Price: ");
			}
			if (mtd != null){
				mtd.setText("$" + i.getPrice());
			}
			if (bt != null){
				bt.setText("Details: ");
			}
			if (btd != null){
				btd.setText(i.getDetails());
			}
		}

		// the view must be returned to our activity
		return v;

	}

}

As you can see, the ItemAdapter sets the text for each TextView. We haven’t implemented the TextViews yet. Time for a bit of XML.

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
<ListView
    android:id="@+id/android:list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    />
<TextView
    android:id="@+id/android:empty"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:text="No items to display."/>
</LinearLayout>

list_item.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="?android:attr/listPreferredItemHeight"

    android:padding="6dip">
    <!-- Item Name -->
   <TextView
		android:id="@+id/toptext"

		android:layout_width="wrap_content"
		android:layout_height="26dip"

		android:layout_alignParentTop="true"
		android:layout_alignParentLeft="true"

		android:textStyle="bold"
		android:singleLine="true"
		android:ellipsize="marquee"
   />

       <!-- Actual Item Name Data -->
   <TextView
		android:id="@+id/toptextdata"

		android:layout_width="fill_parent"
		android:layout_height="wrap_content"

		android:layout_alignParentRight="true"
		android:layout_alignParentTop="true"
		android:layout_toRightOf="@id/toptext"

		android:singleLine="true"
		android:ellipsize="marquee"
   />

   <!-- Price Tag -->
   <TextView
	 	android:id="@+id/middletext"

	 	android:layout_width="wrap_content"
	 	android:layout_height="26dip"

		android:layout_alignParentLeft="true"
		android:layout_below="@id/toptext"

	 	android:textStyle="bold"
	 	android:gravity="center_vertical"
   	/>

   	       <!-- Actual Price Data -->
   <TextView
		android:id="@+id/middletextdata"

		android:layout_width="fill_parent"
		android:layout_height="26dip"

		android:layout_alignParentRight="true"
		android:layout_below="@id/toptext"
		android:layout_toRightOf="@id/middletext"

		android:gravity="center_vertical"
   />

   	<!-- Description Tag -->
   <TextView
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"

		android:layout_alignParentRight="true"
		android:layout_below="@id/middletext"

		android:textStyle="bold"
		android:id="@+id/bottomtext"
		android:singleLine="false"
   />
   <!-- This is the actual description -->
      <TextView
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"

		android:layout_alignParentRight="true"
		android:layout_alignParentBottom="true"
		android:layout_below="@id/bottomtext"

		android:id="@+id/desctext"
		android:singleLine="false"
   />
</RelativeLayout>

I’m not going to explain how these two files work, because the point of this article isn’t to teach XML. However, as always, if you have any questions feel free to ask in the comments.

There’s one last part to this equation. The MainActivity file – it must extend ListActivity instead of Activity. If you don’t do this, it WILL NOT work. I only emphasize this, because I forgot to when I re-did the code for this article. Only took me a few minutes to figure it out, but I figured I might as well mention it. In addition to displaying the data, I’m going to show you how to use a thread to get the data. This is useful when processing large amounts of data. In an actual application, you may want to include a progress bar to show the user that something is “being done”, otherwise it will appear as though the application has frozen. I won’t be showing you how to do this in this article, but it’s fairly easy to find on Google.

MainActivity

package com.doctororeo.examples;

import java.util.ArrayList;

import android.app.ListActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class MainActivity extends ListActivity {

	// declare class variables
	private ArrayList<Item> m_parts = new ArrayList<Item>();
	private Runnable viewParts;
	private ItemAdapter m_adapter;

    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // instantiate our ItemAdapter class
        m_adapter = new ItemAdapter(this, R.layout.list_item, m_parts);
        setListAdapter(m_adapter);

        // here we are defining our runnable thread.
        viewParts = new Runnable(){
        	public void run(){
        		handler.sendEmptyMessage(0);
        	}
        };

        // here we call the thread we just defined - it is sent to the handler below.
        Thread thread =  new Thread(null, viewParts, "MagentoBackground");
        thread.start();
    }

    private Handler handler = new Handler()
	 {
		public void handleMessage(Message msg)
		{
			// create some objects
			// here is where you could also request data from a server
			// and then create objects from that data.
			m_parts.add(new Item("MyItemName", "This is item #1", 0));
			m_parts.add(new Item("MyItemName #2", "This is item #2", 0));

			m_adapter = new ItemAdapter(MainActivity.this, R.layout.list_item, m_parts);

			// display the list.
	        setListAdapter(m_adapter);
		}
	};
}

 

That’s it. That’s all the code you need to create a ListView with multiple data fields, and the ability to customize each part of it. Feel free to play with the code for learning purposes.

Stay tuned for more examples! Please vote below to let me know how I’m doing!

Android: Creando Swipe Views con Tabs

[Fuente : http://developer.android.com/training/implementing-navigation/lateral.html]

THIS LESSON TEACHES YOU TO

  1. Implement Swipe Views
  2. Add Tabs to the Action Bar
  3. Change Tabs with Swipe Views
  4. Use a Title Strip Instead of Tabs

YOU SHOULD ALSO READ

Las swipe views proporcionan navegación lateral entre pantallas hermanas tales como las tabs con un gesto del dedo horizontal (un patrón algunas veces conocido como paginación horizontal). Este post nos enseña cómo crear un Tab Layout con swipe views para poder moverse entre los tabs arrastrando el dedo.

Diseño de un Swipe View 

Before implementing these features, you should understand the concepts and recommendations as described in Designing Effective Navigation and the Swipe Views design guide.

Implementación de las Swipe Views

Puedes crear swipe views en tu app utilizando el widget ViewPager, incluido el la Support Library. El ViewPager es un widget de layout en el que cada View hijo es una página separada (una tab separada) en el layout.

Para configurar tu layout con ViewPager , añade un elemento <ViewPager> al xml de tu layout. Por ejemplo, si cada página en la swipe view rellena el layout entero, entonces tu layout parece como esto:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Para insertar vistas hijas que representan cada página, necesitas enganchar este layout a un PagerAdapter. Hay dos tipos de adaptadores que puedes utilizar:

FragmentPagerAdapter
Esto es mejor cuando navegando entre pantallas hermanas estas son un número fijo y pequeño de páginas.
FragmentStatePagerAdapter
This is best for paging across a collection of objects for which the number of pages is undetermined. It destroys fragments as the user navigates to other pages, minimizing memory usage.

For example, here’s how you might use FragmentStatePagerAdapter to swipe across a collection of Fragment objects:

public class CollectionDemoActivity extends FragmentActivity {
    // When requested, this adapter returns a DemoObjectFragment,
    // representing an object in the collection.
    DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
    ViewPager mViewPager;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_collection_demo);

        // ViewPager and its adapters use support library
        // fragments, so use getSupportFragmentManager.
        mDemoCollectionPagerAdapter =
                new DemoCollectionPagerAdapter(
                        getSupportFragmentManager());
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mDemoCollectionPagerAdapter);
    }
}

// Since this is an object collection, use a FragmentStatePagerAdapter,
// and NOT a FragmentPagerAdapter.
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
    public DemoCollectionPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int i) {
        Fragment fragment = new DemoObjectFragment();
        Bundle args = new Bundle();
        // Our object is just an integer :-P
        args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getCount() {
        return 100;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "OBJECT " + (position + 1);
    }
}

// Instances of this class are fragments representing a single
// object in our collection.
public static class DemoObjectFragment extends Fragment {
    public static final String ARG_OBJECT = "object";

    @Override
    public View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState) {
        // The last two arguments ensure LayoutParams are inflated
        // properly.
        View rootView = inflater.inflate(
                R.layout.fragment_collection_object, container, false);
        Bundle args = getArguments();
        ((TextView) rootView.findViewById(android.R.id.text1)).setText(
                Integer.toString(args.getInt(ARG_OBJECT)));
        return rootView;
    }
}

This example shows only the code necessary to create the swipe views. The following sections show how you can add tabs to help facilitate navigation between pages.

Add Tabs to the Action Bar


Action bar tabs offer users a familiar interface for navigating between and identifying sibling screens in your app.

To create tabs using ActionBar, you need to enable NAVIGATION_MODE_TABS, then create several instances ofActionBar.Tab and supply an implementation of the ActionBar.TabListener interface for each one. For example, in your activity’s onCreate() method, you can use code similar to this:

@Override
public void onCreate(Bundle savedInstanceState) {
    final ActionBar actionBar = getActionBar();
    ...

    // Specify that tabs should be displayed in the action bar.
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // Create a tab listener that is called when the user changes tabs.
    ActionBar.TabListener tabListener = new ActionBar.TabListener() {
        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
            // show the given tab
        }

        public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
            // hide the given tab
        }

        public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
            // probably ignore this event
        }
    };

    // Add 3 tabs, specifying the tab's text and TabListener
    for (int i = 0; i < 3; i++) {
        actionBar.addTab(
                actionBar.newTab()
                        .setText("Tab " + (i + 1))
                        .setTabListener(tabListener));
    }
}

How you handle the ActionBar.TabListener callbacks to change tabs depends on how you’ve constructed your content. But if you’re using fragments for each tab with ViewPager as shown above, the following section shows how to switch between pages when the user selects a tab and also update the selected tab when the user swipes between pages.

Change Tabs with Swipe Views


To switch between pages in a ViewPager when the user selects a tab, implement yourActionBar.TabListener to select the appropriate page by calling setCurrentItem() on your ViewPager:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    // Create a tab listener that is called when the user changes tabs.
    ActionBar.TabListener tabListener = new ActionBar.TabListener() {
        public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
            // When the tab is selected, switch to the
            // corresponding page in the ViewPager.
            mViewPager.setCurrentItem(tab.getPosition());
        }
        ...
    };
}

Likewise, you should select the corresponding tab when the user swipes between pages with a touch gesture. You can set up this behavior by implementing the ViewPager.OnPageChangeListener interface to change the current tab each time the page changes. For example:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setOnPageChangeListener(
            new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    // When swiping between pages, select the
                    // corresponding tab.
                    getActionBar().setSelectedNavigationItem(position);
                }
            });
    ...
}

Use a Title Strip Instead of Tabs


If you don’t want to include action bar tabs and prefer to provide scrollable tabs for a shorter visual profile, you can use PagerTitleStrip with your swipe views.

Below is an example layout XML file for an activity whose entire contents are a ViewPager and a top-alignedPagerTitleStrip inside it. Individual pages (provided by the adapter) occupy the remaining space inside theViewPager.

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:textColor="#fff"
        android:paddingTop="4dp"
        android:paddingBottom="4dp" />

</android.support.v4.view.ViewPager>

Android: Creando un navigation drawer

[Fuente: http://developer.android.com/training/implementing-navigation/nav-drawer.html]

El navigation drawer es un panel que muestra las opciones de navegación principales en el lateral izquierdo de la pantalla. It is hidden most of the time, but is revealed when the user swipes a finger from the left edge of the screen or, while at the top level of the app, the user touches the app icon in the action bar.

This lesson describes how to implement a navigation drawer using the DrawerLayout APIs available in the Support Library.

Navigation Drawer Design

Before you decide to use a navigation drawer in your app, you should understand the use cases and design principles defined in the Navigation Drawer design guide.

Create a Drawer Layout


To add a navigation drawer, declare your user interface with a DrawerLayout object as the root view of your layout. Inside the DrawerLayout, add one view that contains the main content for the screen (your primary layout when the drawer is hidden) and another view that contains the contents of the navigation drawer.

For example, the following layout uses a DrawerLayout with two child views: a FrameLayout to contain the main content (populated by a Fragment at runtime), and a ListView for the navigation drawer.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- The navigation drawer -->
    <ListView android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>

This layout demonstrates some important layout characteristics:

  • The main content view (the FrameLayout above) must be the first child in the DrawerLayout because the XML order implies z-ordering and the drawer must be on top of the content.
  • The main content view is set to match the parent view’s width and height, because it represents the entire UI when the navigation drawer is hidden.
  • The drawer view (the ListViewmust specify its horizontal gravity with the android:layout_gravity attribute. To support right-to-left (RTL) languages, specify the value with "start" instead of "left" (so the drawer appears on the right when the layout is RTL). 
  • The drawer view specifies its width in dp units and the height matches the parent view. The drawer width should be no more than 320dp so the user can always see a portion of the main content.

Initialize the Drawer List

In your activity, one of the first things to do is initialize the navigation drawer’s list of items. How you do so depends on the content of your app, but a navigation drawer often consists of a ListView, so the list should be populated by an Adapter (such as ArrayAdapter or SimpleCursorAdapter).

For example, here’s how you can initialize the navigation list with a string array:

public class MainActivity extends Activity {
    private String[] mPlanetTitles;
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPlanetTitles = getResources().getStringArray(R.array.planets_array);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        // Set the adapter for the list view
        mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                R.layout.drawer_list_item, mPlanetTitles));
        // Set the list's click listener
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        ...
    }
}

This code also calls setOnItemClickListener() to receive click events in the navigation drawer’s list. The next section shows how to implement this interface and change the content view when the user selects an item.

Handle Navigation Click Events


When the user selects an item in the drawer’s list, the system calls onItemClick() on theOnItemClickListener given to setOnItemClickListener().

What you do in the onItemClick() method depends on how you’ve implemented your app structure. In the following example, selecting each item in the list inserts a different Fragment into the main content view (theFrameLayout element identified by the R.id.content_frame ID):

private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        selectItem(position);
    }
}

/** Swaps fragments in the main content view */
private void selectItem(int position) {
    // Create a new fragment and specify the planet to show based on position
    Fragment fragment = new PlanetFragment();
    Bundle args = new Bundle();
    args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
    fragment.setArguments(args);

    // Insert the fragment by replacing any existing fragment
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.beginTransaction()
                   .replace(R.id.content_frame, fragment)
                   .commit();

    // Highlight the selected item, update the title, and close the drawer
    mDrawerList.setItemChecked(position, true);
    setTitle(mPlanetTitles[position]);
    mDrawerLayout.closeDrawer(mDrawerList);
}

@Override
public void setTitle(CharSequence title) {
    mTitle = title;
    getActionBar().setTitle(mTitle);
}

Listen for Open and Close Events


To listen for drawer open and close events, call setDrawerListener() on your DrawerLayout and pass it an implementation of DrawerLayout.DrawerListener. This interface provides callbacks for drawer events such as onDrawerOpened() and onDrawerClosed().

However, rather than implementing the DrawerLayout.DrawerListener, if your activity includes the action bar, you can instead extend the ActionBarDrawerToggle class. The ActionBarDrawerToggle implementsDrawerLayout.DrawerListener so you can still override those callbacks, but it also facilitates the proper interaction behavior between the action bar icon and the navigation drawer (discussed further in the next section).

As discussed in the Navigation Drawer design guide, you should modify the contents of the action bar when the drawer is visible, such as to change the title and remove action items that are contextual to the main content. The following code shows how you can do so by overriding DrawerLayout.DrawerListener callback methods with an instance of the ActionBarDrawerToggle class:

public class MainActivity extends Activity {
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private CharSequence mDrawerTitle;
    private CharSequence mTitle;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...

        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {

            /** Called when a drawer has settled in a completely closed state. */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            /** Called when a drawer has settled in a completely open state. */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };

        // Set the drawer toggle as the DrawerListener
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    /* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
}

The next section describes the ActionBarDrawerToggle constructor arguments and the other steps required to set it up to handle interaction with the action bar icon.

Open and Close with the App Icon


Users can open and close the navigation drawer with a swipe gesture from or towards the left edge of the screen, but if you’re using the action bar, you should also allow users to open and close it by touching the app icon. And the app icon should also indicate the presence of the navigation drawer with a special icon. You can implement all this behavior by using the ActionBarDrawerToggle shown in the previous section.

To make ActionBarDrawerToggle work, create an instance of it with its constructor, which requires the following arguments:

  • The Activity hosting the drawer.
  • The DrawerLayout.
  • A drawable resource to use as the drawer indicator.

    The standard navigation drawer icon is available in the Download the Action Bar Icon Pack.

  • A String resource to describe the “open drawer” action (for accessibility).
  • A String resource to describe the “close drawer” action (for accessibility).

Then, whether or not you’ve created a subclass of ActionBarDrawerToggle as your drawer listener, you need to call upon your ActionBarDrawerToggle in a few places throughout your activity lifecycle:

public class MainActivity extends Activity {
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    ...

    public void onCreate(Bundle savedInstanceState) {
        ...

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerToggle = new ActionBarDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer icon to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description */
                R.string.drawer_close  /* "close drawer" description */
                ) {

            /** Called when a drawer has settled in a completely closed state. */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                getActionBar().setTitle(mTitle);
            }

            /** Called when a drawer has settled in a completely open state. */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                getActionBar().setTitle(mDrawerTitle);
            }
        };

        // Set the drawer toggle as the DrawerListener
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Pass the event to ActionBarDrawerToggle, if it returns
        // true, then it has handled the app icon touch event
        if (mDrawerToggle.onOptionsItemSelected(item)) {
          return true;
        }
        // Handle your other action bar items...

        return super.onOptionsItemSelected(item);
    }

    ...
}

Android: Diseñando una navegación efectiva

[Fuente: http://developer.android.com/training/design-navigation/index.html]

Una de las primeras cosas que hay que plantearse para diseñar y desarollar una aplicación Android es determinar lo que los usuarios pueden ver y hacer con la app. Una vez que sabemos el tipo de datos con el que los usuarios están interactuando en nuestra aoo, el siguiente paso es diseñar las interacciones que permitan a los usuarios navegar por ellos adelante y atrás a través de las distintas piezas de contenido dentro de la app.

En este post te mostramos como planificar a alto nivel una jerarquia de pantallas para tu app y entonces elegir las formas más apropiadas de navegación que permita a tus usuarios efectivamente e intuitivamente navegar por ellas.. Each lesson covers various stages in the interaction design process for navigation in Android applications, in roughly chronological order. After going through the lessons in this class, you should be able to apply the methodology and navigation paradigms outlined here to your own applications, providing a coherent navigation experience for your users.

Lessons


Planificando las pantallas y sus relaciones
Learn how to choose which screens your application should contain. Also learn how to choose which screens should be directly reachable from others. This lesson introduces a hypothetical news application to serve as an example for later lessons.
Planificando para múltiples pantallas táctiles
Learn how to group related screens together on larger-screen devices to optimize use of available screen space.
Proporcionando navegación lateral y descendente
Learn about techniques for allowing users to navigate deep into, as well as across, your content hierarchy. Also learn about pros and cons of, and best practices for, specific navigational UI elements for various situations.
Proporcionando navegación temporal y ancestral
Learn how to allow users to navigate upwards in the content hierarchy. Also learn about best practices for the Back button and temporal navigation, or navigation to previous screens that may not be hierarchically related.
Poniendolo todo junto: Wireframing una aplicación de ejemplo
Learn how to create screen wireframes (low-fidelity graphic mockups) representing the screens in a news application based on the desired information model. These wireframes utilize navigational elements discussed in previous lessons to demonstrate intuitive and efficient navigation.

Planning Screens and Their Relationships

THIS LESSON TEACHES YOU TO
  1. Create a Screen List
  2. Diagram Screen Relationships
  3. Go Beyond a Simplistic Design

La mayoría de las apps tienen un modelo de información inherente que puede ser expresado como un árbol de tipos de objetos. Es decir, podemos dibujar un diagrama de tipos de información distintas que representan los tipos de cosas con las que los usuarios interactuan dentro de nuestra app. Los ingenieros de software y los arquitectos de datos a menudo utilizan diagramas entidad-relación (ERDs) para describir el modelo de información de una aplicación.

Consideremos una aplicación de ejemplo que permite a los usuarios navegar por un conjunto de noticias (stories) y fotos categorizadas. un posible modelo ERD para tal app podría ser el siguiente:

Entity-relationship diagram for the example news application

Figure 1. Entity-relationship diagram for the example news application.

Create a Screen List


Una vez que defines el modelo de información , puedes comenzar a definir los contextos necesarios para permitir a tus usuarios descubrir , visualizar y actuar sobre los datos de tu app de forma efectiva . En la práctica ,una forma de hacer esto es determinando de forma exhaustiva el conjunto completo de pantallas necesario que permita a tus usuarios navegar e interactuar con los datos. El conjunto de pantallas que exponemos por supuesto variará dependiendo del tipo de dispositivo: es importante considerar esto desde el principio en el proceso de diseño para asegurar que la app se adapte a todos los entornos.

En nuestra aplicación de ejemplo , queremos habilitar usuarios para ver , grabar y compartir noticias y fotos categorizadas. A continuación exponemos una lista exhaustiva de pantallas que cubren estos casos de uso:

  • Home or “launchpad” screen for accessing stories and photos
  • List of categories
  • List of news stories for a given category
  • Story detail view (from which we can save and share)
  • List of photos, uncategorized
  • Photo detail view (from which we can save and share)
  • List of all saved items
  • List of saved photos
  • List of saved stories

Diagram Screen Relationships


Ahora podemos definir las relaciones directas entre pantallas; una flecha desde una pantalla A a una pantalla B implica que la pantalla B debe ser alcanzable por alguna interacción del usuario desde la pantalla A. Una vez que defines tanto el conjunto de pantallas como sus relaciones, podemos expresar esto en términos de una screen map, la cual muestra todas nuestras pantallas y sus relaciones:

Exhaustive screen map for the example news application

Figure 2. Exhaustive screen map for the example news application.

If we later wanted to allow users to submit news stories or upload photos, we could add additional screens to this diagram.

Ir hacia un diseño más simplista


En este punto es posible diseñar una aplicación completamente funcional desde este screen map exhaustivo. Un interfaz de usuario simple se puede componer de listas y botones para ir a las pantallas hijas.

  • Botones para ir a las distinas secciones (e.g., stories, photos, saved items)
  • Listas verticales que representen colecciones de elementos (e.g., story lists, photo lists, etc.)
  • Información de detalle e.g., story view, full-screen photo view, etc.)

Sin embargo , puedes utilizar técnicas de agrupación de pantallas y elementos de navegación más sofisticados para presentar contenido de una forma más intuitiva y que se adapte mejor al dispositivo. En el siguiente apartado , exploraremos estas técnicas , tales como proporcionar  multi-pane layouts para dispositivos tablets. Más adelante , profundizaremos en los patrones de navegación más comunes en dispositivos Android.

Planning for Multiple Touchscreen Sizes

THIS LESSON TEACHES YOU TO
  1. Group Screens with Multi-pane Layouts
  2. Design for Multiple Tablet Orientations
  3. Group Screens in the Screen Map

YOU SHOULD ALSO READ

El mapa de pantallas que hemos hecho en el apartado anterior no está atado a un dispositivo en particular, aunque puede verse bien y funcionar en un móvil o dispositivo de un tamaño similar. Pero las aplicaciones Android necesitan adaptarse a una amplia variedad de dispositivos, desde 3″ handsets to 10″ tablets to 42″ TVs.En este apartado exploraremos las razones y tácticas para agrupar juntas varias pantallas desde el screen exhaustive map.

Note: Designing applications for television sets also requires attention to other factors, including interaction methods (i.e., the lack of a touch screen), legibility of text at large reading distances, and more. Although this discussion is outside the scope of this class, you can find more information on designing for TVs in the Google TV documentation for design patterns.

Agrupar Screens con Layouts Multi-pane

Diseño de un Layout Multi-pane 

For design guidelines, read Android Design’s Multi-pane Layouts pattern guide.

Las pantallas de 3 o 4 pulgadas se ajustan bien a la hora de mostrar un sólo panel vertical de contenido en cada momento , ya sea una lista de elementos , o información de detalle de un elemento , etc. Asi que en tales dispositivos , las screens se mapean one-to-one con la jerarquia de los niveles de información (categorias –> lista de objetos –> detalle del objeto)

Las pantallas más grandes , como las de las tablets y las TVs, por otra parte , tiene más espacio de pantalla disponible y son capaces de presentar varios paneles de contenido. En landscape, los paneles son generalmente posicionados de izquierda a derecha en orden creciente de detalle. Los usuarios están acostumbrados a varios paneles en pantallas grandes desde hace muchos años en aplicaciones de escritorio y en aplicaciones web.Muchas aplicaciones de escritorio y websites ofrecen un panel de navegación en el lateral izquierdo o utilizan un layout de dos paneles master/detail.

Además de tratar con las expectativas del usuario, es generalmente necesario proporcionar múltiples paneles de información en tablets para eliminar mucho espacio vacío o poder prevenir interacciones del usuario no deseadas: por ejemplo botones de 10 x 0.5-pulgadas.

La siguiente figura demuestra algunos de los problemas que pueden surgir cuando se muestra un diseño UI  en un layout más grande y cómo solucionar estos inconvenientes con multi-pane layouts:

Single pane layouts on large screens in landscape lead to awkward whitespace and exceedingly long line lengthsFigure 1. Single pane layouts on large screens in landscape lead to awkward whitespace and exceedingly long line lengths.

Multi-pane layouts in landscape offer better a visual balance while offering more utility and legibilityFigure 2. Multi-pane layouts in landscape result in a better visual balance while offering more utility and legibility.

Implementation Note: After deciding on the screen size at which to draw the line between single-pane and multi-pane layouts, you can provide different layouts containing one or multiple panes for devices in varying screen size buckets (such as large/xlarge) or varying minimum screen widths (such as sw600dp).

Implementation Note: While a single screen is implemented as an Activity subclass, individual content panes can be implemented as Fragment subclasses. This maximizes code re-use across different form factors and across screens that share content.

Diseño para múltiples orientaciones de Tablet

Aunque no hemos empezado a colocar elementos de nuestro interfaz de usuario en nuestras pantallas todavia ,es un buen momento para considerar cómo tus pantallas de mulyi-pane se adaptarán a las distintas orientaciones de los dispositivos. Multi-pane layouts en landscape funcionan bastante bien because of the large amount of available horizontal space. Sin embargo , en la orientación portrait , your horizontal space is more limited, so you may need to design a separate layout for this orientation.

A continuación hay unas cuantas estrategias para crear portrait tablet layouts.

  • Stretch Stretch strategy La estrategia más directa es estrechar la anchura de cada uno de los panes cuando se presente el contenido en la orientación portrait. Los panes pueden tener anchuras fijas o tomar determinados porcentajes del espacio disponible de pantalla
  • Expand/collapse Expand/collapse strategy Una variación de la estrategia de estrechar es colapsar los contenidos del panel izquierdo cuando se pone en portrait. Esto funciona bien con master/detail panes donde el panel izquierdo contiene una lista de elementps fácilmente colapsables. Un ejemplo podría ser una aplicación de chat en tiempo real. En landscape , la lista izquierda podría contener las fotos , los nombres y el estado de los contactos. En portrait, el espacio horizontal puede ser colapsado escondiendo nombres de los contactos y sólo mostrando las fotos y los iconos indicadores de estado. Opcionalmente también proporcionar un control para poder expandir/esconder los contenidos del panel izquierdo.
  • Show/Hide Show/Hide strategy En este escenario, el panel izquierdo está completamente escondido en modo portrait. sin embargo, para asegurar la paridad funcionar de tu pantalla en portrait y landscape , el panel izquierdo debe estar disponible a través de algún tipo de control (como un botón). Es generalmente apropiado utilizar el botón Up del Action Bar (pattern docs at Android Design) para mostrar el panel izqdo, como se discutió en later lesson.
  • Stack Stack strategy The last strategy is to vertically stack your normally horizontally-arranged panes in portrait. This strategy works well when your panes aren’t simple text-based lists, or when there are multiple blocks of content running along the primary content pane. Be careful to avoid the awkward whitespace problem discussed above when using this strategy.

Agrupar Screen del Screen Map

Now that we are able to group individual screens together by providing multi-pane layouts on larger-screen devices, let’s apply this technique to our exhaustive screen map from the previous lesson to get a better sense of our application’s hierarchy on such devices:

Updated example news application screen map for tablets

Figure 3. Updated example news application screen map for tablets.

In the next lesson we discuss descendant and lateral navigation, and explore more ways of grouping screens to maximize the intuitiveness and speed of content access in the application’s user interface.

Providing Descendant and Lateral Navigation

THIS LESSON TEACHES YOU ABOUT:
  1. Buttons and Simple Targets
  2. Lists, Grids, Carousels, and Stacks
  3. Tabs
  4. Horizontal Paging (Swipe Views)

YOU SHOULD ALSO READ

Una forma de proporcionar acceso a un amplio rango de pantallas de la aplicación es reorganizarlas en una navegación jerárquica. En este apartado discutiremos la descendant navigation, permitiendo a los usuarios descender descend ‘down’ en la jerarquía de pantallas a una pantalla hija, y lateral navigation, permitiendo a los usuarios acceder a pantallas hermanas.

Descendant and lateral navigationFigure 1. Descendant and lateral navigation.

There are two types of sibling screens: collection-related and section-related screensCollection-related screens represent individual items in the collection represented by the parent. Section-related screens represent different sections of information about the parent. For example, one section may show textual information about an object while another may provide a map of the object’s geographic location. The number of section-related screens for a given parent is generally small.

Collection-related children and section-related childrenFigure 2. Collection-related children and section-related children.

Tanto la navegación descendente como la navegación lateral puede ser realizada utilizando listas , tabs , y otros patrones de interfaces.  User interface patterns, como los software design patterns, son comúnmente utilizados, common solutions to recurring interaction design problems. Exploraremos unos pocos lateral navigation patterns en los apartados siguientes.

Botones y Targets simples

Diseño de botones

For design guidelines, read Android Design’s Buttons guide.

For section-related screens, offering touchable and keyboard-focusable targets in the parent is generally the most straightforward and familiar kind of touch-based navigation interface. Examples of such targets include buttons, fixed-size list views, or text links, although the latter is not an ideal UI (user interface) element for touch-based navigation. Upon selecting one of these targets, the child screen is opened, replacing the current context (screen) entirely. Buttons and other simple targets are rarely used for representing items in a collection.

Example button-based navigation interface with relevant screen map excerpt. Also shows dashboard pattern discussed below.Figure 3. Example button-based navigation interface with relevant screen map excerpt. Also shows dashboard pattern discussed below.

A common, button-based pattern for accessing different top-level application sections, is the dashboard pattern. A dashboard is a grid of large, iconic buttons that constitutes the entirety, or most of, the parent screen. The grid generally has either 2 or 3 rows and columns, depending on the number of top-level sections in the app. This pattern is a great way to present all the sections of the app in a visually rich way. The large touch targets also make this UI very easy to use. Dashboards are best used when each section is equally important, as determined by product decisions or better yet, real-world usage. However, this pattern doesn’t visually work well on larger screens, and requires users to take an extra step to jump directly into the app’s content.

More sophisticated user interfaces can make use of a variety of other user interaction patterns to improve content immediacy and presentation uniqueness, all the while remaining intuitive.

Lists, Grids, Carousels, and Stacks

List and Grid List Design

For design guidelines, read Android Design’s Lists and Grid Lists guides.

For collection-related screens, and especially for textual information, vertically scrolling lists are often the most straightforward and familiar kind of interface. For more visual or media-rich content items such as photos or videos, vertically scrolling grids of items, horizontally scrolling lists (sometimes referred to as carousels), or stacks (sometimes referred to as cards) can be used instead. These UI elements are generally best used for presenting item collections or large sets of child screens (for example, a list of stories or a list of 10 or more news topics), rather than a small set of unrelated, sibling child screens.

Example list-, grid-, and carousel-based navigation interfaces with relevant screen map excerptFigure 4. Example list-, grid-, and carousel-based navigation interfaces with relevant screen map excerpt.

There are several issues with this pattern. Deep, list-based navigation, known as drill-down list navigation, where lists lead to more lists which lead to even more lists, is often inefficient and cumbersome. The number of touches required to access a piece of content with this kind of navigation is generally very high, leading to a poor user experience—especially for users on-the-go.

Using vertical lists can also lead to awkward user interactions and poor use of whitespace on larger screens, as list items generally span the entire width of the screen yet have a fixed height. One way to alleviate this is to provide additional information, such as text summaries, that fills the available horizontal space. Another way is to provide additional information in a separate horizontal pane adjacent to the list.

Tabs

Tab Design

For design guidelines, read Android Design’s Tabs guide.

Using tabs is a very popular solution for lateral navigation. This pattern allows grouping of sibling screens, in that the tab content container in the parent screen can embed child screens that otherwise would be entirely separate contexts. Tabs are most appropriate for small sets (4 or fewer) of section-related screens.

Example phone and tablet tab-based navigation interfaces with relevant screen map excerptFigure 5. Example phone and tablet tab-based navigation interfaces with relevant screen map excerpt.

Several best practices apply when using tabs. Tabs should be persistent across immediate related screens. Only the designated content region should change when selecting a tab, and tab indicators should remain available at all times. Additionally, tab switches should not be treated as history. For example, if a user switches from a tab A to another tab B, pressing the Back button (more on that in the next lesson) should not re-select tab A. Tabs are usually laid out horizontally, although other presentations of tab navigation such as using a drop-down list in the Action Bar (pattern docs at Android Design) are sometimes appropriate. Lastly, and most importantly, tabs should always run along the top of the screen, and should not be aligned to the bottom of the screen.

There are some obvious immediate benefits of tabs over simpler list- and button-based navigation:

  • Since there is a single, initially-selected tab, users have immediate access to that tab’s content from the parent screen.
  • Users can navigate quickly between related screens, without needing to first revisit the parent.Note: when switching tabs, it is important to maintain this tab-switching immediacy; do not block access to tab indicators by showing modal dialogs while loading content.

A common criticism is that space must be reserved for the tab indicators, detracting from the space available to tab contents. This consequence is usually acceptable, and the tradeoff commonly weighs in favor of using this pattern. You should also feel free to customize tab indicators, showing text and/or icons to make optimal use of vertical space. When adjusting indicator heights however, ensure that tab indicators are large enough for a human finger to touch without error.

Horizontal Paging (Swipe Views)

Swipe Views Design

For design guidelines, read Android Design’s Swipe Views pattern guides.

Another popular lateral navigation pattern is horizontal paging, also referred to as swipe views. This pattern applies best to collection-related sibling screens, such as a list of categories (world, business, technology, and health stories). Like tabs, this pattern also allows grouping screens in that the parent presents the contents of child screens embedded within its own layout.

Example horizontal paging navigation interface with relevant screen map excerptFigure 6. Example horizontal paging navigation interface with relevant screen map excerpt.

In a horizontal paging UI, a single child screen (referred to as a page here) is presented one at a time. Users are able to navigate to sibling screens by touching and dragging the screen horizontally in the direction of the desired adjacent page. This gestural interaction is often complemented by another UI element indicating the current page and available pages, to aid discoverability and provide more context to the user. This practice is especially necessary when using this pattern for lateral navigation of section-related sibling screens. Examples of such elements include tick marks, scrolling labels, and tabs.

Example paging companion UI elementsFigure 7. Example paging companion UI elements.

It’s also best to avoid this pattern when child screens contain horizontal panning surfaces (such as maps), as these conflicting interactions may deter your screen’s usability.

Additionally, for sibling-related screens, horizontal paging is most appropriate where there is some similarity in content type and when the number of siblings is relatively small. In these cases, this pattern can be used along with tabs above the content region to maximize the interface’s intuitiveness. For collection-related screens, horizontal paging is most intuitive when there is a natural ordered relationship between screens, for example if each page represents consecutive calendar days. For infinite collections (again, calendar days), especially those with content in both directions, this paging mechanism can work quite well.

In the next lesson, we discuss mechanisms for allowing users to navigate up our information hierarchy and back, to previously visited screens.

Providing Ancestral and Temporal Navigation

THIS LESSON TEACHES YOU TO:
  1. Support Temporal Navigation: Back
  2. Provide Ancestral Navigation: Up and Home

YOU SHOULD ALSO READ

Now that users can navigate deep into the application’s screen hierarchy, we need to provide a method for navigating up the hierarchy, to parent and ancestor screens. Additionally, we should ensure that temporal navigation via the Back button is respected to respect Android conventions.

Back/Up Navigation Design

For design guidelines, read Android Design’s Navigation pattern guide.

Support Temporal Navigation: Back


Temporal navigation, or navigation between historical screens, is deeply rooted in the Android system. All Android users expect the Back button to take them to the previous screen, regardless of other state. The set of historical screens is always rooted at the user’s Launcher application (the phone’s “home” screen). That is, pressing Back enough times should land you back at the Launcher, after which the Back button will do nothing.

The Back button behavior after entering the Email app from the People (or Contacts) appFigure 1. The Back button behavior after entering the Email app from the People (or Contacts) app.

Applications generally don’t have to worry about managing the Back button themselves; the system handles tasks and the back stack, or the list of previous screens, automatically. The Back button by default simply traverses this list of screens, removing the current screen from the list upon being pressed.

There are, however, cases where you may want to override the behavior for Back. For example, if your screen contains an embedded web browser where users can interact with page elements to navigate between web pages, you may wish to trigger the embedded browser’s default back behavior when users press the device’s Back button. Upon reaching the beginning of the browser’s internal history, you should always defer to the system’s default behavior for the Back button.

Provide Ancestral Navigation: Up and Home

Before Android 3.0, the most common form of ancestral navigation was the Home metaphor. This was generally implemented as a Home item accessible via the device’s Menu button, or a Home button at the top-left of the screen, usually as a component of the Action Bar (pattern docs at Android Design). Upon selecting Home, the user would be taken to the screen at the top of the screen hierarchy, generally known as the application’s home screen.

Providing direct access to the application’s home screen can give the user a sense of comfort and security. Regardless of where they are in the application, if they get lost in the app, they can select Home to arrive back at the familiar home screen.

Android 3.0 introduced the Up metaphor, which is presented in the Action Bar as a substitute for the Home button described above. Upon tapping Up, the user should be taken to the parent screen in the hierarchy. This navigation step is usually the previous screen (as described with the Back button discussion above), but this is not universally the case. Thus, developers must ensure that Up for each screen navigates to a single, predetermined parent screen.

Example behavior for UP navigation after entering the Email app from the People appFigure 2. Example behavior for up navigation after entering the Email app from the People app.

In some cases, it’s appropriate for Up to perform an action rather than navigating to a parent screen. Take for example, the Gmail application for Android 3.0-based tablets. When viewing a mail conversation while holding the device in landscape, the conversation list, as well as the conversation details are presented side-by-side. This is a form of parent-child screen grouping, as discussed in a previous lesson. However, when viewing a mail conversation in the portrait orientation, only the conversation details are shown. The Up button is used to temporarily show the parent pane, which slides in from the left of the screen. Pressing the Up button again while the left pane is visible exits the context of the individual conversation, up to a full-screen list of conversations.

Implementation Note: As a best practice, when implementing either Home or Up, make sure to clear the back stack of any descendent screens. For Home, the only remaining screen on the back stack should be the home screen. For Up navigation, the current screen should be removed from the back stack, unless Back navigates across screen hierarchies. You can use the FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_NEW_TASKintent flags together to achieve this.

In the last lesson, we apply the concepts discussed in all of the lessons so far to create interaction design wireframes for our example news application.

GAE: Google APIs Client Library for Python

[Fuente: https://developers.google.com/api-client-library/python/?hl=es]

Easily access Google APIs from Python

The Google APIs Client Library for Python provides access to many Google APIs. It is designed for Python client-application developers and offers a way to access APIs that is simple, flexible, and powerful. See the navigation sidebar for a list of guides, references, and other information.

Making it simple to call Google APIs

Use the simple and clean library to make calls from Python to an API.

# List my public Google+ activities.
result = service.activities().list(userId='me', collection='public').execute()
tasks = result.get('items', [])
for task in tasks:
  print task['title']

Easy authentication

The easy-to-use authentication library can reduce the amount of code you need to write to handle OAuth 2.0. Sometimes as little as a couple of lines is all you need.

# Authorize server-to-server interactions from Google Compute Engine.
from oauth2client import gce

credentials = gce.AppAssertionCredentials(
  scope='https://www.googleapis.com/auth/devstorage.read_write')
http = credentials.authorize(httplib2.Http())

Runs on Google App Engine

App Engine-specific helpers make quick work of authenticated calls to APIs. No need to worry about exchanging code for tokens; get right down to writing the meat of your application.

# Restrict access to users that have granted access to Calendar information.
decorator = appengine.OAuth2DecoratorFromClientSecrets(
  'client_secrets.json',
  scope='https://www.googleapis.com/auth/calendar')

class MainHandler(webapp.RequestHandler):
  @decorator.oauth_required
  def get(self):
    http = decorator.http()
    request = service.events().list(calendarId='primary')
    ...

Client library installation

Install the library using standard Python tools.

$ pip install --upgrade google-api-python-client

There are also custom installs optimized for Google App Engine.

Use the Quickstart guide to download a starter application for the API and platform you’re interested in:

Check out all the installation options.

Quickstart: Run a Gmail App in Python

Complete the steps described in the rest of this page, and in about five minutes you’ll have a simple app that uses the Gmail API to:

  1. Download a page of threads for the current user, and
  2. Output the ID for each thread

Contents

To run a quickstart example you’ll need:

  • Access to the internet and a web browser, in order to authorize the sample app.
  • A Google account for the Gmail address.
  • An environment to run programs in your selected language.

Step 1: Enable the Gmail API

To get started using Gmail API, you need to first create or select a project in the Google Developers Console and enable the API. Using this link guides you through the process and activates the Gmail API automatically.

Alternatively, you can activate the Gmail API yourself in the Developers Console by doing the following:

  1. Go to the Google Developers Console.
  2. Select a project, or create a new one.
  3. In the sidebar on the left, expand APIs & auth. Next, click APIs. In the list of APIs, make sure the status is ON for the Gmail API.
  4. In the sidebar on the left, select Credentials.

In either case, you end up on the Credentials page and can create your project’s credentials from here.

To find your application’s client ID and client secret, and set a redirect URI, expand the OAuth 2.0 Client ID section.

Click Download JSON to save the client secrets file, then place this file at a location where your app can easily access it.

Step 2: Set up the sample

You’ll need to create a source code file and then modify it to reference your app’s client secret file, as described below.

  1. Create a new file quickstart.py, then copy the source code below into it.
  2. Edit the source file to specify the correct CLIENT_SECRET_PATH: replace client_secret.json with the actual path to the client secret file that you downloaded in the “Enable the Gmail API” step.

 

#!/usr/bin/python

import httplib2

from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run


# Path to the client_secret.json file downloaded from the Developer Console
CLIENT_SECRET_FILE = 'client_secret.json'

# Check https://developers.google.com/gmail/api/auth/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.readonly'

# Location of the credentials storage file
STORAGE = Storage('gmail.storage')

# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(CLIENT_SECRET_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()

# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
  credentials = run(flow, STORAGE, http=http)

# Authorize the httplib2.Http object with our credentials
http = credentials.authorize(http)

# Build the Gmail service from discovery
gmail_service = build('gmail', 'v1', http=http)

# Retrieve a page of threads
threads = gmail_service.users().threads().list(userId='me').execute()

# Print ID for each thread
if threads['threads']:
  for thread in threads['threads']:
    print 'Thread ID: %s' % (thread['id'])

 

Step 3: Run the sample

When you run the sample from command line, it provides a link you’ll need to visit in order to authorize.

Run the sample using python quickstart.py.

  1. Browse to the provided URL in your web browser.
  2. If you are not already logged into your Google account, you will be prompted to log in. If you are logged into multiple Google accounts, you will be asked to select one account to use for the authorization.
  3. Copy the code you’re given after browsing to the link, and paste it into the prompt Enter authorization code:. Click Enter.

The application should display a list of thread IDs.

Next steps

If your goal is to expand the quickstart sample into something for your own installed application, consult the API Reference. The API Reference discusses all of the features of the Gmail API, and gives samples in each language on how to use a feature.

All requests to the Gmail API must be authorized by an authenticated user. To examine more authorization code and learn how to authorize requests, see Authorizing Your App with Gmail.

GAE: Python

[Fuente: https://developers.google.com/appengine/docs/python/gettingstartedpython27/introduction?hl=es]

Introduction

Welcome to Google App Engine! Creating an App Engine application is easy, and only takes a few minutes. And it’s free to start: upload your app and share it with users right away, at no charge and with no commitment required.

Google App Engine applications can be written in the Python 2.7, Java, Go or PHP programming languages. This tutorial covers Python 2.7. If you would prefer to use Java, Go or PHP to build your applications, see the JavaGo or PHP guides.

In this tutorial, you will learn how to:

  • build an App Engine application using Python
  • use the webapp2 web application framework
  • use the App Engine datastore with the Python modeling API
  • integrate an App Engine application with Google Accounts for user authentication
  • use Jinja2 templates with your app
  • upload your app to App Engine

By the end of the tutorial, you will have implemented a working application, a simple guest book that lets users post messages to a public message board.

Run/Modify

While going through this tutorial you will see buttons that allow you to test the code sample right in your browser in the Google Cloud Playground. These are labeled “Run/Modify.” You can even make changes to the code and see the results in real-time!

Get set up

Before we continue, you will need to download the Google App Engine Python SDK, which includes a web server application that simulates the App Engine environment, and tools to deploy your application to the App Engine production environment. Follow the directions for your operating system, then come back here so we can get going!

Hello, World!

Let’s begin by implementing a tiny application that displays a short message.

Creating a Simple Request Handler

Create a directory named helloworld. All files for this application reside in this directory.

Inside the helloworld directory, create a file named helloworld.py, and give it the following contents:

import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write('Hello, World!')

application = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)

This Python script responds to a request with an HTTP header that describes the content and the message Hello, World!.

Note: Ensure that you save the files you create as plain text. You may encounter errors otherwise.

Creating the Configuration File

An App Engine application has a configuration file called app.yaml. Among other things, this file describes which handler scripts should be used for which URLs.

Inside the helloworld directory, create a file named app.yaml with the following contents:

application: your-app-id
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /.*
  script: helloworld.application

From top to bottom, this configuration file says the following about this application:

  • The application identifier is your-app-id. Every new application on App Engine has a unique application identifier. You’ll choose the identifier for your application when you register it in the next step. Until then you can just leave the value here set to your-app-id because this value is not important when developing locally.
  • This is version number 1 of this application’s code. If you adjust this before uploading new versions of your application software, App Engine will retain previous versions, and let you roll back to a previous version using the administrative console.
  • This code runs in the python27 runtime environment, API version 1. Additional runtime environments and languages may be supported in the future.
  • This application is threadsafe so the same instance can handle several simultaneous requests. Threadsafe is an advanced feature and may result in erratic behavior if your application is not specifically designed to be threadsafe.
  • Every request to a URL whose path matches the regular expression /.* (all URLs) should be handled by the application object in the helloworld module.

The syntax of this file is YAML. For a complete list of configuration options, see the app.yaml reference.

Testing the Application

With a handler script and configuration file mapping every URL to the handler, the application is complete. You can now test it with the web server included with the App Engine SDK.

If you’re using the Google App Engine Launcher, you can set up the application by selecting the File menu, Add Existing Application…, then selecting the helloworld directory. Select the application in the app list, click the Run button to start the application, then click the Browse button to view it. Clicking Browse simply loads (or reloads) http://localhost:8080/ in your default web browser.

If you’re not using Google App Engine Launcher, start the web server with the following command, giving it the path to the helloworld directory:

google_appengine/dev_appserver.py helloworld/

The web server is now running, listening for requests on port 8080. You can test the application by visiting the following URL in your web browser:

For more information about running the development web server, including how to change which port it uses, see the Dev Web Server reference, or run the command with the option --help.

Iterative Development

You can leave the web server running while you develop your application. The web server knows to watch for changes in your source files and reload them if necessary.

Try it now: Leave the web server running, then edit helloworld.py to change Hello, World! to something else. Reload http://localhost:8080/ or click Browse in Google App Engine Launcher to see the change.

To shut down the web server, make sure the terminal window is active, then press Control-C (or the appropriate “break” key for your console), or click Stop in Google App Engine Launcher.

You can leave the web server running for the rest of this tutorial. If you need to stop it, you can restart it again by running the command above.

Explaining the webapp2 Framework

The Web Server Gateway Interface (WSGI) standard is simple, but it would be cumbersome to write all of the code that uses it by hand. Web application frameworks handle these details for you, so you can focus your development efforts on your application’s features. Google App Engine supports any framework written in pure Python that speaks WSGI, including DjangoCherryPyPylonsweb.py, and web2py. You can bundle a framework of your choosing with your application code by copying its code into your application directory.

App Engine includes a simple web application framework, called webapp2. The webapp2 framework is already installed in the App Engine environment and in the SDK, so you do not need to bundle it with your application code to use it. We will use webapp2 for the rest of this tutorial.

Hello, webapp2!

webapp2 application has two parts:

  • one or more RequestHandler classes that process requests and build responses
  • WSGIApplication instance that routes incoming requests to handlers based on the URL

Let’s take another look at our friendly greeting application:

import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write('Hello, World!')

application = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)

What webapp2 Does

This code defines one request handler, MainPage, mapped to the root URL (/). When webapp2 receives an HTTP GET request to the URL /, it instantiates the MainPage class and calls the instance’s get method. Inside the method, information about the request is available using self.request. Typically, the method sets properties on self.response to prepare the response, then exits. webapp2 sends a response based on the final state of the MainPage instance.

The application itself is represented by a webapp2.WSGIApplication instance. The parameter debug=true passed to its constructor tells webapp2 to print stack traces to the browser output if a handler encounters an error or raises an uncaught exception. You may wish to remove this option from the final version of your application.

We’ll use a few more features of webapp2 later in this tutorial. For more information about webapp2, see the webapp2 documentation

Using the Users Service

Google App Engine provides several useful services based on Google infrastructure, accessible by applications using libraries included with the SDK. One such service is the Users service, which lets your application integrate with Google user accounts. With the Users service, your users can use the Google accounts they already have to sign in to your application.

Let’s use the Users service to personalize this application’s greeting.

Using Users

Edit helloworld/helloworld.py again, and replace its contents with the following:

from google.appengine.api import users

import webapp2

class MainPage(webapp2.RequestHandler):

    def get(self):
        # Checks for active Google account session
        user = users.get_current_user()

        if user:
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.write('Hello, ' + user.nickname())
        else:
            self.redirect(users.create_login_url(self.request.uri))

application = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)

Reload the page in your browser. Your application redirects you to the local version of the Google sign-in page suitable for testing your application. You can enter any username you’d like in this screen, and your application will see a fake User object based on that username.

When your application is running on App Engine, users will be directed to the Google Accounts sign-in page, then redirected back to your application after successfully signing in or creating an account.

The Users API

Let’s take a closer look at the new pieces:

# Checks for active Google account session
user = users.get_current_user()

If the user is already signed in to your application, get_current_user() returns the User object for the user. Otherwise, it returns None.

if user:
    self.response.headers['Content-Type'] = 'text/plain'
    self.response.write('Hello, ' + user.nickname())

If the user has signed in, display a personalized message, using the nickname associated with the user’s account.

else:
    self.redirect(users.create_login_url(self.request

If the user has not signed in, tell webapp2 to redirect the user’s browser to the Google account sign-in screen. The redirect includes the URL to this page (self.request.uri) so the Google account sign-in mechanism will send the user back here after the user has signed in or registered for a new account.

For more information about the Users API, see the Users reference.

Handling Forms with webapp2

If we want users to be able to post their own greetings, we need a way to process information submitted by the user with a web form. The webapp2 framework makes processing form data easy.

From Hello World to Guestbook

In order to prepare the Hello World app we’ve created thus far, please make the following changes:

  • Rename the top level helloworld directory to guestbook
  • Rename helloworld.py to guestbook.py
  • Replace the handlers section of app.yaml with:
handlers:
- url: /.*
  script: guestbook.application

Restart the development server using the new guestbook directory.

Handling Web Forms With webapp2

Declare that you are using webapp2 by adding this libraries section to your app.yaml:

libraries:
- name: webapp2
  version: latest

Replace the contents of guestbook/guestbook.py with the following:

import cgi
from google.appengine.api import users
import webapp2

MAIN_PAGE_HTML = """\
<html>
  <body>
    <form action="/sign" method="post">
      <div><textarea name="content" rows="3" cols="60"></textarea></div>
      <div><input type="submit" value="Sign Guestbook"></div>
    </form>
  </body>
</html>
"""

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.write(MAIN_PAGE_HTML)

class Guestbook(webapp2.RequestHandler):
    def post(self):
        self.response.write('<html><body>You wrote:<pre>')
        self.response.write(cgi.escape(self.request.get('content')))
        self.response.write('</pre></body></html>')

application = webapp2.WSGIApplication([
    ('/', MainPage),
    ('/sign', Guestbook),
], debug=True)

Reload the page to see the form, then try submitting a message.

This version has two handlersMainPage, mapped to the URL /, displays a web form. Guestbook, mapped to the URL /sign, displays the data submitted by the web form.

The Guestbook handler has a post() method instead of a get() method. This is because the form displayed by MainPage uses the HTTP POST method (method="post") to submit the form data. If for some reason you need a single handler to handle both GET and POST actions to the same URL, you can define a method for each action in the same class.

The code for the post() method gets the form data from self.request. Before displaying it back to the user, it uses cgi.escape()to escape HTML special characters to their character entity equivalents. cgi is a module in the standard Python library; see the documentation for cgi for more information.

Using the Datastore

Storing data in a scalable web application can be tricky. A user could be interacting with any of dozens of web servers at a given time, and the user’s next request could go to a different web server than the previous request. All web servers need to be interacting with data that is also spread out across dozens of machines, possibly in different locations around the world.

With Google App Engine, you don’t have to worry about any of that. App Engine’s infrastructure takes care of all of the distribution, replication, and load balancing of data behind a simple API—and you get a powerful query engine and transactions as well.

App Engine’s data repository, the High Replication Datastore (HRD), uses the Paxos algorithm to replicate data across multiple datacenters. Data is written to the Datastore in objects known as entities. Each entity has a key that uniquely identifies it. An entity can optionally designate another entity as its parent; the first entity is a child of the parent entity. The entities in the Datastore thus form a hierarchically-structured space similar to the directory structure of a file system. An entity’s parent, parent’s parent, and so on recursively, are its ancestors; its children, children’s children, and so on, are its descendants. An entity without a parent is a root entity.

The Datastore is extremely resilient in the face of catastrophic failure, but its consistency guarantees may differ from what you’re familiar with. Entities descended from a common ancestor are said to belong to the same entity group; the common ancestor’s key is the group’s parent key, which serves to identify the entire group. Queries over a single entity group, called ancestor queries, refer to the parent key instead of a specific entity’s key. Entity groups are a unit of both consistency and transactionality: whereas queries over multiple entity groups may return stale, eventually consistent results, those limited to a single entity group always return up-to-date,strongly consistent results.

The sample application in this guide organizes related entities into entity groups, and uses ancestor queries on those entity groups to return strongly consistent results. In the example code comments, we highlight some ways this approach might affect the design of your application. For more detailed information, see Structuring Data for Strong Consistency.

A Complete Example Using the Datastore

Here is a new version of guestbook/guestbook.py that creates a page footer that stores greetings in the Datastore. The rest of this page discusses excerpts from this larger example, organized under the topics of storing the greetings and retrieving them.

import cgi
import urllib

from google.appengine.api import users
from google.appengine.ext import ndb

import webapp2

MAIN_PAGE_FOOTER_TEMPLATE = """\
    <form action="/sign?%s" method="post">
      <div><textarea name="content" rows="3" cols="60"></textarea></div>
      <div><input type="submit" value="Sign Guestbook"></div>
    </form>
    <hr>
    <form>Guestbook name:
      <input value="%s" name="guestbook_name">
      <input type="submit" value="switch">
    </form>
    <a href="%s">%s</a>
  </body>
</html>
"""

DEFAULT_GUESTBOOK_NAME = 'default_guestbook'

# We set a parent key on the 'Greetings' to ensure that they are all in the same
# entity group. Queries across the single entity group will be consistent.
# However, the write rate should be limited to ~1/second.

def guestbook_key(guestbook_name=DEFAULT_GUESTBOOK_NAME):
    """Constructs a Datastore key for a Guestbook entity with guestbook_name."""
    return ndb.Key('Guestbook', guestbook_name)

class Greeting(ndb.Model):
    """Models an individual Guestbook entry."""
    author = ndb.UserProperty()
    content = ndb.StringProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.write('<html><body>')
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)

        # Ancestor Queries, as shown here, are strongly consistent with the High
        # Replication Datastore. Queries that span entity groups are eventually
        # consistent. If we omitted the ancestor from this query there would be
        # a slight chance that Greeting that had just been written would not
        # show up in a query.
        greetings_query = Greeting.query(
            ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
        greetings = greetings_query.fetch(10)

        for greeting in greetings:
            if greeting.author:
                self.response.write(
                        '<b>%s</b> wrote:' % greeting.author.nickname())
            else:
                self.response.write('An anonymous person wrote:')
            self.response.write('<blockquote>%s</blockquote>' %
                                cgi.escape(greeting.content))

        if users.get_current_user():
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        # Write the submission form and the footer of the page
        sign_query_params = urllib.urlencode({'guestbook_name': guestbook_name})
        self.response.write(MAIN_PAGE_FOOTER_TEMPLATE %
                            (sign_query_params, cgi.escape(guestbook_name),
                             url, url_linktext))

class Guestbook(webapp2.RequestHandler):
    def post(self):
        # We set the same parent key on the 'Greeting' to ensure each Greeting
        # is in the same entity group. Queries across the single entity group
        # will be consistent. However, the write rate to a single entity group
        # should be limited to ~1/second.
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greeting = Greeting(parent=guestbook_key(guestbook_name))

        if users.get_current_user():
            greeting.author = users.get_current_user()

        greeting.content = self.request.get('content')
        greeting.put()

        query_params = {'guestbook_name': guestbook_name}
        self.redirect('/?' + urllib.urlencode(query_params))

application = webapp2.WSGIApplication([
    ('/', MainPage),
    ('/sign', Guestbook),
], debug=True)

Replace guestbook/guestbook.py with this, then reload http://localhost:8080/ in your browser. Post a few messages to verify that messages get stored and displayed correctly.

Warning! Exercising the queries in your application locally causes App Engine to create or update index.yaml. If index.yaml is missing or incomplete, you will see index errors when your uploaded application executes queries for which the necessary indexes have not been specified. To avoid missing index errors in production, always test new queries at least once locally before uploading your application. See Python Datastore Index Configuration for more information.

Storing the Submitted Greetings

App Engine includes a data modeling API for Python. It’s similar to Django’s data modeling API, but uses App Engine’s scalable Datastore behind the scenes.

To use the data modeling API, our example imports the google.appengine.ext.ndb module:

# Imports the NDB data modeling API
from google.appengine.ext import ndb

For the guestbook application, we want to store greetings posted by users. Each greeting includes the author’s name, the message content, and the date and time the message was posted so we can display messages in chronological order. The following code defines our data model:

class Greeting(ndb.Model):
    """Models an individual Guestbook entry."""
    author = ndb.UserProperty()
    content = ndb.StringProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)

This defines a Greeting model with three properties: author whose value is a google.appengine.api.user object, contentwhose value is a string, and date whose value is a datetime.datetime.

Some property constructors take parameters to further configure their behavior. Giving the ndb.StringProperty constructor the indexed=False parameter says that values for this property will not be indexed. This saves us writes which aren’t needed since we never use that property in a query. Giving the ndb.DateTimeProperty constructor an auto_now_add=True parameter configures the model to automatically give new objects a datetime stamp of the time the object is created, if the application doesn’t otherwise provide a value. For a complete list of property types and their options, see NDB Properties.

Now that we have a data model for greetings, the application can use the model to create new Greeting objects and put them into the Datastore. The Guestbook handler creates new greetings and saves them to the Datastore:

class Guestbook(webapp2.RequestHandler):
    def post(self):
        # We set the same parent key on the 'Greeting' to ensure each Greeting
        # is in the same entity group. Queries across the single entity group
        # will be consistent. However, the write rate to a single entity group
        # should be limited to ~1/second.
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greeting = Greeting(parent=guestbook_key(guestbook_name))

        if users.get_current_user():
            greeting.author = users.get_current_user()

        greeting.content = self.request.get('content')
        greeting.put()

        query_params = {'guestbook_name': guestbook_name}
        self.redirect('/?' + urllib.urlencode(query_params))

This Guestbook handler creates a new Greeting object, then sets its author and content properties with the data posted by the user. The parent of Greeting is a Guestbook entity. There’s no need to create the Guestbook entity before setting it to be the parent of another entity. In this example, the parent is used as a placeholder for transaction and consistency purposes. See the Transactions page for more information. Objects that share a common ancestor belong to the same entity group. It does not set the date property, so date is automatically set to the present, using auto_now_add=True, which we configured above.

Finally, greeting.put() saves our new object to the Datastore. If we had acquired this object from a query, put() would have updated the existing object. Since we created this object with the model constructor, put() adds the new object to the Datastore.

Because querying in the High Replication Datastore is strongly consistent only within entity groups, we assign all of one book’s greetings to the same entity group in this example by setting the same parent for each greeting. This means a user will always see a greeting immediately after it was written. However, the rate at which you can write to the same entity group is limited to 1 write to the entity group per second. When you design a real application you’ll need to keep this fact in mind. Note that by using services such as Memcache, you can mitigate the chance that a user won’t see fresh results when querying across entity groups immediately after a write.

Retrieving Submitted Greetings

The App Engine Datastore has a sophisticated query engine for data models. Because the App Engine Datastore is not a traditional relational database, queries are not specified using SQL. Instead, data is queried one of two ways: Either via Datastore queries, or using an SQL-like query language called GQL. To access the full range of Datastore query capabilities, we recommend using Datastore queries over GQL.

The MainPage handler retrieves and displays previously submitted greetings. The Datastore query happens here:

greetings_query = Greeting.query(
    ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
greetings = greetings_query.fetch(10)

A Word About Datastore Indexes

Every query in the App Engine Datastore is computed from one or more indexes—tables that map ordered property values to entity keys. This is how App Engine is able to serve results quickly regardless of the size of your application’s Datastore. Many queries can be computed from the builtin indexes, but for queries that are more complex the Datastore requires a custom index. Without a custom index, the Datastore can’t execute these queries efficiently.

For example, our guest book application above filters by guestbook and orders by date, using an ancestor query and a sort order. This requires a custom index to be specified in your application’s index.yaml file. You can edit this file manually or, as noted in the warning box earlier on this page, you can take care of it automatically by running the queries in your application locally. Once the index is defined in index.yaml, uploading your application will also upload your custom index information.

The definition for the query in your index.yaml file looks like this:

indexes:
- kind: Greeting
  ancestor: yes
  properties:
  - name: date
    direction: desc

You can read all about Datastore indexes in the Datastore Indexes page. You can read about the proper specification for your index.yaml file in Python Datastore Index Configuration.

Next…

We now have a working guest book application that authenticates users using Google accounts, lets them submit messages, and displays messages other users have left. Because App Engine handles scaling automatically, we will not need to revisit this code as our application gets popular.

This latest version mixes HTML content with the code for the MainPage handler. This will make it difficult to change the appearance of the application, especially as our application gets bigger and more complex. Let’s use templates to manage the appearance, and introduce static files for a CSS stylesheet.

Using Templates

HTML embedded in code is messy and difficult to maintain. It’s better to use a templating system, where the HTML is kept in a separate file with special syntax to indicate where the data from the application appears. There are many templating systems for Python: EZTCheetahClearSilverQuixoteDjango, and Jinja2 are just a few. You can use your template engine of choice by bundling it with your application code.

For your convenience, App Engine includes the Django and Jinja2 templating engines.

Using Jinja2 Templates

First modify the libraries section at the bottom of guestbook/app.yaml:

libraries:
- name: webapp2
  version: latest
- name: jinja2
  version: latest

This configuration makes the newest supported version of Jinja2 available to your application. To avoid possible compatibility issues, serious applications should use an actual version number rather than latest.

Now modify the statements at the top of guestbook/guestbook.py:

import os
import urllib

from google.appengine.api import users
from google.appengine.ext import ndb

import jinja2
import webapp2

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True)

Replace the MainPage handler with code that resembles the following:

class MainPage(webapp2.RequestHandler):

    def get(self):
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greetings_query = Greeting.query(
            ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
        greetings = greetings_query.fetch(10)

        if users.get_current_user():
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        template_values = {
            'greetings': greetings,
            'guestbook_name': urllib.quote_plus(guestbook_name),
            'url': url,
            'url_linktext': url_linktext,
        }

        template = JINJA_ENVIRONMENT.get_template('index.html')
        self.response.write(template.render(template_values))

Finally, create a new file in the guestbook directory named index.html, with the following contents:

<!DOCTYPE html>
{% autoescape true %}
<html>
  <body>
    {% for greeting in greetings %}
      {% if greeting.author %}
        <b>{{ greeting.author.nickname() }}</b> wrote:
      {% else %}
       An anonymous person wrote:
      {% endif %}
      <blockquote>{{ greeting.content }}</blockquote>
    {% endfor %}

    <form action="/sign?guestbook_name={{ guestbook_name }}" method="post">
      <div><textarea name="content" rows="3" cols="60"></textarea></div>
      <div><input type="submit" value="Sign Guestbook"></div>
    </form>

    <hr>

    <form>Guestbook name:
      <input value="{{ guestbook_name }}" name="guestbook_name">
      <input type="submit" value="switch">
    </form>

    <a href="{{ url|safe }}">{{ url_linktext }}</a>

  </body>
</html>
{% endautoescape %}

Reload the page, and try it out.

JINJA_ENVIRONMENT.get_template(name) takes the name of a template file, and returns a template object. template.render(template_values) takes a dictionary of values, and returns the rendered text. The template uses Jinja2 templating syntax to access and iterate over the values, and can refer to properties of those values. In many cases, you can pass datastore model objects directly as values, and access their properties from templates.

Tip: An App Engine application has read-only access to all of the files uploaded with the project, the library modules, and no other files. The current working directory is the application root directory, so the path to index.html is simply "index.html".

Other templating languages

This example was done in Jinja2, but we also have App Engine starter projects that use Flask and Bottle in the Google Developers Console.

Next…

Every web application returns dynamically generated HTML from the application code, via templates or some other mechanism. Most web applications also need to serve static content, such as images, CSS stylesheets, or JavaScript files. For efficiency, App Engine treats static files differently from application source and data files. You can use App Engine’s static files feature to serve a CSS stylesheet for this application.

Using Static Files

Unlike a traditional web hosting environment, Google App Engine does not serve files directly out of your application’s source directory unless configured to do so. We named our template file index.html, but this does not automatically make the file available at the URL /index.html.

But there are many cases where you want to serve static files directly to the web browser. Images, CSS stylesheets, JavaScript code, movies and Flash animations are all typically stored with a web application and served directly to the browser. App Engine can serve specific files directly without you having to code your own handler.

Using Static Files

Edit guestbook/app.yaml and replace its contents with the following:

application: your-app-id
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /stylesheets
  static_dir: stylesheets

- url: /.*
  script: guestbook.application

libraries:
- name: webapp2
  version: latest
- name: jinja2
  version: latest

The new handlers section defines two handlers for URLs. When App Engine receives a request with a URL beginning with/stylesheets, it maps the remainder of the path to files in the stylesheets directory and, if an appropriate file is found, the contents of the file are returned to the client. All other URLs match the / path, and are handled by the application object in theguestbook module.

By default, App Engine serves static files using a MIME type based on the filename extension. For example, a file with a name ending in .css will be served with a MIME type of text/css. You can configure explicit MIME types by using the mime_type setting when configuring your handlers in app.yaml.

URL handler path patterns are tested in the order they appear in app.yaml, from top to bottom. In this case, the /stylesheets pattern will match before the /.* pattern will for the appropriate paths. For more information on URL mapping and other options you can specify in app.yaml, see the app.yaml reference.

Note: You can specify http_headers settings in the static directory handler to supply custom headers in the responses returned by the handler. This is useful, for example, for including the `Access-Control-Allow-Origin` header required to support CORS. For more information, see the documentation for http_headers under Static file handlers.

Create the directory guestbook/stylesheets/. In this new directory, create a new file named main.css with the following contents:

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #DDDDDD;
}

Finally, edit guestbook/index.html and insert the following lines between the <html> and <body> tags at the top:

<head>
  <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" />
</head>

Reload the page in your browser. The new version uses the stylesheet.

Next…

The time has come to reveal your finished application to the world.

Uploading Your Application

You create and manage App Engine applications using the Google Developers Console. Once you have registered an application ID for your application, you upload it to your website using appcfg.py, a command-line tool provided in the SDK. Or, if you’re using Google App Engine Launcher, you can upload your application by clicking the Deploy button.

Note: Application IDs must begin with a letter. Once you register an application ID, you can delete it, but you can’t re-register that same application ID after it has been deleted. You can skip these next steps if you don’t want to register an ID at this time.

Note: If you have an App Engine Premier account, you can specify that your new application should reside in the European Union rather than the United States. Developers that do not have a Premier account need to fill out this form and enable billing for applications that should reside in the European Union.

Hosting applications in the European Union is especially useful if your users are closer to Europe than to the United States. There is less network latency and the End User Content will be stored at rest in the European Union. You must specify this location by clicking the “Edit” link in the “Location Options” section when you register the application; you cannot change it later.

Registering the Application

You create and manage App Engine applications from the Developers Console, at the following URL:

https://console.developers.google.com/

Google App Engine Launcher users can reach this URL by clicking the Dashboard button.

Sign in to App Engine using your Google account. If you do not have a Google account, you can create a Google account with an email address and password.

Note: You may have already created a project using the Google Developers Console. If this is the case, you do not have to create a new application. Your project has a title and an ID. In the instructions that follow, the project title and ID can be used wherever anapplication title and ID are mentioned. They are the same thing.

To create a new application, click the “Create an Application” button. Follow the instructions to register an application ID, a name unique to this application. If you elect to use the free appspot.com domain name, the full URL for the application will be http://your-app-id.appspot.com/. You can also purchase a top-level domain name for your app, or use one that you have already registered.

Note: The High Replication Datastore is required in order to use the Python 2.7 runtime. This is the default when creating new applications.

If you have an App Engine Premier account, you can specify that your new application should reside in the European Union rather than the United States. This is especially useful if your application’s users are closer to Europe than to the United States. There is less network latency and the End User Content will be stored at rest in the European Union. You must specify this location when you register the application; you cannot change it later. Click the Edit link in the Location Options section; select a location option, either United States or European Union.

Edit the app.yaml file, then change the value of the application: setting from your-app-id to your registered application ID.

Uploading the Application

To upload your finished application to Google App Engine, run the following command:

    appcfg.py update guestbook/

Or click Deploy in the Google App Engine Launcher and enter your Google username and password at the prompts.

If you work with the Git version control system, you can create a remote repository in Google’s cloud, and configure your development environment to deploy the latest version of your code each time you push it to that repository. See Using Git to Push and Deploy.

http://your-app-id.appspot.com

Note: The Datastore Indexes may take some time to generate before your application is available. You will receive a NeedIndexError when accessing your app if the indexes are still in the process of being generated. This is a transient error for the example, so try a little later if at first you receive this exception.

Congratulations!

You have completed this tutorial. For more information on the subjects covered here, see the rest of the App Engine documentation.

Android Fragments

[Fuente: http://developer.android.com/guide/components/fragments.html]

Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a “sub activity” that you can reuse in different activities).

A fragment must always be embedded in an activity and the fragment’s lifecycle is directly affected by the host activity’s lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that’s managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the Back button.

When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity’s view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity’s layout file, as a <fragment> element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.

This document describes how to build your application to use fragments, including how fragments can maintain their state when added to the activity’s back stack, share events with the activity and other fragments in the activity, contribute to the activity’s action bar, and more.

Design Philosophy


Android introduced fragments in Android 3.0 (API level 11), primarily to support more dynamic and flexible UI designs on large screens, such as tablets. Because a tablet’s screen is much larger than that of a handset, there’s more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity’s appearance at runtime and preserve those changes in a back stack that’s managed by the activity.

For example, a news application can use one fragment to show a list of articles on the left and another fragment to display an article on the right—both fragments appear in one activity, side by side, and each fragment has its own set of lifecycle callback methods and handle their own user input events. Thus, instead of using one activity to select an article and another activity to read the article, the user can select an article and read it all within the same activity, as illustrated in the tablet layout in figure 1.

You should design each fragment as a modular and reusable activity component. That is, because each fragment defines its own layout and its own behavior with its own lifecycle callbacks, you can include one fragment in multiple activities, so you should design for reuse and avoid directly manipulating one fragment from another fragment. This is especially important because a modular fragment allows you to change your fragment combinations for different screen sizes. When designing your application to support both tablets and handsets, you can reuse your fragments in different layout configurations to optimize the user experience based on the available screen space. For example, on a handset, it might be necessary to separate fragments to provide a single-pane UI when more than one cannot fit within the same activity.

Figure 1. An example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.

For example—to continue with the news application example—the application can embed two fragments in Activity A, when running on a tablet-sized device. However, on a handset-sized screen, there’s not enough room for both fragments, so Activity A includes only the fragment for the list of articles, and when the user selects an article, it starts Activity B, which includes the second fragment to read the article. Thus, the application supports both tablets and handsets by reusing fragments in different combinations, as illustrated in figure 1.

For more information about designing your application with different fragment combinations for different screen configurations, see the guide to Supporting Tablets and Handsets.

Creating a Fragment


Figure 2. The lifecycle of a fragment (while its activity is running).

Para crear un fragment debemos crear una subclase de  Fragment (o de una subclase existente). La clase Fragment tiene el mismo código de un Activity. Contiene los métodos callback similares a los de una actividad , tales como  onCreate()onStart()onPause(), and onStop(). De hecho , si estás convirtiendo una aplicación Android ya existente para que utilice fragments, se puede perfectamente mover el código de los métodos callback de tu activity a los respectivos de tu fragment.

Generalmente , debes implementar al menos los siguientes métodos del ciclo de vida:

onCreate()
El sistema llama a este método cuando crea el fragment. Dentro de tu implementación, debes inicializar componentes esenciales del fragment que quieres retener cuando el fragment es pausado , parado y entonces vuelta a ser resumido.
onCreateView()
El sistema llama a este método cuando es momento de que el fragment dibuje el interfaz de usuario la primera vez. Para dibujar un UI de tu fragment , debes retornar una View con este método que será la raíz de tu fragment layout. Puedes retornar null si el fragment no tiene UI.
onPause()
El sistema invoca a este método en el momento que el usuario esta saliendo del fragment (y esto no siempre significa que el fragment sea destruido). Esto es generalmente donde debes comitear cualquier cambio que debe ser persistido mas allá de la sesión del  usuario actual (debido a que el usuario puede que no vuelva a esta pantalla).

La mayoría de las aplicaciones deben implementar al menos estos tres métodos para cada fragment, pero hay otros cuantos métodos callback que debes utilizar para manejar varios estados del ciclo de vida del fragment

Most applications should implement at least these three methods for every fragment, but there are several other callback methods you should also use to handle various stages of the fragment lifecycle. All the lifecycle callback methods are discussed in more detail in the section about Handling the Fragment Lifecycle.

There are also a few subclasses that you might want to extend, instead of the base Fragment class:

DialogFragment
Displays a floating dialog. Using this class to create a dialog is a good alternative to using the dialog helper methods in the Activity class, because you can incorporate a fragment dialog into the back stack of fragments managed by the activity, allowing the user to return to a dismissed fragment.
ListFragment
Displays a list of items that are managed by an adapter (such as a SimpleCursorAdapter), similar toListActivity. It provides several methods for managing a list view, such as the onListItemClick()callback to handle click events.
PreferenceFragment
Displays a hierarchy of Preference objects as a list, similar to PreferenceActivity. This is useful when creating a “settings” activity for your application.

Adding a user interface

A fragment is usually used as part of an activity’s user interface and contributes its own layout to the activity.

To provide a layout for a fragment, you must implement the onCreateView() callback method, which the Android system calls when it’s time for the fragment to draw its layout. Your implementation of this method must return a View that is the root of your fragment’s layout.

Note: If your fragment is a subclass of ListFragment, the default implementation returns a ListView from onCreateView(), so you don’t need to implement it.

To return a layout from onCreateView(), you can inflate it from a layout resource defined in XML. To help you do so, onCreateView() provides a LayoutInflater object.

For example, here’s a subclass of Fragment that loads a layout from the example_fragment.xml file:

public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

Creating a layout

In the sample above,R.layout.example_fragment is a reference to a layout resource named example_fragment.xml saved in the application resources. For information about how to create a layout in XML, see the User Interface documentation.

The container parameter passed to onCreateView() is the parent ViewGroup (from the activity’s layout) in which your fragment layout will be inserted. The savedInstanceState parameter is a Bundle that provides data about the previous instance of the fragment, if the fragment is being resumed (restoring state is discussed more in the section about Handling the Fragment Lifecycle).

The inflate() method takes three arguments:

  • The resource ID of the layout you want to inflate.
  • The ViewGroup to be the parent of the inflated layout. Passing the container is important in order for the system to apply layout parameters to the root view of the inflated layout, specified by the parent view in which it’s going.
  • A boolean indicating whether the inflated layout should be attached to the ViewGroup (the second parameter) during inflation. (In this case, this is false because the system is already inserting the inflated layout into the container—passing true would create a redundant view group in the final layout.)

Now you’ve seen how to create a fragment that provides a layout. Next, you need to add the fragment to your activity.

Adding a fragment to an activity

Usually, a fragment contributes a portion of UI to the host activity, which is embedded as a part of the activity’s overall view hierarchy. There are two ways you can add a fragment to the activity layout:

  • Declare the fragment inside the activity’s layout file.In this case, you can specify layout properties for the fragment as if it were a view. For example, here’s the layout file for an activity with two fragments:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <fragment android:name="com.example.news.ArticleListFragment"
                android:id="@+id/list"
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="match_parent" />
        <fragment android:name="com.example.news.ArticleReaderFragment"
                android:id="@+id/viewer"
                android:layout_weight="2"
                android:layout_width="0dp"
                android:layout_height="match_parent" />
    </LinearLayout>

    The android:name attribute in the <fragment> specifies the Fragment class to instantiate in the layout.

    When the system creates this activity layout, it instantiates each fragment specified in the layout and calls the onCreateView() method for each one, to retrieve each fragment’s layout. The system inserts the View returned by the fragment directly in place of the <fragment> element.

    Note: Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment:

    • Supply the android:id attribute with a unique ID.
    • Supply the android:tag attribute with a unique string.
    • If you provide neither of the previous two, the system uses the ID of the container view.
  • Or, programmatically add the fragment to an existing ViewGroup.At any time while your activity is running, you can add fragments to your activity layout. You simply need to specify a ViewGroup in which to place the fragment.To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from FragmentTransaction. You can get an instance of FragmentTransaction from your Activity like this:
    FragmentManager fragmentManager = getFragmentManager()
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    You can then add a fragment using the add() method, specifying the fragment to add and the view in which to insert it. For example:

    ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();

    The first argument passed to add() is the ViewGroup in which the fragment should be placed, specified by resource ID, and the second parameter is the fragment to add.

    Once you’ve made your changes with FragmentTransaction, you must call commit() for the changes to take effect.

Adding a fragment without a UI

The examples above show how to add a fragment to your activity in order to provide a UI. However, you can also use a fragment to provide a background behavior for the activity without presenting additional UI.

To add a fragment without a UI, add the fragment from the activity using add(Fragment, String) (supplying a unique string “tag” for the fragment, rather than a view ID). This adds the fragment, but, because it’s not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don’t need to implement that method.

Supplying a string tag for the fragment isn’t strictly for non-UI fragments—you can also supply string tags to fragments that do have a UI—but if the fragment does not have a UI, then the string tag is the only way to identify it. If you want to get the fragment from the activity later, you need to use findFragmentByTag().

For an example activity that uses a fragment as a background worker, without a UI, see the FragmentRetainInstance.java sample.

Managing Fragments


To manage the fragments in your activity, you need to use FragmentManager. To get it, call getFragmentManager() from your activity.

Some things that you can do with FragmentManager include:

For more information about these methods and others, refer to the FragmentManager class documentation.

As demonstrated in the previous section, you can also use FragmentManager to open a FragmentTransaction, which allows you to perform transactions, such as add and remove fragments.

Performing Fragment Transactions


A great feature about using fragments in your activity is the ability to add, remove, replace, and perform other actions with them, in response to user interaction. Each set of changes that you commit to the activity is called a transaction and you can perform one using APIs in FragmentTransaction. You can also save each transaction to a back stack managed by the activity, allowing the user to navigate backward through the fragment changes (similar to navigating backward through activities).

You can acquire an instance of FragmentTransaction from the FragmentManager like this:

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Each transaction is a set of changes that you want to perform at the same time. You can set up all the changes you want to perform for a given transaction using methods such as add()remove(), and replace(). Then, to apply the transaction to the activity, you must call commit().

Before you call commit(), however, you might want to call addToBackStack(), in order to add the transaction to a back stack of fragment transactions. This back stack is managed by the activity and allows the user to return to the previous fragment state, by pressing the Back button.

For example, here’s how you can replace one fragment with another, and preserve the previous state in the back stack:

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

In this example, newFragment replaces whatever fragment (if any) is currently in the layout container identified by the R.id.fragment_container ID. By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the Backbutton.

If you add multiple changes to the transaction (such as another add() or remove()) and calladdToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and the Back button will reverse them all together.

The order in which you add changes to a FragmentTransaction doesn’t matter, except:

  • You must call commit() last
  • If you’re adding multiple fragments to the same container, then the order in which you add them determines the order they appear in the view hierarchy

If you do not call addToBackStack() when you perform a transaction that removes a fragment, then that fragment is destroyed when the transaction is committed and the user cannot navigate back to it. Whereas, if you do call addToBackStack() when removing a fragment, then the fragment is stopped and will be resumed if the user navigates back.

Tip: For each fragment transaction, you can apply a transition animation, by calling setTransition()before you commit.

Calling commit() does not perform the transaction immediately. Rather, it schedules it to run on the activity’s UI thread (the “main” thread) as soon as the thread is able to do so. If necessary, however, you may call executePendingTransactions() from your UI thread to immediately execute transactions submitted by commit(). Doing so is usually not necessary unless the transaction is a dependency for jobs in other threads.

Caution: You can commit a transaction using commit() only prior to the activity saving its state (when the user leaves the activity). If you attempt to commit after that point, an exception will be thrown. This is because the state after the commit can be lost if the activity needs to be restored. For situations in which its okay that you lose the commit, use commitAllowingStateLoss().

Communicating with the Activity


Although a Fragment is implemented as an object that’s independent from an Activity and can be used inside multiple activities, a given instance of a fragment is directly tied to the activity that contains it.

Specifically, the fragment can access the Activity instance with getActivity() and easily perform tasks such as find a view in the activity layout:

View listView = getActivity().findViewById(R.id.list);

Likewise, your activity can call methods in the fragment by acquiring a reference to the Fragment fromFragmentManager, using findFragmentById() or findFragmentByTag(). For example:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

Creating event callbacks to the activity

In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary.

For example, if a news application has two fragments in an activity—one to show a list of articles (fragment A) and another to display an article (fragment B)—then fragment A must tell the activity when a list item is selected so that it can tell fragment B to display the article. In this case, the OnArticleSelectedListener interface is declared inside fragment A:

public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

Then the activity that hosts the fragment implements the OnArticleSelectedListener interface and overrides onArticleSelected() to notify fragment B of the event from fragment A. To ensure that the host activity implements this interface, fragment A’s onAttach() callback method (which the system calls when adding the fragment to the activity) instantiates an instance of OnArticleSelectedListener by casting the Activity that is passed into onAttach():

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

If the activity has not implemented the interface, then the fragment throws a ClassCastException. On success, the mListener member holds a reference to activity’s implementation of OnArticleSelectedListener, so that fragment A can share events with the activity by calling methods defined by the OnArticleSelectedListener interface. For example, if fragment A is an extension of ListFragment, each time the user clicks a list item, the system calls onListItemClick() in the fragment, which then calls onArticleSelected() to share the event with the activity:

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

The id parameter passed to onListItemClick() is the row ID of the clicked item, which the activity (or other fragment) uses to fetch the article from the application’s ContentProvider.

More information about using a content provider is available in the Content Providers document.

Adding items to the Action Bar

Your fragments can contribute menu items to the activity’s Options Menu (and, consequently, the Action Bar) by implementing onCreateOptionsMenu(). In order for this method to receive calls, however, you must call setHasOptionsMenu() during onCreate(), to indicate that the fragment would like to add items to the Options Menu (otherwise, the fragment will not receive a call to onCreateOptionsMenu()).

Any items that you then add to the Options Menu from the fragment are appended to the existing menu items. The fragment also receives callbacks to onOptionsItemSelected() when a menu item is selected.

You can also register a view in your fragment layout to provide a context menu by calling registerForContextMenu(). When the user opens the context menu, the fragment receives a call to onCreateContextMenu(). When the user selects an item, the fragment receives a call to onContextItemSelected().

Note: Although your fragment receives an on-item-selected callback for each menu item it adds, the activity is first to receive the respective callback when the user selects a menu item. If the activity’s implementation of the on-item-selected callback does not handle the selected item, then the event is passed to the fragment’s callback. This is true for the Options Menu and context menus.

For more information about menus, see the Menus and Action Bar developer guides.

Handling the Fragment Lifecycle


Figure 3. The effect of the activity lifecycle on the fragment lifecycle.

Managing the lifecycle of a fragment is a lot like managing the lifecycle of an activity. Like an activity, a fragment can exist in three states:

Resumed
The fragment is visible in the running activity.
Paused
Another activity is in the foreground and has focus, but the activity in which this fragment lives is still visible (the foreground activity is partially transparent or doesn’t cover the entire screen).
Stopped
The fragment is not visible. Either the host activity has been stopped or the fragment has been removed from the activity but added to the back stack. A stopped fragment is still alive (all state and member information is retained by the system). However, it is no longer visible to the user and will be killed if the activity is killed.

Also like an activity, you can retain the state of a fragment using a Bundle, in case the activity’s process is killed and you need to restore the fragment state when the activity is recreated. You can save the state during the fragment’s onSaveInstanceState() callback and restore it during either onCreate()onCreateView(), or onActivityCreated(). For more information about saving state, see the Activities document.

The most significant difference in lifecycle between an activity and a fragment is how one is stored in its respective back stack. An activity is placed into a back stack of activities that’s managed by the system when it’s stopped, by default (so that the user can navigate back to it with the Back button, as discussed in Tasks and Back Stack). However, a fragment is placed into a back stack managed by the host activity only when you explicitly request that the instance be saved by calling addToBackStack() during a transaction that removes the fragment.

Otherwise, managing the fragment lifecycle is very similar to managing the activity lifecycle. So, the same practices for managing the activity lifecycle also apply to fragments. What you also need to understand, though, is how the life of the activity affects the life of the fragment.

Caution: If you need a Context object within your Fragment, you can call getActivity(). However, be careful to call getActivity() only when the fragment is attached to an activity. When the fragment is not yet attached, or was detached during the end of its lifecycle, getActivity() will return null.

Coordinating with the activity lifecycle

The lifecycle of the activity in which the fragment lives directly affects the lifecycle of the fragment, such that each lifecycle callback for the activity results in a similar callback for each fragment. For example, when the activity receives onPause(), each fragment in the activity receives onPause().

Fragments have a few extra lifecycle callbacks, however, that handle unique interaction with the activity in order to perform actions such as build and destroy the fragment’s UI. These additional callback methods are:

onAttach()
Called when the fragment has been associated with the activity (the Activity is passed in here).
onCreateView()
Called to create the view hierarchy associated with the fragment.
onActivityCreated()
Called when the activity’s onCreate() method has returned.
onDestroyView()
Called when the view hierarchy associated with the fragment is being removed.
onDetach()
Called when the fragment is being disassociated from the activity.

The flow of a fragment’s lifecycle, as it is affected by its host activity, is illustrated by figure 3. In this figure, you can see how each successive state of the activity determines which callback methods a fragment may receive. For example, when the activity has received its onCreate() callback, a fragment in the activity receives no more than the onActivityCreated() callback.

Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently.

However, when the activity leaves the resumed state, the fragment again is pushed through its lifecycle by the activity.

Example


To bring everything discussed in this document together, here’s an example of an activity using two fragments to create a two-pane layout. The activity below includes one fragment to show a list of Shakespeare play titles and another to show a summary of the play when selected from the list. It also demonstrates how to provide different configurations of the fragments, based on the screen configuration.

Note: The complete source code for this activity is available in FragmentLayout.java.

The main activity applies a layout in the usual way, during onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.fragment_layout);
}

The layout applied is fragment_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
            android:id="@+id/titles" android:layout_weight="1"
            android:layout_width="0px" android:layout_height="match_parent" />

    <FrameLayout android:id="@+id/details" android:layout_weight="1"
            android:layout_width="0px" android:layout_height="match_parent"
            android:background="?android:attr/detailsElementBackground" />

</LinearLayout>

Using this layout, the system instantiates the TitlesFragment (which lists the play titles) as soon as the activity loads the layout, while the FrameLayout (where the fragment for showing the play summary will go) consumes space on the right side of the screen, but remains empty at first. As you’ll see below, it’s not until the user selects an item from the list that a fragment is placed into the FrameLayout.

However, not all screen configurations are wide enough to show both the list of plays and the summary, side by side. So, the layout above is used only for the landscape screen configuration, by saving it at res/layout-land/fragment_layout.xml.

Thus, when the screen is in portrait orientation, the system applies the following layout, which is saved atres/layout/fragment_layout.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
            android:id="@+id/titles"
            android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>

This layout includes only TitlesFragment. This means that, when the device is in portrait orientation, only the list of play titles is visible. So, when the user clicks a list item in this configuration, the application will start a new activity to show the summary, instead of loading a second fragment.

Next, you can see how this is accomplished in the fragment classes. First is TitlesFragment, which shows the list of Shakespeare play titles. This fragment extends ListFragment and relies on it to handle most of the list view work.

As you inspect this code, notice that there are two possible behaviors when the user clicks a list item: depending on which of the two layouts is active, it can either create and display a new fragment to show the details in the same activity (adding the fragment to the FrameLayout), or start a new activity (where the fragment can be shown).

public static class TitlesFragment extends ListFragment {
    boolean mDualPane;
    int mCurCheckPosition = 0;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // Populate list with our static array of titles.
        setListAdapter(new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));

        // Check to see if we have a frame in which to embed the details
        // fragment directly in the containing UI.
        View detailsFrame = getActivity().findViewById(R.id.details);
        mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;

        if (savedInstanceState != null) {
            // Restore last state for checked position.
            mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
        }

        if (mDualPane) {
            // In dual-pane mode, the list view highlights the selected item.
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            // Make sure our UI is in the correct state.
            showDetails(mCurCheckPosition);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("curChoice", mCurCheckPosition);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        showDetails(position);
    }

    /**
     * Helper function to show the details of a selected item, either by
     * displaying a fragment in-place in the current UI, or starting a
     * whole new activity in which it is displayed.
     */
    void showDetails(int index) {
        mCurCheckPosition = index;

        if (mDualPane) {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is currently shown, replace if needed.
            DetailsFragment details = (DetailsFragment)
                    getFragmentManager().findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index) {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                if (index == 0) {
                    ft.replace(R.id.details, details);
                } else {
                    ft.replace(R.id.a_item, details);
                }
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        } else {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }
}

The second fragment, DetailsFragment shows the play summary for the item selected from the list fromTitlesFragment:

public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist.  The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // won't be displayed.  Note this is not needed -- we could
            // just run the code below, where we would create and return
            // the view hierarchy; it would just never be used.
            return null;
        }

        ScrollView scroller = new ScrollView(getActivity());
        TextView text = new TextView(getActivity());
        int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                4, getActivity().getResources().getDisplayMetrics());
        text.setPadding(padding, padding, padding, padding);
        scroller.addView(text);
        text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
        return scroller;
    }
}

Recall from the TitlesFragment class, that, if the user clicks a list item and the current layout does not include the R.id.details view (which is where the DetailsFragment belongs), then the application starts theDetailsActivity activity to display the content of the item.

Here is the DetailsActivity, which simply embeds the DetailsFragment to display the selected play summary when the screen is in portrait orientation:

public static class DetailsActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE) {
            // If the screen is now in landscape mode, we can show the
            // dialog in-line with the list so we don't need this activity.
            finish();
            return;
        }

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
        }
    }
}

Notice that this activity finishes itself if the configuration is landscape, so that the main activity can take over and display the DetailsFragment alongside the TitlesFragment. This can happen if the user begins theDetailsActivity while in portrait orientation, but then rotates to landscape (which restarts the current activity).

For more samples using fragments (and complete source files for this example), see the API Demos sample app available in ApiDemos (available for download from the Samples SDK component).

AngularJS: Dependency injection

[Fuente: https://docs.angularjs.org/guide/di]

Dependency Injection

Dependency Injection (DI) is a software design pattern that deals with how components get hold of their dependencies.

The Angular injector subsystem is in charge of creating components, resolving their dependencies, and providing them to other components as requested.

For in-depth discussion about DI, see Dependency Injection at Wikipedia, Inversion of Control by Martin Fowler, or read about DI in your favorite software design pattern book.

DI in a Nutshell

There are only three ways a component (object or function) can get a hold of its dependencies:

  1. The component can create the dependency, typically using the new operator.
  2. The component can look up the dependency, by referring to a global variable.
  3. The component can have the dependency passed to it where it is needed.

The first two options of creating or looking up dependencies are not optimal because they hard code the dependency to the component. This makes it difficult, if not impossible, to modify the dependencies. This is especially problematic in tests, where it is often desirable to provide mock dependencies for test isolation.

The third option is the most viable, since it removes the responsibility of locating the dependency from the component. The dependency is simply handed to the component.

function SomeClass(greeter) {
  this.greeter = greeter;
}

SomeClass.prototype.doSomething = function(name) {
  this.greeter.greet(name);
}

In the above example SomeClass is not concerned with creating or locating the greeter dependency, it is simply handed the greeter when it is instantiated.

This is desirable, but it puts the responsibility of getting hold of the dependency on the code that constructs SomeClass.

To manage the responsibility of dependency creation, each Angular application has an injector. The injector is a service locator that is responsible for construction and lookup of dependencies.

Here is an example of using the injector service:

// Provide the wiring information in a module
var myModule = angular.module('myModule', []);

Teach the injector how to build a greeter service. Notice that greeter is dependent on the $window service. The greeter service is an object that contains a greet method.

myModule.factory('greeter', function($window) {
  return {
    greet: function(text) {
      $window.alert(text);
    }
  };
});

Create a new injector that can provide components defined in our myModule module and request our greeter service from the injector. (This is usually done automatically by angular bootstrap).

var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');

Asking for dependencies solves the issue of hard coding, but it also means that the injector needs to be passed throughout the application. Passing the injector breaks the Law of Demeter. To remedy this, we use a declarative notation in our HTML templates, to hand the responsibility of creating components over to the injector, as in this example:

<div ng-controller="MyController">
  <button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
  $scope.sayHello = function() {
    greeter.greet('Hello World');
  };
}

When Angular compiles the HTML, it processes the ng-controller directive, which in turn asks the injector to create an instance of the controller and its dependencies.

injector.instantiate(MyController);

This is all done behinds the scenes. Notice that by having the ng-controller ask the injector to instantiate the class, it can satisfy all of the dependencies of MyController without the controller ever knowing about the injector.

This is the best outcome. The application code simply declares the dependencies it needs, without having to deal with the injector. This setup does not break the Law of Demeter.

Dependency Annotation

How does the injector know what components need to be injected?

The application developer needs to provide annotation information that the injector uses in order to resolve the dependencies. Throughout Angular, certain API functions are invoked using the injector, as per the API documentation. The injector needs to know what services to inject into the function. There are three equivalent ways of annotating your code with service name information:

  • Implicitly from the function parameter names
  • Using the $inject property annotation
  • Using the inline array annotation

These can be used interchangeably as you see fit and are equivalent.

Implicit Dependencies

The simplest way to get hold of the dependencies, is to assume that the function parameter names are the names of the dependencies.

function MyController($scope, greeter) {
  // ...
}

Given a function the injector can infer the names of the service to inject by examining the function declaration and extracting the parameter names. In the above example $scope, and greeter are two services which need to be injected into the function.

While straightforward, this method will not work with JavaScript minifiers/obfuscators as they rename the method parameter names. This makes this way of annotating only useful for pretotyping, and demo applications.

$inject Property Annotation

To allow the minifiers to rename the function parameters and still be able to inject right services, the function needs to be annotated with the $inject property. The $inject property is an array of service names to inject.

var MyController = function(renamed$scope, renamedGreeter) {
  ...
}
MyController['$inject'] = ['$scope', 'greeter'];

In this scenario the ordering of the values in the $inject array must match the ordering of the arguments to inject. Using above code snippet as an example, $scope will be injected into renamed$scope and greeter into renamedGreeter. Care must be taken that the $inject annotation is kept in sync with the actual arguments in the function declaration.

This method of annotation is useful for controller declarations since it assigns the annotation information with the function.

Inline Array Annotation

Sometimes using the $inject annotation style is not convenient such as when annotating directives or services defined inline by a factory function.

For example:

someModule.factory('greeter', function($window) {
  // ...
});

Results in code bloat due to needing a temporary variable:

var greeterFactory = function(renamed$window) {
  // ...
};

greeterFactory.$inject = ['$window'];

someModule.factory('greeter', greeterFactory);

For this reason the third annotation style is provided as well.

someModule.factory('greeter', ['$window', function(renamed$window) {
  // ...
}]);

Here, instead of simply providing the factory function, we pass an array, whose elements consist of a list of strings (the names of the dependencies) followed by the function itself.

Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular where injection is supported.

Where Can I Use DI?

DI is pervasive throughout Angular. You can use it when defining components or when providing run and config blocks for a module.

  • Components such as services, directives, filters and animations are defined by an injectable factory method or constructor function. These components can be injected with “service” and “value” components as dependencies.
  • The run method accepts a function, which can be injected with “service”, “value” and “constant” components as dependencies. Note that you cannot inject “providers” into run blocks.
  • The config method accepts a function, which can be injected with “provider” and “constant” components as dependencies. Note that you cannot inject “service” or “value” components into configuration
  • Controllers are defined by a constructor function, which can be injected with any of the “service” and “value” components as dependencies, but they can also be provided with special dependencies. See Controllers below for a list of these special dependencies.

See Modules for more details about injecting dependencies into run and config blocks.

Factory Methods

Factory methods are responsible for creating most objects in Angular. Examples are directives, services, and filters. The factory methods are registered with the module, and the recommended way of declaring factories is:

angular.module('myModule', [])
  .factory('serviceId', ['depService', function(depService) {
    ...
  }])
  .directive('directiveName', ['depService', function(depService) {
    ...
  }])
  .filter('filterName', ['depService', function(depService) {
    ...
  }]);

Module Methods

We can specify functions to run at configuration and run time for a module by calling the run and config methods. These functions are injectable with dependencies just like the factory functions above.

angular.module('myModule', [])
  .config(['depProvider', function(depProvider){
    ...
  }])
  .run(['depService', function(depService) {
    ...
  }]);

Controllers

Controllers are “classes” or “constructor functions” that are responsible for providing the application behavior that supports the declarative markup in the template. The recommended way of declaring Controllers is using the array notation:

someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
}]);

This avoids the creation of global functions for controllers and also protects against minification.

Controllers are special in that, unlike services, there can be many instances of them in the application. For example, there would be one instance for every ng-controller directive in the template.

Moreover, additional dependencies are made available to Controllers:

  • $scope: Controllers are always associated with a point in the DOM and so are provided with access to the scope at that point. Other components, such as services only have access to the singleton $rootScope service.
  • $route resolves: If a controller is instantiated as part of a route, then any values that are resolved as part of the route are made available for injection into the controller.

Python: Introducción

Python is a clear and powerful object-oriented programming language, comparable to Perl, Ruby, Scheme, or Java.

Some of Python’s notable features:

  • Uses an elegant syntax, making the programs you write easier to read.
  • Is an easy-to-use language that makes it simple to get your program working. This makes Python ideal for prototype development and other ad-hoc programming tasks, without compromising maintainability.
  • Comes with a large standard library that supports many common programming tasks such as connecting to web servers, searching text with regular expressions, reading and modifying files.
  • Python’s interactive mode makes it easy to test short snippets of code. There’s also a bundled development environment called IDLE.
  • Is easily extended by adding new modules implemented in a compiled language such as C or C++.
  • Can also be embedded into an application to provide a programmable interface.
  • Runs on many different computers and operating systems: Windows, MacOS, many brands of Unix, OS/2, …
  • Is free software in two senses. It doesn’t cost anything to download or use Python, or to include it in your application. Python can also be freely modified and re-distributed, because while the language is copyrighted it’s available under an open source license.

Some programming-language features of Python are:

  • A variety of basic data types are available: numbers (floating point, complex, and unlimited-length long integers), strings (both ASCII and Unicode), lists, and dictionaries.
  • Python supports object-oriented programming with classes and multiple inheritance.
  • Code can be grouped into modules and packages.
  • The language supports raising and catching exceptions, resulting in cleaner error handling.
  • Data types are strongly and dynamically typed. Mixing incompatible types (e.g. attempting to add a string and a number) causes an exception to be raised, so errors are caught sooner.
  • Python contains advanced programming features such as generators and list comprehensions.
  • Python’s automatic memory management frees you from having to manually allocate and free memory in your code.

See the SimplePrograms collection of short programs, gradually increasing in length, which show off Python’s syntax and readability.

History

Python was conceived in the late 1980s and its implementation was started in December 1989 by Guido van Rossum at CWI in Amsterdam. Python is a successor to the ABC programming language (itself inspired by SETL) capable of exception handling and interfacing with the Amoeba operating system. Van Rossum is Python’s principal author, and his continuing central role in deciding the direction of Python is reflected in the title given to him by the Python community, Benevolent Dictator for Life (BDFL).


Programming philosophy

Python is a multi-paradigm programming language. Rather than forcing programmers to adopt a particular style of programming, it permits several styles: object-oriented programming and structured programming are fully supported, and there are a number of language features which support functional programming and aspect-oriented programming (including metaprogramming and “by magic” methods). Many other paradigms are supported using extensions, such as pyDBC and Contracts for Python which allow Design by Contract.

Rather than requiring all desired functionality to be built into the language’s core, Python was designed to be highly extensible. New built-in modules can be easily written in C, C++ or Cython. Python can also be used as an extension language for existing modules and applications that need a programmable interface. This design, a small core language with a large standard library with an easily extensible interpreter, was intended by Van Rossum from the very start because of his frustrations with ABC (which espoused the opposite mindset).

Name and neologisms

An important goal of the Python developers is making Python fun to use. This is reflected in the origin of the name (based on the television series Monty Python’s Flying Circus), in the common practice of using Monty Python references in example code, and in an occasionally playful approach to tutorials and reference materials.[24][25] For example, the metasyntactic variables often used in Python literature are spam and eggs, instead of the traditional foo and bar.

 

Usage

Python is often used as a scripting language for web applications, e.g. via mod_wsgi for the Apache web server. With Web Server Gateway Interface, a standard API has been developed to facilitate these applications. Web application frameworks like Django, Pylons, TurboGears, web2py, Flask and Zope support developers in the design and maintenance of complex applications. Libraries like NumPySciPy and Matplotlib allow Python to be used effectively in scientific computing.

Syntax and semantics

Python was intended to be a highly readable language. It is designed to have an uncluttered visual layout, frequently using English keywords where other languages use punctuation. Python requires less boilerplate than traditional manifestly typed structured languages such as C or Pascal, and has a smaller number of syntactic exceptions and special cases than either of these. For a detailed description of the differences between 2.x and 3.x versions, see History of Python.

Indentation

Python uses whitespace indentation, rather than curly braces or keywords, to delimit blocks (a feature also known as the off-side rule). An increase in indentation comes after certain statements; a decrease in indentation signifies the end of the current block.

Statements and control flow

Python’s statements include (among others):

  • The if statement, which conditionally executes a block of code, along with else and elif (a contraction of else-if).
  • The for statement, which iterates over an iterable object, capturing each element to a local variable for use by the attached block.
  • The while statement, which executes a block of code as long as its condition is true.
  • The try statement, which allows exceptions raised in its attached code block to be caught and handled by except clauses; it also ensures that clean-up code in a finally block will always be run regardless of how the block exits.
  • The class statement, which executes a block of code and attaches its local namespace to a class, for use in object-oriented programming.
  • The def statement, which defines a function or method.
  • The with statement (from Python 2.5), which encloses a code block within a context manager (for example, acquiring a lock before the block of code is run, and releasing the lock afterwards).
  • The pass statement, which serves as a NOP and can be used in place of a code block.
  • The assert statement, used during debugging to check for conditions that ought to apply.
  • The yield statement, which returns a value from a generator function. (From Python 2.5, yield is also an operator. This form is used to implement coroutines — see below.)

Expressions

  • In Python 2, the / operator on integers does integer division: it truncates the result to an integer. Floating-point division on integers can be achieved by converting one of the integers to a float (e.g. float(x) / y).
    • In Python 3, the result of / is always a floating-point value, and a new operator // is introduced to do integer division; this behaviour can be enabled in Python 2.2+ using from __future__ import division.
  • In Python, == compares by value, in contrast to Java, where it compares by reference. (Value comparisons in Java use the equals() method.) Python’s is operator may be used to compare object identities (comparison by reference). Comparisons may be chained, for example a <= b <= c.
  • Python uses the words andornot for its boolean operators rather than the symbolic &&, ||, ! used in C.
  • Python has a type of expression known as a list comprehension. Python 2.4 extended list comprehensions into a more general expression known as a generator expression.
  • Anonymous functions are implemented using lambda expressions; however, these are limited in that the body can only be a single expression.
  • Conditional expressions in Python are written as x if c else y (different in order of operands from the ?: operator common to many other languages).
  • Python makes a distinction between lists and tuples. Lists, written as [1, 2, 3], are mutable, and cannot be used as the keys of dictionaries (dictionary keys must be immutable in Python). Tuples, written as (1, 2, 3), are immutable and thus can be used as the keys of dictionaries, provided all elements of the tuple are immutable. The parentheses around the tuple are optional in some contexts. Tuples can appear on the left side of an equal sign; hence a statement like x, y = y, x can be used to swap two variables.
  • Python 2 has a “string format” operator %. This functions analogous to printf format strings in C, e.g. “foo=%s bar=%d” % (“blah”, 2) evaluates to “foo=blah bar=2”. In Python 3, this was obsoleted in favour of the format() method of the str class, e.g. “foo={0} bar={1}”.format(“blah”, 2).
  • Python has various kinds of string literals:
    • Strings are delimited by single or double quotation marks. Unlike in Unix shells, Perl and Perl-influenced languages, single quotation marks and double quotation marks function similarly. Both kinds of string use the backslash (\) as an escape character and there is no implicit string interpolation such as “$foo”.
    • Triple-quoted strings, which begin and end with a series of three single or double quotation marks, may span multiple lines and function like here documents in shells, Perl and Ruby.

Methods

Methods on objects are functions attached to the object’s class; the syntax instance.method(argument) is, for normal methods and functions, syntactic sugar for Class.method(instance, argument). Python methods have an explicit self parameter to access instance data, in contrast to the implicit self in some other object-oriented programming languages (for example, Java, C++ or Ruby).

Typing

Python uses duck typing and has typed objects but untyped variable names. Type constraints are not checked at compile time; rather, operations on an object may fail, signifying that the given object is not of a suitable type. Despite being dynamically typed, Python is strongly typed, forbidding operations that are not well-defined (for example, adding a number to a string) rather than silently attempting to make sense of them.

Mathematics

Python defines the modulus operator so that the result of a % b is in the half-open interval [0,b), where b is a positive integer. When b is negative, the result lies in the interval (b,0]. However, this consequently affects how integer division is defined. To maintain the validity of the equation b * (a // b) + a % b == a, integer division is defined to round towards minus infinity. Therefore 7 // 3 is 2, but (−7) // 3 is −3. This is different from many programming languages, where the result of integer division rounds towards zero, and Python’s modulus operator is consequently defined in a way that can return negative numbers.

Implementations

CPython

The mainstream Python implementation, known as CPython, is written in C meeting the C89 standard. CPython compiles Python programs into intermediate bytecode,[65] which are then executed by the virtual machine. It is distributed with a large standard library written in a mixture of C and Python. CPython ships in versions for many platforms, including Microsoft Windows and most modern Unix-like systems. CPython was intended from almost its very conception to be cross-platform; its use and development on esoteric platforms such as Amoeba, alongside more conventional ones like Unix and Mac OS, has greatly helped in this regard.

Alternative implementations

Jython compiles the Python program into Java byte code, which can then be executed by every Java Virtual Machine implementation. This also enables the use of Java class library functions from the Python program. IronPython follows a similar approach in order to run Python programs on the .NET Common Language Runtime. PyPy is a fast self-hosting implementation of Python, written in Python, that can output several types of bytecode, object code and intermediate languages. There also exist compilers to high-level object languages, with either unrestricted Python, a restricted subset of Python, or a language similar to Python as the source language. PyPy is of this type, compiling RPython to several languages; other examples include Pyjamas compiling to JavaScript; Shed Skin compiling to C++; and Cython and Pyrex compiling to C.

  • Python is available on Android as an option as part of the Android Scripting Environment.

Interpretational semantics

Most Python implementations (including CPython) can function as a command line interpreter, for which the user enters statements sequentially and receives the results immediately. In short, Python acts as a shell. While the semantics of the other modes of execution (bytecode compilation, or compilation to native code) preserve the sequential semantics, they offer a speed boost at the cost of interactivity, so they are usually only used outside of a command-line interaction (e.g., when importing a module).

Other shells add capabilities beyond those in the basic interpreter, including IDLE and IPython. While generally following the visual style of the Python shell, they implement features like auto-completion, retention of session state, and syntax highlighting.


Development

Python’s development is conducted largely through the Python Enhancement Proposal (PEP) process. PEPs are standardized design documents providing general information related to Python, including proposals, descriptions, design rationales, and explanations for language features. Outstanding PEPs are reviewed and commented upon by Van Rossum, the Python project’s Benevolent Dictator for Life (leader / language architect). CPython’s developers also communicate over a mailing list, python-dev, which is the primary forum for discussion about the language’s development; specific issues are discussed in the Roundup bug tracker maintained at python.org. Development takes place at the self-hosted hg.python.org.

CPython’s public releases come in three types, distinguished by which part of the version number is incremented:

  • backwards-incompatible versions, where code is expected to break and must be manually ported. The first part of the version number is incremented. These releases happen infrequently—for example, version 3.0 was released 8 years after 2.0.
  • major or ‘feature’ releases, which are largely compatible but introduce new features. The second part of the version number is incremented. These releases are scheduled to occur roughly every 18 months, and each major version is supported by bugfixes for several years after its release.
  • bugfix releases, which introduce no new features but fix bugs. The third and final part of the version number is incremented. These releases are made whenever a sufficient number of bugs have been fixed upstream since the last release, or roughly every 3 months. Security vulnerabilities are also patched in bugfix releases.

A number of alpha, beta, and release-candidates are also released as previews and for testing before the final release is made. Although there is a rough schedule for each release, this is often pushed back if the code is not ready. The development team monitor the state of the code by running the large unit test suite during development, and using the BuildBot continuous integration system.

Standard library

Python has a large standard library, commonly cited as one of Python’s greatest strengths,[81] providing pre-written tools suited to many tasks. This is deliberate and has been described as a “batteries included” Python philosophy. The modules of the standard library can be augmented with custom modules written in either C or Python. Boost C++ Libraries includes a library, Boost.Python, to enable interoperability between C++ and Python. Because of the wide variety of tools provided by the standard library, combined with the ability to use a lower-level language such as C and C++, which is already capable of interfacing between other libraries, Python can be a powerful glue language between languages and tools.

The standard library is particularly well tailored to writing Internet-facing applications, with a large number of standard formats and protocols (such as MIME and HTTP) already supported. Modules for creating graphical user interfaces, connecting to relational databases, arithmetic with arbitrary precision decimals, manipulating regular expressions, and doing unit testing are also included.

Some parts of the standard library are covered by specifications (for example, the WSGI implementation wsgiref follows PEP 333), but the majority of the modules are not. They are specified by their code, internal documentation, and test suite (if supplied). However, because most of the standard library is cross-platform Python code, there are only a few modules that must be altered or completely rewritten by alternative implementations.

For software testing, the standard library provides the unittest and doctest modules.


Influence on other languages

Python’s design and philosophy have influenced several programming languages, including:

  • Pyrex and its derivative Cython are code translators that are targeted at writing fast C extensions for the CPython interpreter. The language is mostly Python with syntax extensions for C and C++ features. Both languages produce compilable C code as output.
  • Boo uses indentation, a similar syntax, and a similar object model. However, Boo uses static typing and is closely integrated with the .NET framework.[84]
  • Cobra uses indentation and a similar syntax. Cobra’s “Acknowledgements” document lists Python first among languages that influenced it. However, Cobra directly supports design-by-contract, unit tests and optional static typing.
  • \ borrowed iterators, generators, and list comprehensions from Python.
  • Go is described as incorporating the “development speed of working in a dynamic language like Python”.
  • Groovy was motivated by the desire to bring the Python design philosophy to Java.
  • OCaml has an optional syntax, called twt (The Whitespace Thing), inspired by Python and Haskell.