• Widget小练习


      WIDGET是安卓桌面的控件,使用方便直观。That's cool,isn't it?

      WIDGET的本质是一个BroadcastReceiver,它有自己的生命周期。生命周期的方法如下:

      1.onEnabled方法:此方法在Widget第一次被创建的时候调用,并且只调用一次,此方法中常放入初始化数据,服务的操作。

          2.onReceive方法:通BroadcastReceiver的OnReceive方法,但是这里有所不同的是,当接收到Widget操作时首先调用的是OnReceive方法,然后才是相关的操作方法。这也

    很好理解,Widget的是运行在桌面运用程序中的小控件,当自己的应用程序需要调用Widget是,就需要发送广播事件去调用。

          3.onUpdate:Widget在固定的时间里更新时调用的方法。

          4.onDeleted:Widget被删除时调用的方法。

          5.onDisabled:所用Widget被删除是调用的方法,同onEnabled方法相对。

      本例设计了一个实时天气的WIDGET。WIDGET的显示板上显示了当天的所选城市的天气。点击显示板,可以查看所选城市的详细天气并允许修改城市。程序还会根据天气更换不同的手机壁纸。

      AndroidMainfest.xml  

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.memeda.lsy.widgettest">
    
        <application android:allowBackup="true" android:label="@string/app_name"
            android:icon="@drawable/ic_launcher" android:theme="@style/AppTheme">
            <receiver android:label="Hello,App Widget" android:name=".HelloWidgetProvider">
                <intent-filter>
                    <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
                    <action android:name="com.demo.appwidget.refresh"></action>
                </intent-filter>
                <meta-data android:resource="@xml/provider_info" android:name="android.appwidget.provider"></meta-data>
            </receiver>
            <activity android:name=".SetWeatherUI"/>     
            <service android:name=".Weather_Service"/>
        </application>
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.SET_WALLPAPER"/>
    </manifest>

      应用申请了壁纸更改的权限用来更改壁纸,还申请了网络权限用以获取天气信息。

      值得注意的是,WIDGET桌面小控件的入口不再是一个activity,而变成了一个receiver。

      provider_info.xml

    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:minWidth="225dip"
        android:minHeight="70dip"
        android:initialLayout="@layout/main"/>

      设置桌面组件的长宽及初始layout文件。此例面板为一格高,三格宽。

      main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <AnalogClock
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/analogClock"
    
            android:layout_weight="2"/>
        <TextView
            android:id="@+id/textview"
            android:gravity="left"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="请点击设置城市"
            android:textSize="20sp"
            android:layout_weight="1"
            />
    </LinearLayout>

      设置了WIDGET的面板布局,该布局由一个时钟和一个TextView水平组成。

      HelloWidgetProvider.java

    package com.memeda.lsy.widgettest;
    
    import android.app.PendingIntent;
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.Message;
    import android.text.format.Time;
    import android.widget.RemoteViews;
    import android.widget.Toast;
    /**
     * Created by Administrator on 2015/2/9.
     */
    public class HelloWidgetProvider extends AppWidgetProvider {
        static public Context myContext;
        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);
        }
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
            myContext.startService(new Intent(myContext,Weather_Service.class));
            Toast.makeText(context,"请设置城市",Toast.LENGTH_SHORT).show();
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.main);
            //设置点击事件,打开Activity
            Intent intent = new Intent(context,SetWeatherUI.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context,0,intent,0);
            remoteViews.setOnClickPendingIntent(R.id.textview,pendingIntent);
            appWidgetManager.updateAppWidget(appWidgetIds[0],remoteViews);
        }
        @Override
        public void onEnabled(Context context) {
            super.onEnabled(context);
            this.myContext = context;
        }
    }

       设置WIDGET的初始状态。因为随着时间变长,onUpdate是会失去响应的,所以只能算初始状态(至于为什么我也不知道,忘大大指点一下)。将main.xml中的textview显示面板设为可点击的,其点击事件即是打开SetWeatherUI.class这个Activity。

      接下来我们来看看SetWeatherUI这个Activity。

      set_city_ui.xml  

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <EditText
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="8"
                android:id="@+id/cityInput"
                android:hint="请输入您的城市"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:id="@+id/cityButton"
                android:layout_gravity="center"
                android:textSize="20sp"
                android:text="获取天气"/>
            </LinearLayout>
    
        <TextView
            android:id="@+id/cityWeather"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="left"
            android:minLines="5"
            android:textSize="20sp"
            />
    </LinearLayout>

      以上是SetWeatherUI的布局文件主要包含了一个EditText用来输入城市,一个Button用来确认,一个TextView用来显示所选城市的天气详细信息。

      SetWeatherUI.java

    package com.memeda.lsy.widgettest;
    
    import android.app.Activity;
    import android.app.PendingIntent;
    import android.app.ProgressDialog;
    import android.appwidget.AppWidgetManager;
    import android.content.BroadcastReceiver;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.SharedPreferences;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.RemoteViews;
    import android.widget.TextView;
    
    import com.memeda.lsy.widgettest.net.UrlGetWeatherUtil;
    
    import java.util.Map;
    
    /**
     * Created by Administrator on 2015/2/10.
     */
    public class SetWeatherUI extends Activity {
        EditText cityInput;
        TextView cityWeather;
        Button   cityButton;
        String stringCityName;
        String weatherString,weatherDetails;
        ProgressDialog dialog2;
        ActivityReceive activityReceive;
        SharedPreferences sharedPreferences;
        SharedPreferences.Editor editor;
        public final static String WEATHER_SER = "com.memeda.lsy.action.WEATHER_SER";
        public final static String WEATHER_ACTI= "com.memeda.lsy.action.WEATHER_ACTI";
    
        public class ActivityReceive extends BroadcastReceiver {
    
            @Override
            public void onReceive(Context context, Intent intent) {
                String state = intent.getStringExtra("state");
                switch (state){
                    case "Loading":
                        dialog2 = ProgressDialog.show(context , "提示", "加载中……");
                        //dialog2.show();
                        break;
                    case "finishLoading":
                        dialog2.cancel();
                        weatherDetails = intent.getStringExtra("weatherDetail");
                        cityWeather.setText(weatherDetails);
                        weatherString=intent.getStringExtra("weatherString");
                        RemoteViews appWidgetView = new RemoteViews(SetWeatherUI.this.getPackageName(),R.layout.main);
                        appWidgetView.setTextViewText(R.id.textview,weatherString);
                        AppWidgetManager.getInstance(SetWeatherUI.this)
                                .updateAppWidget(new ComponentName(SetWeatherUI.this, HelloWidgetProvider.class), appWidgetView);
                        break;
                    default:
                        cityWeather.setText("未响应");
                        break;
                }
            }
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.set_city_ui);
            activityReceive = new ActivityReceive();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(WEATHER_ACTI);
            registerReceiver(activityReceive,intentFilter);
            Intent intent =new Intent(SetWeatherUI.this,Weather_Service.class);
            startService(intent);
    
            sharedPreferences=getSharedPreferences("weatherInfo",MODE_WORLD_READABLE);
            editor=sharedPreferences.edit();
            stringCityName=sharedPreferences.getString("cityName","北京");
            Intent intentInit = new Intent(WEATHER_SER);
            intentInit.putExtra("command","changeCity");
            intentInit.putExtra("cityName",stringCityName);
            sendBroadcast(intentInit);
    
            cityInput= (EditText) findViewById(R.id.cityInput);
            cityInput.setText(stringCityName);
            cityWeather= (TextView) findViewById(R.id.cityWeather);
            cityButton = (Button) findViewById(R.id.cityButton);
            cityButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    stringCityName=cityInput.getText().toString();
                    Intent intent = new Intent(WEATHER_SER);
                    intent.putExtra("command","changeCity");
                    intent.putExtra("cityName",stringCityName);
                    sendBroadcast(intent);
                    editor.putString("cityName",stringCityName);
                    editor.commit();
                }
            });
        }
    }

      SetWeatherUI只做了4件事:1、更新Activity界面;2、更新WidGet;3、向Service发请求获取天气信息;4、保存用户设定的城市信息。

      1&2)更新Activity界面&更新WidGet:

     public void onReceive(Context context, Intent intent) {
                String state = intent.getStringExtra("state");
                switch (state){
                    case "Loading":
                        dialog2 = ProgressDialog.show(context , "提示", "加载中……");
                        //dialog2.show();
                        break;
                    case "finishLoading":
                        dialog2.cancel();
                        weatherDetails = intent.getStringExtra("weatherDetail");
                        cityWeather.setText(weatherDetails);
                        weatherString=intent.getStringExtra("weatherString");
                        RemoteViews appWidgetView = new RemoteViews(SetWeatherUI.this.getPackageName(),R.layout.main);
                        appWidgetView.setTextViewText(R.id.textview,weatherString);
                        AppWidgetManager.getInstance(SetWeatherUI.this)
                                .updateAppWidget(new ComponentName(SetWeatherUI.this, HelloWidgetProvider.class), appWidgetView);
                        break;
                    default:
                        cityWeather.setText("未响应");
                        break;
                }
            }

      SetWeatherUI根据Service发回来的广播,更改UI,并更改WidGet显示信息。SetWeatherUI显示weatherDetail,WidGet显示weatherString

      3&4)向Service发请求获取天气信息&保存用户设定的城市信息。

            cityButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    stringCityName=cityInput.getText().toString();
                    //向Weather_Service发送广播要求更改城市
                    Intent intent = new Intent(WEATHER_SER);
                    intent.putExtra("command","changeCity");
                    intent.putExtra("cityName",stringCityName);
                    sendBroadcast(intent);
                    editor.putString("cityName",stringCityName);
                    editor.commit();
                }
            });

      当确认键按下后,运用广播向Weather_Service发送更改城市的命令,并将城市名称传入。随后使用SharedPreferences保存城市名称。

      接下来是Weather_Service的设计

    package com.memeda.lsy.widgettest;
    
    import android.app.PendingIntent;
    import android.app.ProgressDialog;
    import android.app.Service;
    import android.app.WallpaperManager;
    import android.appwidget.AppWidgetManager;
    import android.content.BroadcastReceiver;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.SharedPreferences;
    import android.os.AsyncTask;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.util.Log;
    import android.widget.RemoteViews;
    import android.widget.Toast;
    
    import com.memeda.lsy.widgettest.net.UrlGetWeatherUtil;
    
    import java.io.IOException;
    import java.net.URISyntaxException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /**
     * Created by Administrator on 2015/2/10.
     */
    public class Weather_Service extends Service {
        MyReceiver myReceiver;
        SharedPreferences sharedPreferences;
        SharedPreferences.Editor editor;
        Timer timer;
        WallpaperManager wallpaperManager;
        int wallPaperCount=0;
    
        int[] snowWallPaperIds=new int[]{R.drawable.background_snow1,R.drawable.background_snow2};
        int[] sunWallPaperIds=new int[]{R.drawable.background_sunday1,R.drawable.background_sunday2};
        int[] cloudWallPaperIds=new int[]{R.drawable.background_cloud1,R.drawable.background_cloud2};
        int[] rainWallPaperIds=new int[]{R.drawable.background_rain1,R.drawable.background_rain2};
        int[] darkWallPaperIds=new int[]{R.drawable.background_dark1,R.drawable.background_dark2};
    
    
        class ShowWeatherTask extends AsyncTask<String,Integer,Map<String,String>> {
            Context myContext;
            public ShowWeatherTask(Context context){
                myContext=context;
            }
    
            @Override
            protected Map<String,String> doInBackground(String... params) {
                //通过Url的GET请求在百度API上获得天气信息并使用JSON解析后储存
                Map<String,String> map = UrlGetWeatherUtil.getWeather(params[0]);
                editor.putString("weather",map.get("weather"));
                editor.commit();
                getWallPaper(map.get("weather"));
                return map;
            }
    
            @Override
            protected void onPreExecute() {
                Intent intent = new Intent(SetWeatherUI.WEATHER_ACTI);
                intent.putExtra("state","Loading");
                sendBroadcast(intent);
                super.onPreExecute();
            }
    
            @Override
            protected void onPostExecute(Map<String,String> s) {
                super.onPostExecute(s);
                String weatherString="";
                String weatherDetail="";
    
                Intent intent = new Intent(SetWeatherUI.WEATHER_ACTI);
                //更新状态:天气信息获取完成
                intent.putExtra("state","finishLoading");
                if(s!=null){
                    weatherString=showEasyInfo(s);
                    weatherDetail=showDetailInfo(s);
                }
                else {
                    weatherString="未能成功获取天气信息";
                    weatherDetail="未能成功获取天气信息";
                }
                //更新WidGet的界面
                upDataWidget(weatherString);
                //将天气信息发送给UI界面
                intent.putExtra("weatherDetail", weatherDetail);
                intent.putExtra("weatherString",weatherString);
                sendBroadcast(intent);
            }
        }
        public class MyReceiver extends BroadcastReceiver{
    
            @Override
            public void onReceive(Context context, Intent intent) {
                String command = intent.getStringExtra("command");
                switch (command){
                    case "changeCity":{
                        //获得城市名称
                        String cityName = intent.getStringExtra("cityName");
                        //获取天气信息并提交
                        ShowWeatherTask showWeatherTask = new ShowWeatherTask(context);
                        showWeatherTask.execute(cityName);
                        //保存城市信息
                        editor.putString("cityName",cityName);
                        editor.commit();
                        break;
                    }
                    case "updateWeather":{
                        //提取保存的城市信息
                        String cityName=sharedPreferences.getString("cityName","北京");
                        //获取天气信息并提交
                        ShowWeatherTask showWeatherTask = new ShowWeatherTask(context);
                        showWeatherTask.execute(cityName);
                        break;
                    }
                }
            }
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            //注册广播接收器
            myReceiver = new MyReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(SetWeatherUI.WEATHER_SER);
            registerReceiver(myReceiver, intentFilter);
            //获取SharedPreferences
            sharedPreferences = getSharedPreferences("weatherInfo", MODE_WORLD_READABLE);
            editor = sharedPreferences.edit();
            //获取WallpapaerManager以更改墙纸
            wallpaperManager = WallpaperManager.getInstance(this);
            //定时更新天气,更换壁纸
            timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    handler.sendEmptyMessage(0x123);
                }
            },0,30000);
        }
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if (msg.what==0x123){
                    //获取城市信息
                    String cityName=sharedPreferences.getString("cityName","北京");
                    //通过网络获取天气信息
                    ShowWeatherTask showWeatherTask = new ShowWeatherTask(Weather_Service.this);
                    showWeatherTask.execute(cityName);
                }
                super.handleMessage(msg);
            }
        };
        //更换壁纸
        private void changeWallPaper(int[] weatherPicture ){
            wallPaperCount=wallPaperCount%weatherPicture.length;
            try {
                wallpaperManager.setResource(weatherPicture[wallPaperCount]);
                wallPaperCount++;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //更新WidGet的界面
        private void upDataWidget(String detail){
            RemoteViews remoteViews = new RemoteViews(Weather_Service.this.getPackageName(),R.layout.main);
            //设置点击事件,打开Activity
            Intent intent = new Intent(Weather_Service.this,SetWeatherUI.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(Weather_Service.this,0,intent,0);
            remoteViews.setOnClickPendingIntent(R.id.textview,pendingIntent);
            remoteViews.setTextViewText(R.id.textview,detail);
            AppWidgetManager.getInstance(Weather_Service.this)
                    .updateAppWidget(new ComponentName(Weather_Service.this, HelloWidgetProvider.class), remoteViews);
        }
        //根据天气获得相应壁纸
        private void getWallPaper(String tempWeather){
            if(tempWeather.equals("晴")){
                changeWallPaper(sunWallPaperIds);
            }
            else if(tempWeather.contains("雪")){
                changeWallPaper(snowWallPaperIds);
            }
            else if(tempWeather.contains("雨")){
                changeWallPaper(rainWallPaperIds);
            }
            else if(tempWeather.contains("云")){
                changeWallPaper(cloudWallPaperIds);
            }
            else if(tempWeather.equals("阴")){
                changeWallPaper(darkWallPaperIds);
            }
        }
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        //把将要显示在Widget上的信息转化成字符串
        public String showEasyInfo(Map<String,String> weather){
            String weatherString=new String();
            weatherString=""+weather.get("city");
            weatherString+="
    "+weather.get("weather");
            weatherString+="
    "+weather.get("l_tmp")+"~"+weather.get("h_tmp");
            weatherString+="
    "+weather.get("WS");
            return weatherString;
        }
        //把将要显示在Activity上的信息转化成字符串
        public String showDetailInfo(Map<String,String> weather){
            String weatherString=new String();
            weatherString="城市:"+weather.get("city");
            weatherString+="
    天气:"+weather.get("weather");
            weatherString+="
    当前气温:"+weather.get("temp");
            weatherString+="
    今日气温:"+weather.get("l_tmp")+"~"+weather.get("h_tmp");
            weatherString+="
    发布时间:"+weather.get("time");
            weatherString+="
    邮编:"+weather.get("postCode");
            weatherString+="
    经度:"+weather.get("longitude");
            weatherString+="
    纬度:"+weather.get("latitude");
            weatherString+="
    风向:"+weather.get("WD");
            weatherString+="
    风力:"+weather.get("WS");
            weatherString+="
    日出时间:"+weather.get("sunrise");
            weatherString+="
    日落时间:"+weather.get("sunset");
            return weatherString;
        }
    }

      Weather_Service只做两件事:1、接收广播并给出回应;2、定时更新Widget的显示信息并更换墙纸。

      1)接收广播并给出回应

        class ShowWeatherTask extends AsyncTask<String,Integer,Map<String,String>> {
            Context myContext;
            public ShowWeatherTask(Context context){
                myContext=context;
            }
    
            @Override
            protected Map<String,String> doInBackground(String... params) {
                //通过Url的GET请求在百度API上获得天气信息并使用JSON解析后储存
                Map<String,String> map = UrlGetWeatherUtil.getWeather(params[0]);
                editor.putString("weather",map.get("weather"));
                editor.commit();
                getWallPaper(map.get("weather"));
                return map;
            }
    
            @Override
            protected void onPreExecute() {
                Intent intent = new Intent(SetWeatherUI.WEATHER_ACTI);
                intent.putExtra("state","Loading");
                sendBroadcast(intent);
                super.onPreExecute();
            }
    
            @Override
            protected void onPostExecute(Map<String,String> s) {
                super.onPostExecute(s);
                String weatherString="";
                String weatherDetail="";
    
                Intent intent = new Intent(SetWeatherUI.WEATHER_ACTI);
                //更新状态:天气信息获取完成
                intent.putExtra("state","finishLoading");
                if(s!=null){
                    weatherString=showEasyInfo(s);
                    weatherDetail=showDetailInfo(s);
                }
                else {
                    weatherString="未能成功获取天气信息";
                    weatherDetail="未能成功获取天气信息";
                }
                //更新WidGet的界面
                upDataWidget(weatherString);
                //将天气信息发送给UI界面
                intent.putExtra("weatherDetail", weatherDetail);
                intent.putExtra("weatherString",weatherString);
                sendBroadcast(intent);
            }
        }    
      public class MyReceiver extends BroadcastReceiver{
    
            @Override
            public void onReceive(Context context, Intent intent) {
                String command = intent.getStringExtra("command");
                switch (command){
                    case "changeCity":{
                        //获得城市名称
                        String cityName = intent.getStringExtra("cityName");
                        //获取天气信息并提交
                        ShowWeatherTask showWeatherTask = new ShowWeatherTask(context);
                        showWeatherTask.execute(cityName);
                        //保存城市信息
                        editor.putString("cityName",cityName);
                        editor.commit();
                        break;
                    }
                    case "updateWeather":{
                        //提取保存的城市信息
                        String cityName=sharedPreferences.getString("cityName","北京");
                        //获取天气信息并提交
                        ShowWeatherTask showWeatherTask = new ShowWeatherTask(context);
                        showWeatherTask.execute(cityName);
                        break;
                    }
                }
            }
        }

      获取天气信息的过程通过AsyncTask异步任务类进行管理,使用Url的Get请求方法,百度API的数据,通过JSON解析,获得天气信息。

      

      2)定时更新Widget显示信息

        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if (msg.what==0x123){
                    //获取城市信息
                    String cityName=sharedPreferences.getString("cityName","北京");
                    //通过网络获取天气信息
                    ShowWeatherTask showWeatherTask = new ShowWeatherTask(Weather_Service.this);
                    showWeatherTask.execute(cityName);
                }
                super.handleMessage(msg);
            }
        };

    以上

  • 相关阅读:
    WiFi流量劫持—— 浏览任意页面即可中毒!
    POJ3614防晒霜 这个贪心有点东西(贪心+优先队列)
    7月24日训练记录
    环形均分纸牌问题(中位数)
    7月23日训练总结
    7.22学习总结
    POJ 1176 Party Lamps&& USACO 2.2 派对灯(搜索)
    尘埃落定,以梦为马,不负韶华
    P1522 牛的旅行 Cow Tours(floyd)
    分享一种解题的思想,有关时间复杂度探讨
  • 原文地址:https://www.cnblogs.com/fishbone-lsy/p/4295602.html
Copyright © 2020-2023  润新知