I have an app that I desperately need to convert from using the old ActivityGroup class to Fragments. I'm not sure how to go about it though. Below is a sample of the code I use now. Could anyone provide some insight into what steps I should take to start switching it over to use Fragments / FragmentManager instead?
Main.java
public class Main extends TabActivity implements OnTabChangeListener {
public static TextView txtViewHeading;
public static Button btnBack;
public static ImageButton btnShare;
public static Main mainActivity;
public static Boolean isVisible = false;
private GoogleCloudMessaging gcm;
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mainActivity = this;
NotificationsManager.handleNotifications(this, NotificationSettings.SenderId, PushHandler.class);
registerWithNotificationHubs();
//reference headings text & button for access from child activities
txtViewHeading = (TextView) findViewById(R.id.txtViewHeading);
btnBack = (Button) findViewById(R.id.btnBack);
btnShare = (ImageButton) findViewById(R.id.btnShare);
// Update the font for the heading and back button
Typeface arialTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/arial.ttf");
Typeface myriadTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/myriad.ttf");
txtViewHeading.setTypeface(myriadTypeface);
btnBack.setTypeface(arialTypeface);
Resources res = getResources();
TabHost tabsNavigation = getTabHost();
// Set up the views for each tab - custom view used for Badge icon
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Set up my tabs...each one looks similar to this
View statusTabView = inflater.inflate(R.layout.tab, null);
ImageView statusTabIcon = (ImageView) statusTabView.findViewById(R.id.tabIcon);
statusTabIcon.setImageResource(R.drawable.tab_first);
TextView statusTabText = (TextView) statusTabView.findViewById(R.id.tabText);
statusTabText.setText("Status");
statusTabText.setTypeface(arialTypeface);
statusTabBadge = (TextView) statusTabView.findViewById(R.id.tabBadge);
statusTabBadge.setTypeface(arialTypeface);
tabsNavigation.addTab(tabsNavigation.newTabSpec(getResources().getString(R.string.main_tab_status))
.setIndicator(statusTabView)
.setContent(new Intent(this, StatusGroupActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)));
//Set default tab to Status
tabsNavigation.setCurrentTab(0);
tabsNavigation.setOnTabChangedListener(this);
}
/* Set txtViewHeading text to selected tab text */
@Override
public void onTabChanged(String tabId) {
// TODO Auto-generated method stub
txtViewHeading.setText(tabId);
}
/* Set code to execute when onDestroy method is called */
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
/* Set code to execute when onPause method is called */
@Override
protected void onPause() {
super.onPause();
isVisible = false;
}
/* Set code to execute when onResume method is called */
@Override
protected void onResume() {
super.onResume();
isVisible = true;
}
/* Set code to execute when onStop method is called */
@Override
protected void onStop() {
super.onStop();
isVisible = false;
}
/**
* Check the device to make sure it has the Google Play Services APK. If
* it doesn't, display a dialog that allows users to download the APK from
* the Google Play Store or enable it in the device's system settings.
*/
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
.show();
} else {
ToastNotify("This device is not supported by Google Play Services.");
finish();
}
return false;
}
return true;
}
public void ToastNotify(final String notificationMessage) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(Main.this, notificationMessage, Toast.LENGTH_LONG).show();
}
});
}
public void registerWithNotificationHubs()
{
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
}
}
TabGroupActivity.java
public class TabGroupActivity extends ActivityGroup
{
private ArrayList<String> mIdList;
Button btnBack;
ImageButton btnShare;
TextView txtViewHeading;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
btnBack = Main.btnBack;
btnShare = Main.btnShare;
txtViewHeading = Main.txtViewHeading;
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
if (mIdList == null) mIdList = new ArrayList<String>();
}
/**
* This is called when a child activity of this one calls its finish method.
* This implementation calls {@link LocalActivityManager#destroyActivity} on the child activity
* and starts the previous activity.
* If the last child activity just called finish(),this activity (the parent),
* calls finish to finish the entire group.
*/
@Override
public void finishFromChild(Activity child)
{
try
{
btnShare.setVisibility(View.GONE);
LocalActivityManager manager = getLocalActivityManager();
int index = mIdList.size()-1;
if (index < 1)
{
finish();
return;
}
manager.destroyActivity(mIdList.get(index), true);
mIdList.remove(index);
index--;
String lastId = mIdList.get(index);
Intent lastIntent = manager.getActivity(lastId).getIntent();
Window newWindow = manager.startActivity(lastId, lastIntent);
setContentView(newWindow.getDecorView());
//Set Heading text to current Id
txtViewHeading.setText(getActivityHeading(lastId));
//Set Back button text to previous Id if applicable
btnBack.setVisibility(View.VISIBLE);
//Back button
String backId = "";
if(mIdList.size() > 1)
{
backId = mIdList.get(mIdList.size()-2);
btnBack.setVisibility(View.VISIBLE);
btnBack.setText(getActivityHeading(backId));
txtViewHeading.setPadding(10,0,0,0);
}
else
{
btnBack.setVisibility(View.GONE);
txtViewHeading.setPadding(0,0,0,0);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Starts an Activity as a child Activity to this.
* @param Id Unique identifier of the activity to be started.
* @param intent The Intent describing the activity to be started.
*/
public void startChildActivity(String Id, Intent intent)
{
try
{
btnShare.setVisibility(View.GONE);
Window window = getLocalActivityManager().startActivity(Id,intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
if (window != null)
{
mIdList.add(Id);
setContentView(window.getDecorView());
txtViewHeading.setText(getActivityHeading(Id));
//Back button
String backId = "";
if(mIdList.size() > 1)
{
backId = mIdList.get(mIdList.size()-2);
btnBack.setVisibility(View.VISIBLE);
btnBack.setText(backId);
txtViewHeading.setPadding(5,0,0,0);
}
else
{
btnBack.setVisibility(View.GONE);
txtViewHeading.setPadding(0,0,0,0);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* The primary purpose is to prevent systems before android.os.Build.VERSION_CODES.ECLAIR
* from calling their default KeyEvent.KEYCODE_BACK during onKeyDown.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
//preventing default
return true;
}
return super.onKeyDown(keyCode, event);
}
/**
* Overrides the default implementation for KeyEvent.KEYCODE_BACK
* so that all systems call onBackPressed().
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
onBackPressed();
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* If a Child Activity handles KeyEvent.KEYCODE_BACK.
* Simply override and add this method.
*/
@Override
public void onBackPressed ()
{
try
{
btnShare.setVisibility(View.GONE);
int length = mIdList.size();
if ( length > 1)
{
Activity current = getLocalActivityManager().getActivity(mIdList.get(length-1));
current.finish();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* Get the correct heading text and language based on activity id
*/
public String getActivityHeading(String id)
{
// method that returns the TEXT for my main heading TextView based on the activity we're on...
}
}
StatusGroupActivity
public class StatusGroupActivity extends TabGroupActivity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startChildActivity("Status", new Intent(this,Status.class));
}
}
... so basically when my app loads, I get my tabs at the bottom, my header at the top, and the "tab content" in the middle. In my Status activity, I can load another activity from it by using ...
Intent intent = new Intent(getParent(), SomeOtherActivity.class)
TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Some Other Activity", intent);
... and it loads the SomeOtherActivity activity into the content area. Hitting back takes me back to the Status screen.
Any pointers, examples and assistance with converting this over to use Fragments is so greatly appreciated. I will gladly donate 500 of my rep. points for a full example.
main.xml (Main Activity Layout file)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:ignore="ContentDescription,HardcodedText" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/imageSuccess"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:scaleType="matrix"
android:src="@drawable/bg_navbar_blank" />
<com.myproject.android.BgButtonStyle
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="0dp"
android:background="@drawable/back_button"
android:text=""
android:textColor="@color/White"
android:textSize="12sp"
android:visibility="visible"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:padding="5dp"/>
<ImageButton
android:id="@+id/btnShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:background="@null"
android:src="@drawable/icon_share"
android:visibility="visible"
android:adjustViewBounds="false"
android:scaleType="fitXY"/>
<com.myproject.android.AutoResizeTextView
android:id="@+id/txtViewHeading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="5dp"
android:text="Status"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="28sp"
android:textStyle="bold"
android:paddingRight="5dp"
android:layout_toEndOf="@id/btnBack"
android:layout_toStartOf="@id/btnShare"
android:layout_centerVertical="true"
android:lines="1"/>
</RelativeLayout>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
</FrameLayout>
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:layout_weight="0"
android:background="@drawable/bg_tabs">
</TabWidget>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
In my current TabGroupActivity class, in the finishFromChild and startChildActivity methods, I am able to call setText on the txtViewHeading TextView element in my main activity layout. Which is the current activities "title". If there is more than 1 activity in the group, the back button shows the previous title. How can I duplicate this in the examples below? The main activity layout there is much different than mine.