I have a Room database which stores vocabulary data. Also I am trying to make a widget which shows one in the vocabulary database.
When I start my app and add a widget to home screen, no problem with starting the app. But whenever I start my app after adding the widget, I get an error that says my loaded data is null.
Here is my Widget code:
public class VocaWidget extends AppWidgetProvider {
    private AppWidgetManager manager;
    private RemoteViews remoteView;
    private AsyncTask<Void, Void, LiveData<Vocabulary>> showVocaTask;
    private Callable myTask;
    private UpdateWidgetReceiver receiver;
    private final int UPDATE_WIDGET_ID = 17;
    public final String UPDATE_WIDGET = "action.updatewidget.update";
    @Override
    public void onReceive(Context context, Intent intent) {
        super.onReceive(context, intent);
        Log.d("HSK APP", "VocaWidget onReceive()");
        if (remoteView == null) {
            remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        }
        manager = AppWidgetManager.getInstance(context);
        ComponentName widgetName = new ComponentName(context.getPackageName(), VocaWidget.class.getName());
        int[] widgetIds = manager.getAppWidgetIds(widgetName);
        setPendingIntent(context, widgetIds);
    }
    @Override
    public void onEnabled(final Context context) {
        Log.d("HSK APP", "VocaWidget onEnabled()");
        if (remoteView == null) {
            remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        }
        if (receiver == null) {
            receiver = new UpdateWidgetReceiver();
        }
        IntentFilter filter = new IntentFilter(UPDATE_WIDGET);
        context.getApplicationContext().registerReceiver(receiver, filter);
        super.onEnabled(context);
        AppHelper.loadInstance(context);
    }
    private void setPendingIntent(Context context, int[] appWidgetIds) {
        Intent intent = new Intent(UPDATE_WIDGET);
        PendingIntent updateWidgetPI = PendingIntent.getBroadcast(context, UPDATE_WIDGET_ID, intent, 0);
        remoteView.setOnClickPendingIntent(R.id.widget_voca_button, updateWidgetPI);
        manager.updateAppWidget(appWidgetIds, remoteView);
    }
    @Override
    public void onUpdate(final Context context, AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
        Log.d("HSK APP", "VocaWidget onUpdate()");
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        if (showVocaTask == null) {
            showVocaTask = new AsyncTask<Void, Void, LiveData<Vocabulary>>() {
                @Override
                protected LiveData<Vocabulary> doInBackground(Void... voids) {
                    LiveData<Vocabulary> vocabulary = null;
                    VocaRepository repository = VocaRepository.getInstance();
                    vocabulary = repository.getRandomVocabulary();
                    return vocabulary;
                }
                @Override
                protected void onPostExecute(LiveData<Vocabulary> vocabularyLiveData) {
                    super.onPostExecute(vocabularyLiveData);
                    if (vocabularyLiveData == null || vocabularyLiveData.getValue() == null) {
                        Log.d("HSK APP", "getRamdonVocabulary task null");
                        return;
                    }
                    Vocabulary vocabulary = vocabularyLiveData.getValue();
                    Log.d("HSK APP", "onwidget vocabulary: " + vocabulary.eng);
                    remoteView.setTextViewText(R.id.widget_eng, vocabulary.eng);
                    remoteView.setTextViewText(R.id.widget_kor, vocabulary.kor);
                    manager.updateAppWidget(appWidgetIds, remoteView);
                }
            };
        }
        showVocaTask.execute();
    }
    @Override
    public void onDisabled(Context context) {
        Log.d("HSK APP", "VocaWidget onDisabled()");
        super.onDisabled(context);
        context.getApplicationContext().unregisterReceiver(receiver);
    }
    public static class UpdateWidgetReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("HSK APP", "WidgetReceiver onReceive()");/*
            if (intent.getAction().equalsIgnoreCase(UPDATE_WIDGET)) {
                showVocaTask.execute();
            }*/
        }
    }
}
And here is my Database Repository code:
// Singleton
public class VocaRepository {
    private VocaDao vocaDao;
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private static VocaRepository instance;
    private VocaDatabase database;
    private LiveData<List<Vocabulary>> allVocabulary;
    public static VocaRepository getInstance() {
        if (instance == null) {
            loadInstance();
        }
        return instance;
    }
    public static void loadInstance() {
        synchronized (VocaRepository.class) {
            if (instance == null) {
                instance = new VocaRepository();
                instance.database = VocaDatabase.getInstance();
                instance.vocaDao = VocaDatabase.getInstance().vocaDao();
            }
        }
    }
    private LiveData<List<Vocabulary>> loadVocabulary() {
        if (allVocabulary == null || allVocabulary.getValue() == null) {
            try {
                Future future = executor.submit(new LoadTask());
                allVocabulary = (LiveData<List<Vocabulary>>) future.get(1, TimeUnit.SECONDS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Log.d("HSK APP", "Load Vocabulary result: " + (allVocabulary != null));
        return allVocabulary;
    }
    public LiveData<List<Vocabulary>> getVocabulary(final String eng) {
        return vocaDao.loadVocabulary(eng);
    }
    public LiveData<List<Vocabulary>> getAllVocabulary() {
        loadVocabulary();
        return allVocabulary;
    }
    public LiveData<Vocabulary> getRandomVocabulary() {
        loadVocabulary();
        Random random = new Random();
        int index = random.nextInt(allVocabulary.getValue().size()); // Error!
        return new MutableLiveData<>(allVocabulary.getValue().get(index));
    }
    private class LoadTask implements Callable {
        @Override
        public Object call() throws Exception {
            return vocaDao.loadAllVocabulary();
        }
    }
}
As you can see, whenever I try to get any data, I check whether the loaded data(allVocabulary in VocaRepository) is null and load it if it is so. But it always give me a NullPointerException:
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:354)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
        at Database.source.VocaRepository.getRandomVocabulary(VocaRepository.java:74)
        at hsk.practice.myvoca.widget.VocaWidget$1.doInBackground(VocaWidget.java:97)
        at hsk.practice.myvoca.widget.VocaWidget$1.doInBackground(VocaWidget.java:91)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:764) 
I struggled with this problem for several weeks but I have no idea. Any suggestions will be appreciated.
 
    
>) future.get(1, TimeUnit.SECONDS);`
– Waqar UlHaq Mar 03 '20 at 10:39