iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Mobile Development

Android Studio開發系列 第 28

【DAY 28】元件整合實作:製作一個簡易的氣象資訊系統-4-利用tablayout+viewpager及API+retrofit實作簡易氣象資訊系統(上)

  • 分享至 

  • xImage
  •  

今天我們進入最主要的功能,也就是利用API+retrofit抓取兩種氣象局開放平台的資料,在這之前,我們要先做出兩個分頁,然後以tablayout+viewpager的方式分別加入兩種資料。

首先我們先在MainActivity拉出元件tablayout和viewpager,其中tablayout有兩個item,方法就跟之前介紹的一樣,如果還沒有看過的可以參閱先前的文章。

這裡先將layout附上:
activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tl"
        android:layout_width="409dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:tabSelectedTextColor="#FF0072E3"
        app:tabTextColor="#FFADADAD"
        app:tabIndicatorColor="#FF0072E3">

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="1" />

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="2"
            tools:layout_editor_absoluteX="138dp"
            tools:layout_editor_absoluteY="129dp" />

    </com.google.android.material.tabs.TabLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp2"
        android:layout_width="409dp"
        android:layout_height="609dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

tab的樣式也可以參閱之前的文章。


再來新增兩個fragment,將兩個fragment綁定在tablayout和viewpager,同樣利用之前介紹的方法。
添加一個適配器FragmentMainAdapter:
FragmentMainAdapter:

public class FragmentMainAdapter extends FragmentStateAdapter {
    Fragment1 fragment_1;
    Fragment2 fragment_2;
    public FragmentMainAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0:
                fragment_1 = new Fragment1();
                return fragment_1;
            default:
                fragment_2 = new Fragment2();
                return fragment_2;
        }
    }

    @Override
    public int getItemCount(){
        return 2;
    }
}

MainActivity:

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;
    private ViewPager2 viewPager2;
    private String[] tab_title = {"各縣市氣溫資訊","各地區氣候資訊"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tabLayout=findViewById(R.id.tl);
        viewPager2=findViewById(R.id.vp2);

        viewPager2.setAdapter(new FragmentMainAdapter(getSupportFragmentManager(),getLifecycle()));

        new TabLayoutMediator(tabLayout, viewPager2,true, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                viewPager2.setCurrentItem(tab.getPosition());
            }
        }).attach();
        for(int i = 0 ; i < tabLayout.getTabCount() ; i++){
            tabLayout.getTabAt(i).setText(tab_title[i]);
        }
    }
}

再來就介紹下fragment1的介面,這個介面我們會將抓取到各縣市的最高氣溫與最低氣溫顯示出來。使用到的元件有:四個textview、一個spinner、一個button。

完成如右:
可以使用選單選擇縣市,選擇完按下搜尋按鈕後,就會將抓取到的資料顯示在中間兩個框中,分別顯示出最高氣溫與最低氣溫。


大部分的製作方法可以參閱之前介紹API的文章,裡面有實作的過程,這裡就不再贅述。值得一提的是,主要程式都是寫在onViewCreated()中,但綁定元件的部分,我們移至onCreateView()這個方法中進行:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_1, container, false);
    //綁定元件及變數
    bts=view.findViewById(R.id.search);
    tvMax=view.findViewById(R.id.tvMax);
    tvMin=view.findViewById(R.id.tvMin);
    spinner = view.findViewById(R.id.spinner);
    return view;
}

因為fragment中沒有findViewById()方法,所以我們設定一個變數view,並將介面綁定給view,再以view呼叫findViewById()方法。


這裡直接附上fragment1的程式:
fragment1:

public class Fragment1 extends Fragment {
    private static final String base="https://opendata.cwb.gov.tw/api/v1/rest/datastore/";
    //金鑰
    private static final String author="填入金鑰";
    //想要抓取的元素名稱
    private static final String element1="MaxT",element2="MinT";
    //定義變數
    private Button bts;
    private TextView tvMax,tvMin;
    private String location=city[0];
    private Spinner spinner;
    //定義下拉式選單的內容
    static final String[] city=
            {"宜蘭縣","花蓮縣","臺東縣","澎湖縣","金門縣","連江縣","臺北市","新北市","桃園市","臺中市","臺南市",
                    "高雄市","基隆市","新竹縣","新竹市","苗栗縣","彰化縣","南投縣","雲林縣","嘉義縣","嘉義市","屏東縣"};
    static final String[] array1= {element1,element2};
    public Fragment1() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_1, container, false);
        //綁定元件及變數
        bts=view.findViewById(R.id.search);
        tvMax=view.findViewById(R.id.tvMax);
        tvMin=view.findViewById(R.id.tvMin);
        spinner = view.findViewById(R.id.spinner);
        return view;
    }
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(base)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        weather myAPIService = retrofit.create(weather.class);

        //下拉式選單設定
        ArrayAdapter<CharSequence> adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_spinner_item,city);
        spinner.setAdapter(adapter);

        //下拉式選單監聽器
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                location=city[i];
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {
            }
        });

        bts.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                for(int j=0;j<2;j++)
                {
                    if(j==0)
                    {
                        myAPIService.getweather(author, location, array1[j]).enqueue(new Callback<MyResponse>() {
                            @Override
                            public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
                                Log.d("title", "請求成功");
                                //Log.d("title", response.body().records.location.get(0).locationName);
                                //Log.d("title", response.body().records.location.get(0).weatherElement.get(0).time.get(0).parameter.parameterName);
                                tvMax.setText(location + "今日最高溫度:" + response.body().records.location.get(0).weatherElement.get(0).time.get(0).parameter.parameterName
                                        + '°' + response.body().records.location.get(0).weatherElement.get(0).time.get(0).parameter.parameterUnit);
                            }

                            @Override
                            public void onFailure(Call<MyResponse> call, Throwable t) {
                                Log.d("title", "請求失敗");
                            }
                        });
                    }
                    else if(j==1)
                    {
                        myAPIService.getweather(author, location, array1[j]).enqueue(new Callback<MyResponse>() {
                            @Override
                            public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
                                tvMin.setText(location + "今日最低溫度:" + response.body().records.location.get(0).weatherElement.get(0).time.get(0).parameter.parameterName
                                        + '°' + response.body().records.location.get(0).weatherElement.get(0).time.get(0).parameter.parameterUnit);
                            }

                            @Override
                            public void onFailure(Call<MyResponse> call, Throwable t) {
                            }
                        });
                    }
                }
            }
        });
    }
}

完成之後來看下成果:


今天就先做完fragment1,明天來繼續做fragment2~~


上一篇
【DAY 27】元件整合實作:製作一個簡易的氣象資訊系統-3-透過SharedPreferences傳送註冊資料
下一篇
【DAY 29】元件整合實作:製作一個簡易的氣象資訊系統-5-利用tablayout+viewpager及API+retrofit實作簡易氣象資訊系統(下)
系列文
Android Studio開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言