Comunicación entre TabActivity y la actividad incorporada

Estoy tratando de averiguar la mejor práctica de comunicación entre una TabActivity y la actividad de los niños incrustados en este TabActivity.

En mi TabActivity, hay un botón. Cuando se hace clic en el botón, quiero que se actualice la actividad secundaria incrustada en esta TabActivity. Escribí el código como a continuación, y me pregunto si es una buena práctica. Gracias.

MyTabActivity.java

public class MyTabActivity extends TabActivity implements OnClickListener { private TabHost m_tabHost; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ff_tab_activity); LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); m_tabHost = getTabHost(); TabHost.TabSpec spec; Intent intent; intent = new Intent().setClass(this, ChildActivity.class); spec = m_tabHost.newTabSpec("Tab 1"); spec.setContent(intent); tabView = (TextView) inflater.inflate(R.layout.tab_indicator, null); spec.setIndicator(tabView); m_tabHost.addTab(spec); m_tabHost.setCurrentTab(0); ImageView nextButtonIv = (ImageView) findViewById(R.id.next_button); nextButtonIv.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.next_button: synchronized (ChildActivity.class) { if (null != ChildActivity.s_childActivity) { ChildActivity.s_childActivity.changeUI(); } } break; } } 

ChildActivity.java

 public class ChildActivity extends Activity { public static ChildActivity s_childActivity; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); synchronized (MatchupsActivity.class) { s_childActivity = this; } setContentView(R.layout.child_activity); } public void changeUi() { code that changes UI } protected void onDestroy() { super.onDestroy(); synchronized (MatchupsActivity.class) { s_childActivity = null; } } 

Se ve bien. Un par de notas:
– No veo ninguna razón para la sincronización.
Yo reemplazaría

 ChildActivity.s_childActivity.changeUI(); 

con

 if(ChildActivity.s_childActivity != null){ ChildActivity.s_childActivity.changeUI(); } 

o incluso

 try{ ChildActivity.s_childActivity.changeUI(); } catch(Exception e){ //log } 

para la seguridad paranoica añadida. 🙂

Ya que TabActivity es un ActivityGroup, usaría uno de los siguientes:

  • getCurrentActivity ()

Devuelve la actividad de la ficha secundaria que se muestra. En su caso, este método devolverá la instancia de ChildActivity que se está utilizando.

 ChildActivity childActivity = (ChildActivity) getCurrentActivity(); 
  • getLocalActivityManager (). getActivity (String)

Devuelve la actividad de la pestaña secundaria dada su ID / nombre de ficha de especificación, cualquier actividad que se muestra.

 ChildActivity childActivity = (ChildActivity) getLocalActivityManager().getActivity("Tab 1"); 

Sugiero reemplazar onNewIntent (Intent) en su ChildActivity:

 Intent intent = new Intent(); intent.putExtra("xyz", "whatever"); // or a serializable ChildActivity childActivity = (ChildActivity) getLocalActivityManager().getActivity("Tab 1"); childActivity.onNewIntent(intent); 

¡Déjame saber si funciona!

El camino de arriba con

 ChildActivity childActivity = (ChildActivity) getLocalActivityManager().getActivity("Tab 1"); childActivity.onNewIntent(intent); 

no es muy agradable. En lugar de invocar su método de actividad directamente (puede ser nulo !!!) mejor hacerlo de esta manera:

 Intent intent = new Intent(this, ChildActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.putExtra(AlbumBrowser.INTENT_EXTRA_FILTER, mediaTitle); getLocalActivityManager().startActivity("activityIdHere", intent); 

Par de problemas de diseño con esto, pero en general parece razonable.

Quisiera renunciar a la instancia estática en la clase ChildActivity . ¿Por qué? Bueno, piensa en la relación que estás modelando. Una TabActivity tiene una ChildActivity . Esta es la composición del libro de texto, y se lograría agregando un campo ChildActivity a la clase TabActivity, así:

  public class TabActivity { private ChildActivity child; //remember to initialize child in onCreate //then, call methods using child.changeUI();, for example } 

Esto es mejor, porque A) ahora puedo tener varias instancias de TabActivity y ChildActivity que no interfieren entre sí (antes, era sólo una variable estática, por lo que sólo se podía usar una ChildActivity), y B) ChildActivity es encapsulado dentro de la clase TabActivity … antes, era un campo público, lo que significa que cualquier cosa puede usar y modificarlo (podría no ser deseable, a menudo puede conducir a algunos extraños errores de ejecución, así como desordenado, a un campo privado, porque realmente no queremos que otras clases lo accedan de maneras inesperadas.

Lo único que puede necesitar el acceso de ChildActivity es el padre (TabActivity). Para ello, agregue los métodos y el campo siguientes a la clase ChildActivity y llame al método registerParent () después de construir ChildActivity:

 public class ChildActivity ...{ private TabActivity parent; public void registerParent(TabActivity newParent){ if (newParent != null){ parent = newParent; } } } 

Por lo tanto, si necesita tener acceso al TabActivity padre desde el niño, simplemente llame a parent.someMethod ();

También sería aconsejable acceder a campos como parent e child través de getters y setters; podría ahorrarle tiempo en el largo plazo.

Puede utilizar getParent () para obviar la necesidad de hacer algo de esto.

Aquí está mi clase hijo de lanzador con botones que cambian entre las actividades manejadas por el tabHost:

 public class LaunchPadActivity extends Activity implements OnClickListener { private static final int ICON_PROFILE = 0; private static final int ICON_SEARCH = 1; private static final int ICON_MAP = 2; private static final int FAVOURITES = 3; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.launchpad); GridView launchPad = (GridView) findViewById(R.id.launchpad); launchPad.setAdapter(new LaunchIconAdapter(this)); } public class LaunchIconAdapter extends BaseAdapter { private Context mContext; // references to our images private Integer[] mThumbIds = { R.drawable.user, R.drawable.find, R.drawable.map, R.drawable.favourites, R.drawable.reviews, R.drawable.news, R.drawable.tutorial, R.drawable.info, R.drawable.options, }; public String[] texts = { "Profile", "Search", "Map", "Favourites", "Reviews", "News", "Tutorial", "Info", "Options" }; public LaunchIconAdapter(Context c) { mContext = c; } // Number of thumbs determines number of GridView items public int getCount() { return mThumbIds.length; } public Object getItem(int position) { return null; } public long getItemId(int position) { return 0; } // create a new ImageView for each item referenced by the Adapter public View getView(int position, View convertView, ViewGroup parent) { // Icon elements LinearLayout launchIcon; ImageView launchImage; TextView launchText; if (convertView == null) { launchIcon = (LinearLayout) ((LayoutInflater) mContext .getSystemService(LAYOUT_INFLATER_SERVICE)).inflate( R.layout.launchicon, null); } else { launchIcon = (LinearLayout) convertView; } // Add ClickListener with metadata launchIcon.setTag(new Integer(position)); launchIcon.setOnClickListener(LaunchPadActivity.this); // Get subviews launchImage = (ImageView) launchIcon .findViewById(R.id.launch_image); launchText = (TextView) launchIcon.findViewById(R.id.launch_text); // Configure subviews launchImage.setImageResource(mThumbIds[position]); launchText.setText(texts[position]); return launchIcon; } } @Override public void onClick(View v) { int position = ((Integer) v.getTag()).intValue(); switch (position) { case ICON_PROFILE: Toast.makeText(this, "Profile", Toast.LENGTH_LONG).show(); break; case ICON_SEARCH: Toast.makeText(this, "Search", Toast.LENGTH_LONG).show(); ((TabActivity) getParent()).getTabHost().setCurrentTab(1); break; case ICON_MAP: Toast.makeText(this, "Map", Toast.LENGTH_LONG).show(); ((TabActivity) getParent()).getTabHost().setCurrentTab(2); break; case FAVOURITES: Toast.makeText(this, "Map", Toast.LENGTH_LONG).show(); ((TabActivity) getParent()).getTabHost().setCurrentTab(3); break; } } } 

Funciona de maravilla.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.