Иконка Java в трее NPE
Я создал экземпляр Java trayIcon и хочу показать на нем displayMessage со следующим кодом:
trayIcon.displayMessage(_titel, _msg, TrayIcon.MessageType.INFO);
Но вместо сообщения я получаю исключение NullpointerException и не знаю почему?
Этот NPE:
Exception in thread "main" java.lang.NullPointerException
at myPckg.Tray.showMsg(Tray.java:165)
at myPckg.Main.main(Main.java:65)
В строке 65 я создаю экземпляр класса через конструктор, а в 155 я вызываю этот объект.
Спасибо за помощь!
Редактировать код:
import java.awt.AWTException;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
public class Tray {
//http://www.oracle.com/technetwork/articles/javase/index-136970.html
public static MenuItem itmSpeicher = new MenuItem("0% von 0MB belegt");
public static MenuItem itmSyncStatus = new MenuItem("Synchronisation starten");
public static PopupMenu popup = new PopupMenu();
public static TrayIcon trayIcon = null;
public Tray(){
final TrayIcon trayIcon;
if (SystemTray.isSupported()) {
SystemTray tray = SystemTray.getSystemTray();
Image image = null;
try {
image = ImageIO.read(getClass().getResource("sync.gif"));
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
new Thread(){ public void run(){ Main.syncProzess.reset();}}.start();
}
MouseListener mouseListener = new MouseListener() {
public void mouseClicked(MouseEvent e) {
Main.MainWindow.setVisible(true);
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
};
ActionListener exitListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
int x = JOptionPane.showConfirmDialog(null, "Synchronisation wirklich beenden?");
if(x==0){
System.out.println("Beende... "+x);
System.exit(0);
}
}
};
ActionListener itmSyncStatusListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Main.syncProzess.starte();
}
};
ActionListener itmFolderListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Runtime.getRuntime().exec("explorer.exe "+ Main.syncDir );
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
new Thread(){ public void run(){ Main.syncProzess.reset();}}.start();
}
}
};
ActionListener itmSettingListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Main.MainWindow.setVisible(true);
}
};
MenuItem defaultItem = new MenuItem("Programm beenden");
defaultItem.addActionListener(exitListener);
itmSyncStatus.addActionListener(itmSyncStatusListener);
MenuItem itmFolder = new MenuItem(Main.programmName + " Ordner öffnen");
itmFolder.addActionListener(itmFolderListener);
MenuItem itmSettings = new MenuItem("Einstellungen");
itmFolder.addActionListener(itmSettingListener);
popup.add(itmFolder);
popup.add(itmSpeicher);
popup.add(itmSettings);
popup.add(itmSyncStatus);
popup.add(defaultItem);
trayIcon = new TrayIcon(image, Main.programmName, popup);
ActionListener doubleClick = new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Runtime.getRuntime().exec("explorer.exe "+ Main.syncDir );
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
new Thread(){ public void run(){ Main.syncProzess.reset();}}.start();
}
}
};
trayIcon.setImageAutoSize(true);
trayIcon.addActionListener(doubleClick);
trayIcon.addMouseListener(mouseListener);
try {
tray.add(trayIcon);
} catch (AWTException e) {
System.err.println("TrayIcon konnte nicht erstellt werden!");
new Thread(){ public void run(){ Main.syncProzess.reset();}}.start();
}
showMsg("Hello", "It's working");
} else {
//Not supportet
}
}
public void showMsg(String _titel, String _msg){
trayIcon.displayMessage(_titel, _msg, TrayIcon.MessageType.INFO);
}
}
3 ответа
Ваша статика trayIcon
является null
, Вы создаете в конструкторе Tray
новый, второй trayIcon
, но твой showMsg
-Метод использует статический trayIcon
не конструктор местный.
Удалить в вашем Tray
-строитель первой строки:
final TrayIcon trayIcon;
и теперь вы инициализируете статическую ссылку.
Проблема в том, что вы переопределяете ту же переменную trayIcon в конструкторе.
final TrayIcon trayIcon;
Поэтому, когда вы инициируете переменную, вызывая trayIcon = new TrayIcon(image, Main.programmName, popup);
локальная переменная метода инициализируется, а не глобальная. Поэтому, когда вы вызываете displayMessage для глобальной переменной, вы получаете NPE.
Решением было бы просто удалить строку из конструктора. OTOH, вы должны поставить нулевую проверку в методе showMessage, так как ваша переменная trayIcon все еще может быть нулевой, если ваше условие (SystemTray.isSupported())
стоит ложь Лучше всегда ставить нулевую проверку.
Еще одна хорошая вещь, сказанная MadProgrammer в комментарии:
Использование статических переменных в этом случае, вероятно, не очень хорошая идея. Потому что разработчик может создать более одного экземпляра, и в этом случае вы получите ошибочные ссылки повсюду. Вместо этого попробуйте сделать класс Tray одиночным или удалить статическое ключевое слово из объявления переменной.
TrayIcon.displayMessage
бросает NullPointerException
если оба caption
а также text
являются null
,
caption
а также text
первые два параметра метода, в этом порядке.
Итак, вот что вы должны проверять в своем коде:
trayIcon
должен быть создан перед вызовом метода_titel
а также_msg
не должно бытьnull
в то же время