壁纸风波

许多有内涵的朋友都喜欢将自己的电脑桌面壁纸设置为美女图片,并且隔一段时间,自动更换,看起来十分炫酷。的确,用过windows的朋友们都知道,windows的个性化设置里面,可以将壁纸设置幻灯片放映,这就解决了壁纸常年不变的尴尬局面,原因在于很多懒猪们拿到自己的电脑以后,往往自己在网上找一张自己觉得好看的壁纸,设置为桌面壁纸以后,就懒得再去管它,这一用就是几个月,乃至上年。

很多稍微有点内涵的朋友们,喜欢经常换换壁纸,换换心情,他们自己去网上下载一些风景画,或是美女图片,然后自己建一个文件夹专门将其存放,于是电脑壁纸也经常自动换过来,换过去,看起来十分高大上。

Java制作壁纸软件 java主题壁纸_java

但是往往上面的这些操作都十分的麻烦,那么有没有一种很便捷的方式,让壁纸自动下载与更换呢?

有的,下载一个壁纸软件就搞定了,但是又有许多朋友,不想让自己电脑安装太多的软件,本来安几个IDE,安个LOL,安个绝地求生等,还有很多开机启动的软件,这就已经很卡了,笔者16G运存,感觉都不舒服!

既然这样,那干脆自己写一个程序算了,占用内存小,没有垃圾文件,何乐而不为?

java实现壁纸自动下载并且自动切换

原理说明:
请求图片接口,下载图片并保存至一个电脑上的一个文件夹,这里我保存的是D盘下面的wallpapers文件夹,另外使用程序控制定时任务,每天早上9:00准时下载图片,且如果9:00电脑处于关机状态,当天开启电脑后,程序自动为我们补上,由于必应的图片接口是每天更换一张的,故我们每天都换下载到不同的图片,然后将其设置为windows幻灯片放映的文件夹,这样每天都会下载一张新的图片,并且由windows自动为我们切换了。最后,我们将程序打包为jar文件,并且设置为开机启动,这样我们就再也不用去管它了,就可以享受每天自动下载的必应图片并交由windows自动作为壁纸切换了(说实话,必应的图片都还是比较经典的,他们往往都出自非一般摄影师之手,经典不在于它们的景深、虚化之类的,在于它们所描绘的往往是常人很难捕捉到的自然奇观,或人性温暖的瞬间,天时地利人和才能拍摄出的照片,会让我们感受到未曾感知过的世界)

首先要下载壁纸,就必须得有提供壁纸的接口,API网站上面有许多图片的接口,这里笔者为了做测试,采用了郭霖先生提供的:必应每日一图(谨慎使用,感谢郭神)

图片链接接口:http://guolin.tech/api/bing_pic,这里接会返回必应图片的真实地址。

Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_02

下面开始利用这个接口进行操作:

一、图片下载
使用HttpURLConnection进行网络请求,首先请求http://guolin.tech/api/bing_pic获得图片的真实地址,再请求真实地址下载图片,由于请求网络是耗时操作,我们将其在子线程中进行,使用接口回调监听下载是否完成。

监听请求完成的接口

public interface RequestFinishListener {
    void finish(String response);
    void error(Exception ex);
}

监听下载完成的接口

public interface DownloadFinishListener {
    void finish();
    void error(Exception ex);
}

网络请求工具

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpUtil {

    /**
     * 获取图片地址
     * 
     * @param address
     * @param listener
     */
    public static void doGet(String address, RequestFinishListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection conn = null;
                InputStream in = null;
                BufferedReader reader = null;
                StringBuffer result = new StringBuffer();
                try {
                    URL url = new URL(address);
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setReadTimeout(5000);
                    conn.setConnectTimeout(3000);
                    conn.connect();
                    in = conn.getInputStream();
                    reader = new BufferedReader(new InputStreamReader(in));
                    String line = "";
                    while ((line = reader.readLine()) != null) {
                        result.append(line);
                    }
                    if (listener != null) {
                        listener.finish(result.toString());
                    }
                    reader.close();
                    in.close();
                } catch (Exception e) {
                    listener.error(e);
                } finally {
                    if (conn != null) {
                        conn.disconnect();
                    }
                }

            }
        }).start();
    }

    /**
     * 下载图片
     * 
     * @param address图片网址
     * @param path保存路径
     * @param name文件名
     * @throws IOException
     */
    public static void download(String address, String dir, String name, DownloadFinishListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection conn = null;
                FileOutputStream out = null;
                InputStream in = null;
                File saveFile = null;
                try {
                    saveFile = new File(dir + "\\" + name);
                    if (saveFile.exists()) {
                        saveFile.delete();
                    }
                    out = new FileOutputStream(saveFile);
                    URL url = new URL(address);
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setReadTimeout(5000);
                    conn.setConnectTimeout(3000);
                    conn.connect();
                    in = conn.getInputStream();
                    int len = -1;
                    byte[] buffer = new byte[1024];
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                    listener.finish();
                    out.close();
                    in.close();
                } catch (Exception ex) {
                    // 删除未正确下载的图片
                    if (saveFile != null) {
                        saveFile.delete();
                    }
                    listener.error(ex);
                } finally {
                    if (conn != null) {
                        conn.disconnect();
                    }
                }
            }
        }).start();
    }
}
二、文件保存的说明
将其保存在D盘下的wallpapers文件下,命名从为数字,一次递增,1.JPG、2.jpg、3.jpg …

下载工具

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class DownUtil {
    private final static int FAILED = 0;
    private final static int SUCCEED = 1;

    /**
     * 检查当天的下载是否已经执行,防止重复下载
     * 
     * @return
     */
    private static boolean check() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String name = sdf.format(date);
        File file1 = new File("D:\\wallpapers\\logs\\" + name + ".txt");
        File file2 = new File("D:\\wallpapers\\errors\\" + name + ".txt");
        if (file1.exists() || file2.exists()) {
            return true;
        }
        return false;
    }

    public static void downWallPaper() {
        if (!check()) {
            String requestAddress = "http://guolin.tech/api/bing_pic";
            HttpUtil.doGet(requestAddress, new RequestFinishListener() {

                @Override
                public void finish(String response) {
                    downPhoto(response);
                }

                @Override
                public void error(Exception ex) {
                    CommUtil.saveLog(FAILED, "请求图片网址时异常: " + ex.toString());
                }
            });
        }
    }

    // 下载图片
    public static void downPhoto(String picAddress) {
        String dir = "D:\\wallpapers";
        File saveDir = new File(dir);
        if (!saveDir.exists()) {
            saveDir.mkdir();
        }
        File[] allFiles = saveDir.listFiles();
        List<File> files = new ArrayList<File>();
        for (File file : allFiles) {
            if (file.isFile()) {
                files.add(file);
            }
        }
        if (files.size() == 0) {
            // 文件夹不存在图片,从1开始命名
            String name = "1.jpg";
            HttpUtil.download(picAddress, dir, name, new DownloadFinishListener() {

                @Override
                public void finish() {
                    CommUtil.saveLog(SUCCEED, "下载成功");
                }

                @Override
                public void error(Exception ex) {
                    CommUtil.saveLog(FAILED, "下载图片时异常: " + ex.toString());
                }
            });
        } else {
            // 文件夹存在图片,获取最大名称,将其加1作为新图片的名称
            int names[] = new int[files.size()];
            for (int i = 0; i < files.size(); i++) {
                String fileName = files.get(i).getName();
                names[i] = Integer.parseInt(fileName.substring(0, fileName.lastIndexOf(".")));
            }
            String name = CommUtil.getMax(names) + 1 + ".jpg";
            HttpUtil.download(picAddress, dir, name, new DownloadFinishListener() {

                @Override
                public void finish() {
                    CommUtil.saveLog(SUCCEED, "下载成功");
                }

                @Override
                public void error(Exception ex) {
                    CommUtil.saveLog(FAILED, "下载图片时异常: " + ex.toString());
                }
            });
        }
    }

}
三、日志记录
不论下载成功或失败,我们都将其使用时间作为命名记录下日志,保存在D盘下,用 txt 文件记录下载成功的日志保存到wallpapers文件夹下的子文件logs中,下载时发生的异常的日志保存到wallpapers文件夹下的子文件errors中
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class CommUtil {
    public static int getMax(int[] array) {
        Arrays.sort(array);
        return array[array.length - 1];
    }

    /**
     * 日志记录
     * 
     * @param state日志状态分类
     * @param message日志详情
     */
    public static void saveLog(int state, String message) {
        FileOutputStream out = null;
        try {
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String name = sdf.format(date);
            File saveDir = null;
            if (state == 1) {
                saveDir = new File("D:\\wallpapers\\logs");
            } else if (state == 0) {
                saveDir = new File("D:\\wallpapers\\errors");
            }
            if (!saveDir.exists()) {
                saveDir.mkdir();
            }
            File file = new File(saveDir + "\\" + name + ".txt");
            out = new FileOutputStream(file);
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = sdf.format(date);
            String log = "时间:" + time + ",  " + message;
            out.write(log.getBytes());
        } catch (Exception e) {
        }
    }
}
四、第一次测试
到这里,我们先测试一下程序,待成功测试后,又设置定时任务,这里不建议大家使用Junit等测试工具,而是直接写Main函数进行测试。
public class Main {
    public static void main(String[] args) {
        //下载图片保存到D:\wallpapaers,生成日志保存到D:\wallpapers\logs(errors)
        DownUtil.downWallPaper();
    }

执行结果:

可以看到,程序自动为我们创建了wallpapers文件夹

Java制作壁纸软件 java主题壁纸_java_03

打开该文件夹,可以看到程序为我们下载了一张图片,并产生了下载成功的日志

Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_04

Java制作壁纸软件 java主题壁纸_windows壁纸_05

Java制作壁纸软件 java主题壁纸_java_06

此时我们使用windows的个性化—壁纸—幻灯片放映—设置文件夹,选择wallpapers这个文件就可以了,过一会儿,会看到windows自动将我们壁纸切换了。

Java制作壁纸软件 java主题壁纸_自动切换_07

五、定时任务
由于必应每天更换一张图片,我们将其设置为每天早上9:00时执行该程序,借助TimerTask与线程计时Timer轻松实现,每天自动下载图片了。修改Main函数。
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Main {
    public static void main(String[] args) {
        downloadTimer();
    }

    public static void downloadTimer() {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                DownUtil.downWallPaper();
            }
        };
        // 设置执行时间
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);// 每天
        calendar.set(year, month, day, 9, 00, 00);
        // 定制每天的09:10:00执行,不重复执行
        Date date = calendar.getTime();
        Timer timer = new Timer();
        timer.schedule(task, date);
    }
}

注意:上面程序实现定时执行,我们使用Timer每天9:10执行TimerTask中的任务,如果现在时间是8:10,则会等待一个小时,等到9:00执行。但是如果已经超过了9:00,假如现在是10:00,我们才执行这个程序,并不会因为超过了9:00就不执行,同样会执行该任务,所以这样可以保证每天9:10如果没有开机,10:00才开机,同样会执行。这顺便也解决了超市补上下载的问题。

六、打包成Jar—脱离eclipse运行
到这里我们如果运行程序,只要不关闭eclipse(我是用eclipse写的),便可以每天09:00自动下载一张图片了,但是仔细想想,这是不可以能的,因为我们不可能让eclipse一直开着,所以我们将程序打包为一个jar包。

包名右键—Export—Jar file—设置Main函数—Finish

Java制作壁纸软件 java主题壁纸_自动切换_08


Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_09

这里一定不能忘记设置Main函数,不然我打包的jar文件是不能运行的哦!

我是将其打包后,放在D盘的 jars 文件夹里面

Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_10

Java制作壁纸软件 java主题壁纸_java_11

此时我们双击该jar文件夹编可以运行了,每天9:00为我们下载一张图片到D:\wallpapers文件里下面,但是问题又来了,我们电脑总得关机吧,关机了程序便停止运行了,这下怎么办呢?

七、开机自启动Jar文件
我们只需编写一个windows的bat脚本就可以实现开机自动运行了

①编写javaProgramsStart.bat,其内容为:start java -jar wallpapers.jar
②创建该bat的快捷方式
③将该快捷方式放在windows的开机自启动文件夹内
其位置为:C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp

Java制作壁纸软件 java主题壁纸_自动下载_12

Java制作壁纸软件 java主题壁纸_自动下载_13

很多朋友在C盘中可能找不到这个文件夹,可以直接搜索就可以了

Java制作壁纸软件 java主题壁纸_windows壁纸_14

Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_15

到此便可以开机自启动了,每天9:00准时为我们下载一张必应的图片,如果那时没有网,便会记录错误的日志,如果网络正常,便会记录下载成功的日志。

八、解决最后一个问题—启动黑框
当我们重启电脑时,会发现我们实际上还存在一个很严重的问题,这会很严重的影响我们的体验,那就是我么在启动电脑后,会发现jar的自动程序,由于涉及到定时任务,使用了TimerTask与Timer,那么程序会一直运行,自启动后,会出现java程序运行时的黑框。

Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_16

这会严重的影响用户体验,每次开机一个黑框什么鬼,就算用户点击了最小化,底部的状态栏也会有一杯咖啡的图标,这样会让用户觉得不舒服。
一种解决办法是使用Jframe图形界面,将宽度和高度设置为接近0 ,这样产生了图形界面之后,黑框便会消失,使用GUI线程来执行任务,就解决了黑框问题。但是这种解决方式不太优雅。

优雅且简单的解决办法:
修改javaProgramsStart.bat,将 java -jar 改成 javaw -jar 就可以了,此时黑框问题也得到了解决。
更改前:

Java制作壁纸软件 java主题壁纸_java_17

更改后:

Java制作壁纸软件 java主题壁纸_自动切换_18

至此开机不会再有黑框的困扰了。

到此,我们便可以实现自动下载壁纸,并且下载有日志进行记录,另外也会开机自启动,我们部署好了以后,就不用再去管它,而每天9:00会自动下载必应的精美图片,如果9:00电脑处于关机状态,那么当天我们开机后,系统会自动为我们补上下载,并且不会重复下载,保证每天一张,这真是十分美妙的一件事情。我们做的只需要将windows的个性化中的幻灯片放映设置文件夹为我们程序生产的wallpapers就ok了!

笔者等到了第二天,发现桌面壁纸有的新了,再次查看:

Java制作壁纸软件 java主题壁纸_自动切换_19

Java制作壁纸软件 java主题壁纸_Java制作壁纸软件_20

Java制作壁纸软件 java主题壁纸_自动下载_21

Java制作壁纸软件 java主题壁纸_java_22

可见第二天又成功的下载了一张。

九、还能继续完善

到这里了,我们就已经可以直接使用这个程序了。但是运气不好,问题又来了。我们每次开机就会自动运行程序,当时间走到了程序该执行下载的时候,从程序的设定来看,如果我们那时电脑没网的话,便会产生一个error日志记录下来,里面则是装的错误日志。是的,仅仅就只有一个错误日志,里面记录的是一个找不到网络的异常。很遗憾,我们由于没网,就一个异常就算了,可是我们还是想要得到图片啊,那我们就继续完善。

解决办法:新增多个时刻,9:00、9:30、10:00…都来监听是否下载。我们每隔半小时,重复执行一次,直到产生下载成功的日志。这样来尽量保证我们每天都下载成功,而不会因为某一段时间刚好没网而错过了。这样只有检测到到下载成功的日志才会进行停止下载,而且由于通过命名检测的原因,error中的日志也会被覆盖,下载失败的日志始终每天最多只会有一条存在。下面给出修改方法:

在DownUtil中,我们上面通过检测error日志与成功日志来判断是否下载:

/**
     * 检查当天的下载是否已经执行,防止重复下载
     * 
     * @return
     */
    private static boolean check() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String name = sdf.format(date);
        File file1 = new File("D:\\wallpapers\\logs\\" + name + ".txt");
        File file2 = new File("D:\\wallpapers\\errors\\" + name + ".txt");
        if (file1.exists() || file2.exists()) {
            return true;
        }
        return false;
    }

那么这里我们就需要改一下,只检测下载成功的日志来判断:

/**
     * 检查当天的下载是否已经执行,防止重复下载
     * 
     * @return
     */
    private static boolean check() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String name = sdf.format(date);
        File file1 = new File("D:\\wallpapers\\logs\\" + name + ".txt");
        if (file1.exists()) {
            return true;
        }
        return false;
    }

再次修改Main方法:

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Main {
    public static void main(String[] args) {
        downloadTimer();
    }

    public static void downloadTimer() {
        // 设置执行时间
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);// 每天
        Date date = calendar.getTime();
        calendar.set(year, month, day, 9, 00, 00);
        Timer timer = new Timer();
        // 第一次执行
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                DownUtil.downWallPaper();
            }
        };
        // 每天9:00时刻执行,每隔30分钟重复执行一次
        int peroid = 30 * 60 * 1000;
        timer.schedule(task, date, peroid);
    }
}

这样每隔半小时,检测一次,尽量保证每天都能够下载成功。

GitHub 地址:https://github.com/zhoupengwa/WallPapers

感谢大家的观看!