one

I remember that I once participated in the development of a Huawei project, which required that the program could support several kinds of terminal devices, including Android phones and Android Pads. Then, in order to save manpower, the company shamelessly made Android phones and Android Pads developed by our team. At that time, the project team decided to make two versions of App, one for mobile phone and one for Pad. Since the main features of the mobile version were already done, the Pad version basically copied the code from the mobile version and then tweaked it to fit the features of the tablet.

But since then we have been very helpless and miserable. The same code is written twice each time a new feature is added. Every time you fix a bug, do it in the mobile code and in the Pad code. That’s not a big deal, and it gets worse every time it gets published. Huawei requires that two versions be issued each time, one for huawei’s internal network environment and one for customers’ site. Now, four versions are issued each time for mobile phones and pads. If there is a problem with the self-test after the release of the version, you can directly overnight. This is especially hard on our manager X (I like to call him God X because of his good dota). He maintained a module separately in our project team, and he was responsible for every version typing. We could run when working overtime, but he could not run. Here is also a compliment to god X for his professionalism, if he can see it.

After going through that period of helplessness and pain, I began to think about whether I could make an App compatible with both mobile phones and tablets. Of course, the answer is yes, but I am a lazy person, has not been able to raise the spirit to study this problem. It was not until my friend Gong, who was studying in the United States, asked me to help her solve an assignment assigned by her graduate supervisor (I know your graduate supervisor can’t read Chinese ^-^) that I took the opportunity to study it and now SHARE it with you.

two

Let’s take a look at the Android phone’s Settings screen. Click on Sound to jump to the Sound Settings screen, as shown in the following two images:

           

Then take a look at the Settings screen of the Android Pad. The main Settings screen and the sound Settings screen are displayed in the same screen, as shown below:

It would not be surprising if these were two different apps. But if it’s the same App, running it on a phone and a tablet has two of the above effects, are you tempted? So let’s simulate that now.

First, you need to have some knowledge of fragments. If you haven’t been exposed to fragments, it is recommended that you read the article Android Fragment Complete Parsing, everything you need to know about fragments. And this code is running on Android 4.0 version, if your SDK version is still relatively low, it is suggested to upgrade first.

Create a new Android project and call it FragmentDemo. Open or create a new MainActivity as the MainActivity of the program, which has the following automatically generated content:

public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}Copy the code

For an Android veteran, the above code is pretty trivial; it comes with every Activity. But today our program will not be so simple, loading the layout of this piece is still a great article.

Open or create res/layout/activity_main. XML as the main layout file of the application.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity" >
 
    <fragment
        android:id="@+id/menu_fragment"
        android:name="com.example.fragmentdemo.MenuFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />
 
</LinearLayout>
Copy the code

This layout refers to a MenuFragment, which we will implement later. First, we need to create a new activity_main.xml file with the same file name as the main layout file, but in a different directory.

Create a new layout-large directory in the res directory. Then create a new activity_main.xml directory and add the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
    android:baselineAligned="false"
    tools:context=".MainActivity"
    >
 
    <fragment
        android:id="@+id/left_fragment"
        android:name="com.example.fragmentdemo.MenuFragment"
        android:layout_width="0dip"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        />
    
    <FrameLayout 
        android:id="@+id/details_layout"
        android:layout_width="0dip"
        android:layout_height="fill_parent"
        android:layout_weight="3"
        ></FrameLayout>
 
</LinearLayout>
Copy the code

The layout also references the MenuFragment and adds a FrameLayout to display the details. This corresponds to the left and right layouts of the tablet interface.

The technique of loading the layout dynamically is used here. The first call to setContentView(r.layout.activity_main) in the Activity indicates that the current Activity wants to load the activity_main layout file. The Android operating system determines if the application is running on a larger screen based on the current operating environment. If it is running on a larger screen, load activity_main.xml in the layout-large directory. Otherwise, the default is to load activity_main.xml in the Layout directory.

For more on dynamically loaded layouts, you can read Android’s official full approach to supporting different screen sizes.

three

Create a MenuFragment class that inherits its own Fragment. The code is as follows:

Public class MenuFragment extends Fragment implements OnItemClickListener {/** * The menu interface contains only one ListView. */ private ListView menuList; /** * ListView adapter. */ private ArrayAdapter<String> adapter; /** * is used to populate the ListView with data. */ private String[] menuItems = { "Sound", "Display" }; /** * whether to double page mode. If an Activity contains two fragments, it is in two-page mode. */ private boolean isTwoPane; /** * Initializes the data in the adapter when an Activity is associated with a Fragment. */ @Override public void onAttach(Activity activity) { super.onAttach(activity); adapter = new ArrayAdapter<String>(activity, android.R.layout.simple_list_item_1, menuItems); } /** * load the menu_fragment layout file, bind the adapter to the ListView, and set the listening event. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.menu_fragment, container, false); menuList = (ListView) view.findViewById(R.id.menu_list); menuList.setAdapter(adapter); menuList.setOnItemClickListener(this); return view; } /** * When the Activity is created, try to see if the detailS_Layout element is present in the layout file. If it is, it is currently in two-page mode; if it is not, it is currently in one-page mode. */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (getActivity().findViewById(R.id.details_layout) ! = null) { isTwoPane = true; } else { isTwoPane = false; }} /** * Handle the ListView click event based on whether it is currently in double-page mode. In two-page mode, fragments are added dynamically. * If it is not in two-page mode, a new Activity is opened. */ @Override public void onItemClick(AdapterView<? > arg0, View view, int index, long arg3) { if (isTwoPane) { Fragment fragment = null; if (index == 0) { fragment = new SoundFragment(); } else if (index == 1) { fragment = new DisplayFragment(); } getFragmentManager().beginTransaction().replace(R.id.details_layout, fragment).commit(); } else { Intent intent = null; if (index == 0) { intent = new Intent(getActivity(), SoundActivity.class); } else if (index == 1) { intent = new Intent(getActivity(), DisplayActivity.class); } startActivity(intent); }}}Copy the code

The code for this class isn’t very long, so I’ll just explain it briefly. In the onCreateView method we load the menu_fragment layout, which contains a ListView. Then we fill the ListView with two simple data “Sound” and “Display”. The onActivityCreated method makes a judgment that if the Activity layout contains the detailS_layout element, it is currently in two-page mode, otherwise it is in single-page mode. The onItemClick method handles the ListView click event and dynamically adds a Fragment to detailS_Layout if it is currently in two-page mode, or directly opens a new Activity if it is currently in single-page mode.

We added the other references to MenuFragment one by one. Create a new menu_fragment. XML file and add the following code:

<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > android:id="@+id/menu_list" android:layout_width="fill_parent" android:layout_height="fill_parent"Copy the code

Then create a new SoundFragment, which is very simple:

public class SoundFragment extends Fragment {

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

		View view = inflater.inflate(R.layout.sound_fragment, container, false);
Copy the code

The sound_fragment. XML layout file is used for SoundFragment, so we create a new layout file and add the following code:

<? The XML version = "1.0" encoding = "utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#00ff00" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="28sp" android:textColor="#000000" android:text="This is sound view" /> </RelativeLayout>Copy the code

For the same reason, let’s create the DisplayFragment and display_fragment.xml layout files:

public class DisplayFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.display_fragment, container, false); return view; }}Copy the code
<? The XML version = "1.0" encoding = "utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0000ff" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textSize="28sp" android:textColor="#000000" android:text="This is display view" /> </RelativeLayout>Copy the code

Then create a new SoundActivity with the following code:

public class SoundActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sound_activity); }}Copy the code

The Activity simply loads a layout file. Now we implement the sound_activity.xml layout file:

<? The XML version = "1.0" encoding = "utf-8"? > <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/sound_fragment" android:name="com.example.fragmentdemo.SoundFragment" android:layout_width="match_parent" android:layout_height="match_parent" > </fragment>Copy the code

The layout file references the SoundFragment. The nice thing about this is that later on we just need to modify the code in the SoundFragment and the SoundActivity will automatically change because all of its code is referenced from the SoundFragment.

Ok, same way, we’ll do DisplayActivity again:

public class DisplayActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.display_activity); }}Copy the code

Then add display_activity.xml:

<? The XML version = "1.0" encoding = "utf-8"? > <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/display_fragment" android:name="com.example.fragmentdemo.DisplayFragment" android:layout_width="match_parent" android:layout_height="match_parent" > </fragment>Copy the code

four

Now that all the code is complete, let’s take a look.

First run the program on a mobile phone, the effect picture is as follows:

Click Sound and Display respectively to jump to Sound and Display:

           

Then run the app on the tablet, click Sound, and look like this:

Then click Display to switch to the Display interface, and the effect picture is as follows:

So we’ve successfully made the app compatible with both phones and tablets. Of course, this is only a simple demo, more complex content needs to be implemented by ourselves.

Well, this is the end of today’s explanation, if you have questions, please leave a message below.

To download the source code, click here

Pay attention to my technical public account “Guo Lin”, there are high-quality technical articles pushed every day.