Forces an update of tab content after the asynchronous task completes
I have a TabActivity
with 3 tabs. There is an asynchronous task that retrieves updated data from the server when refreshed by clicking a menu item. This data is stored in the Controller and accessed by all Views, so the model only needs to be loaded once.
My question is, after the asynchronous activity runs and updates the model, how do I signal all three tabs to update their contents?
My Activities
public class DashboardActivity extends TabActivity {
private ProfileModel profile;
private TabHost tabHost;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
profile = Controller.getProfile();
this.setContentView(R.layout.dashboard);
tabHost = getTabHost();
setupTab(new TextView(this), "Home", new Intent().setClass(DashboardActivity.this, HomeActivity.class));
setupTab(new TextView(this), "History", new Intent().setClass(DashboardActivity.this, PaymentsActivity.class));
setupTab(new TextView(this), "My Wallet", new Intent().setClass(DashboardActivity.this, MyWalletActivity.class));
tabHost.setCurrentTab(0);
ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
actionBar.setTitle(profile. Name);
}
private void setupTab(final View view, final String tag, Intent content) {
View tabview = createTabView(tabHost.getContext(), tag);
TabSpec setContent = tabHost.newTabSpec(tag)
.setIndicator(tabview)
.setContent(content);
tabHost.addTab(setContent);
}
private static View createTabView(final Context context, final String text) {
View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null);
TextView tv = (TextView) view.findViewById(R.id.tabsText);
tv.setText(text);
return view;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mainmenu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Handle item selection
switch (item.getItemId()) {
case R.id.menu_settings:
return true;
case R.id.menu_refresh:
new RefreshDashboardTask().execute();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private class RefreshDashboardTask extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute()
{
ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
if(actionBar != null)
actionBar.setProgressBarVisibility(View.VISIBLE);
}
@Override
protected Void doInBackground(Void... params)
{
try {
profile = DataHelper.getProfile();
Controller.setProfile(profile);
} catch (IOException e) {
TODO Auto-generated catch block
e.printStackTrace();
} catch (HttpException e) {
TODO Auto-generated catch block
e.printStackTrace();
} catch (ServerException e) {
TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
if(actionBar != null)
actionBar.setProgressBarVisibility(View.GONE);
}
}
}
Edit To elaborate further, here is more code.
My Controller
public class Controller extends Application {
private static Controller instance;
private static DefaultHttpClient client;
private static ProfileModel profile;
public Controller() {
instance = this;
client = new DefaultHttpClient();
profile = null;
}
public static Context getContext() {
return instance;
}
public static DefaultHttpClient getHttpContext() {
return client;
}
public static ProfileModel getProfile() {
return profile;
}
public static void setProfile(ProfileModel profile) {
Controller.profile = profile;
}
@Override
public void onCreate()
{
super.onCreate();
}
}
One of my activities is in a tab View. This is the easiest one because it is just a list. Home View is 2 lists, separated by headings, and Wallet View is a dynamically generated list with titles, created from a collection within a collection.
public class PaymentsActivity extends Activity {
ProfileModel profile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.payment_history);
profile = Controller.getProfile();
ListView itemList = (ListView)this.findViewById(R.id.payment_history_list);
itemList.setTextFilterEnabled(true);
itemList.clearChoices();
itemList.setAdapter(new ItemSummaryAdapter(PaymentsActivity.this, R.layout.list_item_payment, profile. Items));
statementList.setOnItemClickListener(clickListener);
}
}
The goal here is to refresh the button to update the data in the controller. All of my views in the tab have been updated.
Solution
Update:
If I were you, I would Observer pattern
public class Controller extends Application {
private static Controller instance;
private static DefaultHttpClient client;
private static ProfileModel profile;
private static Set<ControllerUpdateListener> updateListeners = new HashSet<ControllerUpdateListener>();
//...
public static void addListener(ControllerUpdateListener listener)
{
updateListeners.add(listener);
}
public static interface ControllerUpdateListener {
void onControllerUpdate(ProfileModel model);
}
}
Then have your personal tab activity implement ControllerUpdateListener
. Finally, add the trigger to the Controller
class:
public static void setProfile(ProfileModel profile) {
Controller.profile = profile;
for(ControllerUpdateListener l : updateListeners) {
l.onControllerUpdate(profile);
}
}
Don’t forget to register each activity as a listener for the controller
:
public class PaymentsActivity extends Activity implements Controller.ControllerUpdateListener {
ProfileModel profile;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.payment_history);
Controller.addListener(this); <-- Don't forget this...
profile = Controller.getProfile();
ListView itemList = (ListView)this.findViewById(R.id.payment_history_list);
itemList.setTextFilterEnabled(true);
itemList.clearChoices();
itemList.setAdapter(new ItemSummaryAdapter(PaymentsActivity.this, R.layout.list_item_payment, profile. Items));
statementList.setOnItemClickListener(clickListener);
}
public void onControllerUpdate(ProfileModel model) {
update these views...
}
}
Now, each of your tab activities should trigger their notifyDataSetChanged()
(or any other method that triggers their update) in the onControllerUpdate(ProfileModel)
method.