I'm facing some complexities when developing a medium-complex Android application. I'm searching for information about the possibility of using code-behind
-like techniques for easier maintanability of Android software.
Currently (please highlight anything wrong), I have found that in order to make a multi-step wizard with extra dialogs (eg. dialogs that are not part of the main sequence) I need to code a single XML layout file with a single ViewFlipper containing each subview as child node. Today I discovered how to navigate across views more than forward/backward (viewFlipper.setDisplayedChild(i)
), giving access to extra views.
Now all the Java code is contained within the main Activity
class, which is beginning to look bad. As an experienced .NET developer I have learned how to use custom controls to wrap both layout and business logic inside modules.
I know that in Android I can define a view programmatically as an independent class and add it to the main layout programmatically, however I want to know if it's possible in Android to define a layout by XML (for easier WYSIWYG creation/editing) and define all the code within a dedicated class, with initialization logic, button callbacks, async tasks, etc.
I'm not sure if it's feasible or there is a good compromise that can be achieved.
I have read this question without clearing my doubts.
Thank you.
Code examples:
An extract of the layout file (I expect 4 wizard steps, a help view and an EULA view)
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/view_phone"
style="@android:style/Theme.Light.NoTitleBar"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- First screen/welcome -->
<LinearLayout
android:id="@+id/view_phone_screen1"
style="@android:style/Theme.Light.NoTitleBar"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:weightSum="100" >
<TextView
android:id="@+id/view_phone_screen1_lblChooseProvider"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="@string/view_phone_lblChooseProvider_1ststep"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ImageButton
android:id="@+id/view_phone_btnFrecciarossa"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:contentDescription="@string/provider_FRECCIAROSSA"
android:gravity="center_vertical|clip_vertical"
android:padding="10dp"
android:src="@drawable/logo_frecciarossa"
android:tag="@+id/provider_FRECCIAROSSA" />
<ImageButton
android:id="@+id/view_phone_btnItalo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:contentDescription="@string/provider_ITALO"
android:gravity="center_vertical|clip_vertical"
android:padding="10dp"
android:src="@drawable/logo_italo"
android:tag="@+id/provider_ITALO" />
</LinearLayout>
<!-- Second screen - will need to do some asynchronous task -->
<RelativeLayout
android:id="@+id/view_phone_screen2"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/view_phone_screen2_lblConnectingToWifi"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:text="@string/view_phone_lblConnectToWifi_2ndstep"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/view_phone_step2_lblConnectedToWifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="58dp"
android:text="@string/view_phone_step2_connectingToWifi"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/view_phone_step2_lblPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/editText1"
android:layout_below="@+id/view_phone_step2_lblConnectedToWifi"
android:layout_marginTop="51dp"
android:text="@string/view_phone_step2_msgInputPhoneNumber"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/view_phone_step2_lblUnableDetectPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="@string/view_phone_step2_msgUnableDetectPhoneNumber"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="invisible" />
<Button
android:id="@+id/view_phone_screen2_backward"
style="@style/buttonBackward" />
<Button
android:id="@+id/view_phone_screen2_forward"
style="@style/buttonForward_disabled"
android:enabled="false" />
<EditText
android:id="@+id/view_phone_step2_txtPhoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignRight="@+id/view_phone_step2_lblPhoneNumber"
android:layout_below="@+id/view_phone_step2_lblPhoneNumber"
android:inputType="phone"
android:singleLine="true" >
<requestFocus />
</EditText>
</RelativeLayout>
</ViewFlipper>
Code example from Activity (expect to implement ALL the logic of 4+2 step wizard)
public class MyActivity extends Activity {
/** Called when the activity is first created. */
private final static String LOG_TAG = "LOG_TAG";
private int stepNumber;
@Override
public void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onCreate(savedInstanceState);
this.stepNumber=1;
setContentView(R.layout.view_phone);
//This class wraps the click for the two buttons
ProviderSelectionListener providerSelectionListener = new ProviderSelectionListener(this);
this.findViewById(R.id.view_phone_btnFrecciarossa).setOnClickListener(providerSelectionListener);
this.findViewById(R.id.view_phone_btnItalo).setOnClickListener(providerSelectionListener);
}
@Override
protected void onPause() {
super.onPause();
try {
if (MyApplication.getPlatformManager() != null)
MyApplication.getPlatformManager().onApplicationPause();
} catch (MyCustomException e) {
// WTF (Worse Than Failure!)
Log.e(LOG_TAG, super.getString(R.string.zf_error_unknown_error_pauseactivity), e);
e.printStackTrace();
}
}
@Override
protected void onResume() {
super.onResume();
try {
if (MyApplication.getPlatformManager() != null)
MyApplication.getPlatformManager().onApplicationResume();
} catch (MyCustomException e) {
// WTF (Worse Than Failure!)
Log.e(LOG_TAG, super.getString(R.string.zf_error_unknown_error_pauseactivity), e);
e.printStackTrace();
}
}
/*
* SLIDE INIZIO
*/
protected void slideNext() {
ViewFlipper vf = (ViewFlipper) findViewById(R.id.view_phone);
vf.setOutAnimation(getApplicationContext(), R.anim.slide_out_left);
vf.setInAnimation(getApplicationContext(), R.anim.slide_in_right);
vf.showNext();
}
protected void slidePrevious() {
ViewFlipper vf = (ViewFlipper) findViewById(R.id.view_phone);
vf.setOutAnimation(getApplicationContext(), R.anim.slide_out_right);
vf.setInAnimation(getApplicationContext(), R.anim.slide_in_left);
vf.showPrevious();
}
/*
* SLIDE FINE
*/
/*
* STEP 1 INIZIO
*/
public void completeStep1(ISmsWifiProvider provider) {
if (provider == null) {
Log.e(LOG_TAG, "Provider nullo");
return;
}
MyApplication.setAuthenticationProvider(provider);
slideNext();
initializeStep2();
}
public void returnToStep1() {
MyApplication.setAuthenticationProvider(null);
slidePrevious();
}
/*
* STEP 1 FINE
*/
/*
* STEP 2 INIZIO
*/
private void initializeStep2() {
// Event handler
Button backButton = (Button) findViewById(R.id.view_phone_screen2_backward), fwButton = (Button) findViewById(R.id.view_phone_screen2_forward);
fwButton.setEnabled(false);
backButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
returnToStep1();
}
});
}
/*
* STEP 2 FINE
*/
@Override
public void onBackPressed() {
// This will be called either automatically for you on 2.0
// or later, or by the code above on earlier versions of the
// platform.
return;
}
}