tags:

views:

119

answers:

3

I am trying to figure out the best practice of communication between a TabActivity and the child activity embedded in this TabActivity.

In my TabActivity, there is a button. When the button is clicked, I want the child activity embedded in this TabActivity to be updated. I wrote the code like below, and just wonder whether it is a good practice. Thanks.

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;
        }
}
+1  A: 

Seems fine. A couple of notes:
- I see no reason for synchronization.
- I'd replace

ChildActivity.s_childActivity.changeUI();

with

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

or even

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

for added paranoid safety. :)

alex
I see. They are in the same thread.I prefer if(ChildActivity.s_childActivity != null){ ChildActivity.s_childActivity.changeUI();}Thanks.
A: 

Couple of design issues with this, but overall it seems reasonable.

I would forgo the static instance in the ChildActivity class. Why? Well, think about the relationship you're modeling. A TabActivity has a ChildActivity. This is textbook composition, and would be accomplished by adding a ChildActivity field to the TabActivity class, like so:

 public class TabActivity {

    private ChildActivity child;

    //remember to initialize child in onCreate

    //then, call methods using child.changeUI();, for example

} 

This is better, because A) now I can have multiple instances of TabActivity and ChildActivity that won't interfere with each other (before, it was just a static variable, so only one ChildActivity could be used), and B) the ChildActivity is encapsulated inside the TabActivity class... before, it was a public field, meaning anything can use and modify it (might not be desirable; can often lead to some strange runtime bugs as well as messy, tied-together code) - we changed it to a private field, because we don't really want other classes accessing it in unexpected ways.

The only thing you may need access to from the ChildActivity is the parent (TabActivity). To do this, add the following methods and field to the ChildActivity class, and call the registerParent() method after constructing the ChildActivity:

public class ChildActivity ...{

private TabActivity parent;

public void registerParent(TabActivity newParent){
    if (newParent != null){
        parent = newParent;
    }
}
}

So, if you need access to the parent TabActivity from the child, just call parent.someMethod();

It would also be wise to access fields like parent and child through getters and setters; it might save you some time in the long run.

Kris
A: 

Since TabActivity is an ActivityGroup, I would use one of the following:

  • getCurrentActivity()

Returns the child tab activity being displayed. In your case, this method will return the instance of ChildActivity being used.

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

Returns the child tab activity given its ID/tab spec name, whatever activity being displayed.

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

I suggest overriding onNewIntent(Intent) in your ChildActivity:

Intent intent = new Intent();
intent.putExtra("xyz", "whatever"); // or a serializable

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

Let me know if it works!

patgrdj