This paper develops an application to learn the basic concepts of Android and its UI components.
The application developed is called GeoQuiz, which can give a lot of questions about geographic knowledge. Users click the true or false button to answer questions, and the application gives immediate feedback.
First step, please create a new project by yourself. The catalogue is as follows.
1. User Interface Design
- Define components in an XML file (activity_quiz.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/question_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="24dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/true_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/true_button"/> <Button android:id="@+id/false_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/false_button"/> </LinearLayout> <Button android:id="@+id/cheat_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/cheat_button"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/pre_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/pre_button" android:drawableLeft="@drawable/arrow_left"/> <ImageButton android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/arrow_right" android:contentDescription="@string/next_button"/> </LinearLayout> </LinearLayout>
activity_quiz.xml rendering
- Create string resources
It is better not to hard-code the text information of the settings component, such as: android:text="True". Better practice is to place text content in a separate string resource XML file and reference them, such as: android: text="@string/true_button".
Find the app/res/values directory and open the string.xml file
Add string resources
<resources> <string name="app_name">GeoQuiz</string> <string name="true_button">True</string> <string name="false_button">False</string> <string name="pre_button">Pre</string> <string name="next_button">Next</string> <string name="correct_toast">Correct!</string> <string name="incorrect_toast">Incorrect!</string> <string name="question_oceans">The Pacific Ocean is larger than the Atlantic Ocean.</string> <string name="question_mideast">The Suez Canal connects the Red Sea and the Indian Ocean.</string> <string name="question_africa">The source of the Nile River is in Egypt.</string> <string name="question_americas">The Amazon River is the longest river in the Americas.</string> <string name="question_asia">Lake Baikal is the world\'s oldest and deepest freshwater lake.</string> <string name="warning_text">Are you sure you want to do this?</string> <string name="show_answer_button">SHOW ANSWER</string> <string name="cheat_button">CHEAT!</string> <string name="judgment_toast">Cheating is wrong.</string> <string name="fist_page">This is the first page!</string> </resources>
2. From Layout XML to View Objects
- After the instance of activity subclass is created, the onCreate(Bundle) method will be invoked, and the user interface needs to be acquired and managed. SetContentView (int layout ResID) can be called again. According to the input layout resource ID parameters, the specified layout view is generated and placed on the screen. The components contained in the layout file are instantiated with their respective attribute definitions.
public class QuizActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz); } }
- Resource and Resource ID
- Use the resource ID to get the corresponding resources in the code. The resource ID of activity_quiz.xml layout is R.layout.activity_quiz.
- Place all current resources in R.java files. Switch to the Project view and expand the directory app/build/generated/source/r.debug to see. R.java files are automatically generated during the compilation of Android projects. After modifying the layout or strings and other resources, the application needs to be run again before it can be updated.
- Add a resource ID for the required components. Such as: android:id="@+id/idName".
- Application of Components
private Button mTrueButton;//Add member variables to activity_quiz.java @Override protected void onCreate(Bundle savedInstanceState) { ...... mTrueButton=(Button)findViewById(R.id.true_button);//Reference component mTrueButton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { //Setting up listening events } }); }
3. Create prompt messages
Android toast is a short pop-up message used to notify users. The following method of calling the Toast class can create toast:
public static Toast makeText(Context context,int resId,int durattion)
- The Context parameter is usually an instance of Activity (Activity itself is a subclass of Context).
- The second parameter is toast to display the resource ID of the string message.
- The third parameter is used to specify the residence time of the toast message. Usually one of the Toast constants.
//For example Toast.makeText(QuizActivity.this,R.string.incorrect_toast,Toast.LENGTH_SHORT).show();
4. Android and MVC Design Patterns
- The application object is divided into three parts according to the categories of model, controller and view. Android Application Based on Model-
The architecture pattern of Model-View-Controller (MVC) is designed. MVC design pattern shows that any object applied in the final analysis belongs to one of the model objects, view objects and control objects.
- We use QuizActivity to create Question array objects. Then, by interacting with TextView and three Button s, geographic knowledge questions are displayed on the screen and feedback is given based on the user's answers, as shown in Figure 2-4.
- Model Layer Question Class Code
public class Question { private int mTextResId;//Save the resource ID of the Geographic Knowledge Problem String. Resource ID is always int type private boolean mAnswerTrue;//Question answer public Question(int textResId,boolean answerTrue){ mTextResId=textResId; mAnswerTrue=answerTrue; } public int getTextResId() { return mTextResId; } public void setTextResId(int textResId) { mTextResId = textResId; } public boolean isAnswerTrue() { return mAnswerTrue; } public void setAnswerTrue(boolean answerTrue) { mAnswerTrue = answerTrue; } }
Generating getter and setter methods for member variables with prefix m
First, configure the m prefix of Android Studio to identify member variables.
Open the Android Studio preferences dialog box (Mac users select the Android Studio menu, Windows users select File_
Settings menu. Expand the Editor and Code Style options, respectively, and select the Code Generation option page under the Java option. In the Naming form, select the fields row and add m as the prefix for fields. To add the static variable prefix s, add s as the prefix of Static Fields. The following diagram.
- Controller layer QuizActivity.java
public class QuizActivity extends AppCompatActivity { private ImageButton mNextButton; private TextView mQuestionTextView; private Question[] mQuestionBank=new Question[]{ new Question(R.string.question_oceans,true), new Question(R.string.question_mideast,false), new Question(R.string.question_africa,false), new Question(R.string.question_americas,true), new Question(R.string.question_asia,true) }; private int mCurrentIndex=0; }
5. Adding Picture Resources
1.Add images to drawable In the corresponding directory, the suffix is named.png,.jpg,.gif Documents automatically get resources ID
- mdpi:Medium Pixel Density Screen(About 160 dpi)
- hdpi:High Pixel Density Screen(About 240 dpi)
- xhdpi:Ultra-high Pixel Density Screen(About 320 dpi)
- xxdpi:Ultra-high Pixel Density Screen(About 480 dpi)
2. stay XML Reference resources in files
- by next Button to add pictures(activity_quiz.xml)
<Button android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/next_button" android:drawableLeft="@drawable/arrow_righ android:drawablePadding="4dp"/>
* The definition starting with @string/ is to refer to string resources*
* The definition starting with @drawable/ is to refer to drawable resources*
The ImageButton component inherits from the ImageView. Button components inherit from TextView. ImageView and TextView inherit from View
ImageButton components can also be replaced by Button components. Delete the text and drawable attribute definitions of the next button and add the ImageView attribute.
<ImageButton android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/arrow_right" android:contentDescription="@string/next_button"/>
6. The life cycle of activity
When the device rotates, the system destroys the current QuizActivity instance and creates a new QuizActivity instance. So every time the user of the rotating device starts with the first question, it's time to correct the defect.
- Creating horizontal pattern layout
Right-click the res directory and select New - > Android resource directory. Select layout for resource type, keep the main option of Source set unchanged, select Orientation in the list of resources to be selected, and then click the > button to move it to the selected resource feature area.
Finally, confirm that the Landscape option is selected in the Screen orientation drop-down list and ensure that the directory name is displayed as layout-land.
The - land suffix name here is another example of the use of configuration modifiers. Android relies on the configuration modifier of the res subdirectory to locate the best resource to match the current device configuration. When the device is in the horizontal direction, Android will find and use the layout resources in the res/layout-land directory. In other cases, it defaults to using layout resources in the res/layout directory.
- Copy the activity_quiz.xml file in the res/layout directory to the res/layout-land directory.
Note: The file names of the two layout files must be the same so that they can be referenced with the same resource ID
- Horizontal pattern layout modification (layout-land/activity_quiz.xml)
FrameLayout replaces the top-level Linear Layout. FrameLayout is the simplest ViewGroup component, which arranges the location of its subviews anyway. The placement of FrameLayout subviews depends on their respective android:layout_gravity attributes.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/question_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:padding="24dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" android:orientation="horizontal"> <Button android:id="@+id/true_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/true_button"/> <Button android:id="@+id/false_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/false_button"/> </LinearLayout> <Button android:id="@+id/cheat_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center" android:text="@string/cheat_button"/> <Button android:id="@+id/pre_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|left" android:text="@string/pre_button" android:drawableLeft="@drawable/arrow_left" android:drawablePadding="4dp"/> <ImageButton android:id="@+id/next_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:src="@drawable/arrow_right" android:contentDescription="@string/next_button"/> </FrameLayout>
- Save data for device rotation
Override the following Activity methods
protected void onSaveInstanceState(Bundle outState)
- This method is usually called by the system before the onStop() method unless the user presses the back key.
- The default implementation of this method requires all active views to store their data state in Bundle objects. Bundle is a structure that stores the mapping relationship (key-value pairs) between string keys and defined type values.
public class QuizActivity extends AppCompatActivity { ...... private int mCurrentIndex=0; private static final String KEY_INDEX="index"; @Override protected void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); savedInstanceState.putInt(KEY_INDEX,mCurrentIndex); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz); if(savedInstanceState!=null){ mCurrentIndex=savedInstanceState.getInt(KEY_INDEX,0); } ...... } ...... }
7. log
public static int d(String tag,String msg)//Output log information d:debug
The first parameter of a method is usually passed in as a TAG constant with a class name value
public class QuizActivity extends AppCompatActivity { private static final String TAG="QuizActivity"; ...... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG,"onCreate(Bundle) called"); setContentView(R.layout.activity_quiz); ...... } }
log level | Method | Explain |
---|---|---|
ERROR | Log.e(...) | error |
WARNING | Log.w(...) | warning |
INFO | Log.i(...) | Informational message |
DEBUG | Log.w(...) | Debug output |
VERBOSE | Log.v(...) | For development only |
All logging methods have two parameter signatures: tag and msg parameters of string type, and Throwable instance parameters in addition to tag and msg parameters.
9. Second activity
The new activity will bring a second user interface that will make it easier for users to peek at the answers to questions.
Definition of the layout component of the second activity (activity_cheat.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" tools:context="com.example.mdx.studyworks.CheatActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="24dp" android:text="@string/warning_text"/> <TextView android:id="@+id/answer_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="24dp" tools:text="Answer"/> <Button android:id="@+id/show_answer_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/show_answer_button"/> </LinearLayout>
activity_cheat.xml rendering
- Note the TextView component for displaying answers, which has a special namespace for tools and tools:text attributes. The namespace can override any property of a component. In this way, you can see the effect in the preview, while the Answer text will not appear at run time.
- All activities of an application must be declared in the manifest configuration file so that the operating system can find them.
//Declare CheatActivity in manifest configuration file <activity android:name=".CheatActivity"> </activity>
Start the activity
public void startActivity(Intent intent)
When activity calls the startActivity(Intent) method, the call request is actually sent to the ActiveyManager of the operating system. Activity Manager is responsible for creating an Activity instance and calling its onCreate(Bundle) method
public Intent(Context pageContext,Class<?> cls)
The Class type parameter passed into the method tells ActivityManager which activity to start
The Context parameter tells Activity Manager where to find it
mCheatButton=(Button)findViewById(R.id.cheat_button); mCheatButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Start CheatActivity from QuizActivity Intent i=new Intent(QuizActivity.this,CheatActivity.class); startActivity(i); } });
Data Transfer Between Activities
- Use intent extra
Add extra data information to intent and call the Intent.putExtra(...) method
public Intent putExtra(String name,boolean value)
Intent i=new Intent(QuizActivity.this,CheatActivity.class); i.putExtra(EXTRA_ANSWER_IS_TRUE,answerIsTrue); startActivity(i)
Getting data from extra
public boolean getBooleanExtra(String name,boolean defaultValue)
mAnswerIsTrue=getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE,false);
The Activity.getIntent() method returns the Intent object forwarded by the startActivity(Intent) method.
- Get the return result from the subactivity
//Father activity /*The second parameter is the request code.*/ public void startActivityForResult(Intent intent,int requestCode) //There are two ways for child activity to send back information to parent activity public final void setResult(int resultCode) public final void setResult(int resultCode,Intent data)
resultCode can be any of the following predefined constants
- Activity.RESULT_OK, or 1
- Activity.RESULT_CANCELED, or 0
If you need to customize the result code, you can also use another constant: RESULT_FIRST_USER
//Father, QuizActivity private static final int REQUEST_CODE_CHEAT=0; mCheatButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean answerIsTrue=mQuestionBank[mCurrentIndex].isAnswerTrue(); Intent i=new Intent(QuizActivity.this,CheatActivity.class); i.putExtra(EXTRA_ANSWER_IS_TRUE,answerIsTrue); startActivityForResult(i,REQUEST_CODE_CHEAT); } }); //Processing returned results @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //super.onActivityResult(requestCode, resultCode, data); //Result code inconsistency if (resultCode!= Activity.RESULT_OK){ return; } //The result code is consistent if (requestCode==REQUEST_CODE_CHEAT){ if (data==null){ return; } //Analytic result intent mIsCheater=data.getBooleanExtra(EXTRA_ANSWER_SHOW,false); } }
//Son, CheatActivity Intent data=new Intent(); data.putExtra(EXTRA_ANSWER_SHOW,isAnswerShown); setResult(RESULT_OK,data);//Set the return result
10. Use and management of activity
Designated as the first activity of the application
<!--Specify the first activity yes QuizActivity--> <activity android:name=".QuizActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>