美文网首页
一个完整的Android应用程序(4)

一个完整的Android应用程序(4)

作者: zda123000 | 来源:发表于2018-11-05 22:02 被阅读0次

下面手动更新天气和切换城市

1. 手动更新天气
由于在之前对天气进行了缓存,目前每次展示的都是之前的缓存数据,因此需要实现用户手动更新天气。

首先修改activity_weather.xml中代码,在ScrollView的外面又嵌套了一层SwipeRefreshLayout,这样ScrollView就自动拥有了刷新功能了。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">
    ...
        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ScrollView
                android:id="@+id/weather_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:overScrollMode="never"
                android:scrollbars="none">
        ...
        </android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>

然后修改WeatherActivity中代码,首先在onCreate()方法中获取SwipeRefreshLayout的实例,然后调用setColorSchemeResources()方法来设置下拉刷新进度条的颜色,接着定义一个mWeatherId变量用来记录天气id,然后调用setOnRefreshListener()方法来设置一个下拉刷新的监听器,最后请求结束吼,调用setRefreshing()方法并传入false,用于表示刷新时间结束,隐藏刷新进度条。

public class WeatherActivity extends AppCompatActivity {
    //我是新增的
    public SwipeRefreshLayout swipeRefresh;
    private String mWeatherId;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        //我是新增的
        swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
        swipeRefresh.setColorSchemeResources(R.color.colorPrimary);

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        String weatherString = prefs.getString("weather", null);
        //我是新增的
        if (weatherString != null) {
            //有缓存直接解析天气信息
            Weather weather = Utility.handleWeatherResponse(weatherString);
            mWeatherId = weather.basic.weatherId;
            showWeatherInfo(weather);
        } else {
            // 无缓存去服务器查询天气
            mWeatherId = getIntent().getStringExtra("weather_id");
            weatherLayout.setVisibility(View.INVISIBLE);
            requestWeather(mWeatherId);
        }
        swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                requestWeather(mWeatherId);
            }
        });
        ...
    }

   public void requestWeather(final String weatherId) {
        String weatherUrl = "http://guolin.tech/api/weather?cityid=" +
                weatherId + "&key=9618c9b7080b4638a16fca8687bf9a60";

        HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(WeatherActivity.this, "获取天气信息失败1",
                                Toast.LENGTH_SHORT).show();
                        //我是新增的
                        swipeRefresh.setRefreshing(false);
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseText = response.body().string();
                final Weather weather = Utility.handleWeatherResponse(responseText);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (weather != null && "ok".equals(weather.status)) {
                            SharedPreferences.Editor editor = PreferenceManager.
                                    getDefaultSharedPreferences(WeatherActivity.this).edit();
                            editor.putString("weather", responseText);
                            editor.apply();
                            //我是新增的
                            mWeatherId=weather.basic.weatherId;
                            showWeatherInfo(weather);
                        } else {
                            Toast.makeText(WeatherActivity.this, "获取天气信息失败2",
                                    Toast.LENGTH_SHORT).show();
                        }
                        //我是新增的
                        swipeRefresh.setRefreshing(false);
                    }
                });

            }
        });
        loadBingPic();
    }
}

2. 切换城市
首先按照Material Design 的建议,我们需要在头部布局中加一个切换城市的按钮,不然用户不知道左侧边缘是可以拖动的。修改title.xml中的代码,添加一个BUtton作为切换城市的按钮。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize">
    <Button
        android:id="@+id/nav_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginLeft="10dp"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@drawable/ic_home"></Button>
      ...
</RelativeLayout>

然后修改activity_weather.xml来加入滑动菜单功能,在SwipeRefreshLayout的外面嵌套了一层DrawerLayout。DrawerLayout中第一个子控件用于作为屏幕中显示的内容,第二个子控件用于作为滑动菜单中显示的内容,因此在第二个子控件的位置添加了用于遍历省市县的数据碎片。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary">
    ...
    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.widget.SwipeRefreshLayout
            android:id="@+id/swipe_refresh"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
           ...
        </android.support.v4.widget.SwipeRefreshLayout>

        <fragment
            android:id="@+id/choose_area_fragment"
            android:name="com.example.dean.deanweather.ChooseAreaFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"></fragment>
    </android.support.v4.widget.DrawerLayout>
</FrameLayout>

然后需要在WeatherActivity中加入滑动菜单的逻辑处理,修改WeatherActivity中的代码,首先在onCreate()方法中获取新增的DrawerLayout和Button 的实例,然后在button点击事件中调用DrawerLayout的openDrawer()方法来打开滑动菜单。

public class WeatherActivity extends AppCompatActivity {
    public DrawerLayout drawerLayout;
    private Button navButton;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        navButton = (Button) findViewById(R.id.nav_button);
        ...
        navButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawerLayout.openDrawer(GravityCompat.START);
            }
        });
    }
}

上面仅仅是打开了滑动菜单而已,还需要处理切换城市后的逻辑。之前选中了某个城市后是跳转到WeatherActivity的,而现在由于外面本来是在WeatherActivity当中的,因此不需要跳转,只是去请求新选择城市的天气信息就行了。因此需要根据ChooseAreaFragment的不同状态来进行不同的逻辑处理,修改ChooseAreaFragment中的代码,instanceof 关键字可以用来判断一个对象是否属于某个类的实例。我们在碎片中调用个体Activity()方法,然后配合instanceof关键字,就能轻松的判断该碎片是MainActivity还是WeatherActivity当中。如果是在MainActivity,那么逻辑不变。如果是在WeatherActivity当中,那么关掉滑动菜单,显示下拉刷新进度条,然后请求新的城市的天气信息。

public class ChooseAreaFragment extends Fragment {
        @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (currentLevel == LEVEL_PROVINCE) {
                    selectedProvince = provinceList.get(position);
                    queryCities();
                } else if (currentLevel == LEVEL_CITY) {
                    selectedCity = cityList.get(position);
                    queryCounties();
                } else if (currentLevel == LEVEL_COUNTY) {
                    String weatherId = countyList.get(position).getWeatherId();
                    //我是新增的
                    if(getActivity() instanceof  MainActivity) {
                        Intent intent = new Intent(getActivity(), WeatherActivity.class);
                        intent.putExtra("weather_id", weatherId);
                        startActivity(intent);
                        getActivity().finish();
                    }else if(getActivity() instanceof WeatherActivity) {
                        WeatherActivity activity = (WeatherActivity) getActivity();
                        activity.drawerLayout.closeDrawers();
                        activity.swipeRefresh.setRefreshing(true);
                        activity.requestWeather(weatherId);
                    }
                }
            }
        });
        ...
    }
}
效果1
效果2

3. 后台自动更新天气
想要实现上述功能,需要创建一个长期在后台运行的定时任务。
首先在service包下新建一个服务,创建AutoUpdateService,在onStartCommand()方法中先调用了updateWeather() 方法来更新天气,然后调用了updateBingPic()方法来更新背景图片。这里直接存储到SharedPreferences文件中就可以了,因为打开WeatherActivity的时候会优先从SharedPreferences缓存中读取数据。将时间间隔设置为8小时,8小时后onStartCommand()方法重新执行。

public class AutoUpdateService extends Service {

    public AutoUpdateService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        //throw new UnsupportedOperationException("Not yet implemented");
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        updateWeather();
        updateBingPic();

        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int anhour = 8 * 60 * 60 * 1000;//8小时
        long triggerAtTime = SystemClock.elapsedRealtime() + anhour;
        Intent i = new Intent(this, AutoUpdateService.class);
        PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
        manager.cancel(pi);
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
        return super.onStartCommand(intent, flags, startId);
    }

    private void updateWeather() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        String weatherString = prefs.getString("weather", null);
        if (weatherString != null) {
            Weather weather = Utility.handleWeatherResponse(weatherString);
            final String weatherId = weather.basic.weatherId;

            String weatherUrl = "http://guolin.tech/api/weather?cityid=" + weatherId +
                    "&key=9618c9b7080b4638a16fca8687bf9a60";
            HttpUtil.sendOkHttpRequest(weatherUrl, new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String responseText = response.body().string();
                    Weather weather = Utility.handleWeatherResponse(responseText);
                    if (weather != null && "ok".equals(weather.status)) {
                        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(
                                AutoUpdateService.this).edit();
                        editor.putString("weather", responseText);
                        editor.apply();
                    }
                }

            });
        }
    }

    /**
     * 更新每日一图
     */
    private void updateBingPic() {
        String requestBingPic = "http://guolin.tech/api/bing_pic";
        HttpUtil.sendOkHttpRequest(requestBingPic, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String bingPic = response.body().string();
                SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(
                        AutoUpdateService.this).edit();
                editor.putString("bing_pic", bingPic);
                editor.apply();
            }
        });
    }
}

最后去激活AutoUpdateService 这个服务就行

private void showWeatherInfo(Weather weather) {
            ...
            Intent intent = new Intent(this,AutoUpdateService.class);
            startService(intent);
       
    }

基本功能就已经完成了,后续会继续添加其他功能

源码地址

相关文章

网友评论

      本文标题:一个完整的Android应用程序(4)

      本文链接:https://www.haomeiwen.com/subject/grjexqtx.html