androidandroid-studioalarmmanagergoogle-calendar-apiandroid-googleapiclient

Google Calendar API & Alarm Manager Error


I get the free 1 hour time slots from the Google calendar API using this code.

MainActivity.java:

 private List<String> getDataFromApi() throws IOException {
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonthOfYear();
        int day = now.getDayOfMonth();

        org.joda.time.DateTime startDateJoda= new org.joda.time.DateTime(year,month,day,7,00);
        org.joda.time.DateTime endDateJoda= new org.joda.time.DateTime(year,month,day,22,00);

        // Convert from Joda-Time to old bundled j.u.Date
        java.util.Date juDateStart = startDateJoda.toDate();
        java.util.Date juDateEnd = endDateJoda.toDate();
        Log.v(TAG,"Start Date joda value: "+juDateStart.toString());
        Log.v(TAG,"End Date joda value: "+juDateEnd.toString());

        // Convert from j.u.Date to Google Date.
        com.google.api.client.util.DateTime googleDateTimeStart = new com.google.api.client.util.DateTime( juDateStart );
        com.google.api.client.util.DateTime googleDateTimeEnd = new com.google.api.client.util.DateTime( juDateEnd );
        Log.v(TAG,"Start Date Google value: "+googleDateTimeStart.toString());
        Log.v(TAG,"End Date Google value: "+googleDateTimeEnd.toString());

        List<String> eventStrings = new ArrayList<String>();

        org.joda.time.DateTime rootStart = startDateJoda;
        org.joda.time.DateTime rootEnd = endDateJoda;

        Events events = mService.events().list("primary")
                .setMaxResults(10)
                .setTimeMin(googleDateTimeStart)
                .setTimeMax(googleDateTimeEnd)
                .setOrderBy("startTime")
                .setSingleEvents(true)
                .execute();


        List<Event> items = events.getItems();
        Log.v(TAG,"Items : "+items.toString()+"\n");
        Log.v(TAG,"Items size : "+items.size());
        int interval = 1 ; // how big single slot should be (in this case 1 hrs)

        ArrayList<MyEvent> freeSlots = new ArrayList<MyEvent>();
        for (int index =0;index<items.size();index++) {
            Event event = items.get(index);
            Log.v(TAG,"Items Index: "+event.toString()+"\n");

            DateTime teststart=event.getStart().getDateTime();
            DateTime testend=event.getEnd().getDateTime();
            Log.v(TAG,"Test Start Date value: "+teststart.toString());
            Log.v(TAG,"Test End Date value: "+testend.toString());

            long milliseconds1 = teststart.getValue();
            long milliseconds2 = testend.getValue();

            org.joda.time.DateTime eventStartJoda= new org.joda.time.DateTime(milliseconds1);
            org.joda.time.DateTime eventEndJoda= new org.joda.time.DateTime(milliseconds2);

            Log.v(TAG,"Event Start Date joda value: "+eventStartJoda.toString());
            Log.v(TAG,"Event Date joda value: "+eventEndJoda.toString());

            Log.v(TAG,"Before if index == 0 && start<end");
            if ((index == 0) && (startDateJoda.isBefore(eventStartJoda)) ) {
                Log.v(TAG,"Before Inside if index == 0 && start<end");
                freeSlots.add( new MyEvent(startDateJoda,eventEndJoda) );
                Log.v(TAG,"After Inside if index == 0 && start<end");
            }

            if (index == 0) {
                Log.v(TAG,"Before else if index == 0");
                DateTime teststart2=event.getEnd().getDateTime();
                long milliseconds3 = teststart2.getValue();
                startDateJoda=new org.joda.time.DateTime(milliseconds3);
                Log.v(TAG,"startDateJoda value: "+startDateJoda.toString());
            }

            long milliseconds5=0;
            Log.v(TAG,"Before teststart4");
            if(index!=0) {
                DateTime teststart4 = items.get(index - 1).getEnd().getDateTime();
                Log.v(TAG, "After teststart4");
                milliseconds5 = teststart4.getValue();
                Log.v(TAG, "Before if milliseconds5");
            }
            if (new org.joda.time.DateTime(milliseconds5).isBefore(eventStartJoda)) {
                if(index!=0) {
                    freeSlots.add(new MyEvent
                            (new org.joda.time.DateTime(milliseconds5), eventStartJoda));
                Log.v(TAG,"xxxxxxx1 value: "+ new org.joda.time.DateTime(milliseconds5).toString());
                }
            }

            DateTime teststart3=event.getEnd().getDateTime();
            long milliseconds4 = teststart3.getValue();

            if ((items.size() == (index + 1)) && new org.joda.time.DateTime(milliseconds4).isBefore(endDateJoda)) {
                freeSlots.add(new MyEvent(eventEndJoda, endDateJoda));
                Log.v(TAG,"xxxxxxx2 value: "+ new org.joda.time.DateTime(milliseconds4).toString());
            }
        }
        Log.v(TAG,"Before outside items size == 0 ");
        if (items.size() == 0) {
            Log.v(TAG,"Before Inside items size == 0 ");
            freeSlots.add(new MyEvent(startDateJoda,endDateJoda));
            Log.v(TAG,"After Inside items size == 0 ");
        }
        Log.v(TAG,"After outside items size == 0 ");

        ArrayList<MyEvent> hourSlots = new ArrayList<MyEvent>();
        org.joda.time.DateTime tempstart= null;
        org.joda.time.DateTime tempend= null;
        MyEvent temp = new MyEvent();
        int val=0;
        for(int index =0;index<freeSlots.size();index++){
            MyEvent free = (MyEvent) freeSlots.get(index);
            Log.v(TAG,"Free slot size : "+freeSlots.size());
            int freeHours = free.endDate.getHourOfDay()- free.startDate.getHourOfDay();
            Log.v(TAG,"FreeHours: "+freeHours);
            org.joda.time.DateTime freeStart = free.startDate, freeEnd = free.endDate;
            Log.v(TAG,"Free Start Date: "+free.startDate.toString()+"Free End Date: "+free.endDate.toString());
            Log.v(TAG,"Before eventStrings: "+free.startDate.toString()+" : "+free.endDate.toString());

                while(freeStart.getHourOfDay() + freeHours + interval>=0) {                         if(freeHours>=interval) {
                        Log.v(TAG,"free startDate : "+free.startDate);
                        tempend=free.startDate;
                        Log.v(TAG,"Temp startDate : "+tempend);
                        tempend= tempend.hourOfDay().setCopy(tempend.getHourOfDay()+freeHours);
                        Log.v(TAG,"Tmp Start Date1: "+String.valueOf(tempstart)+"Tmp End Date1: "+String.valueOf(tempend));
                        tempstart=free.startDate;
                        Log.v(TAG,"Temp endDate : "+tempstart);
                    tempstart = tempstart.hourOfDay().setCopy(tempstart.getHourOfDay()+freeHours-interval);
                    Log.v(TAG,"Tmp Start Date2: "+tempstart+"Tmp End Date2: "+tempend);
                    if(tempstart.getHourOfDay() >= freeStart.getHourOfDay() && tempend.getHourOfDay() <= freeEnd.getHourOfDay()) {
                        Log.v(TAG,"While loop inside if condition inside if condition inside");
                        if(val!=0) {
                            hourSlots.add(new MyEvent(tempstart, tempend));
                            Log.v(TAG, "Tmp hour slot: " + tempstart + " : " + tempend);
                            eventStrings.add(
                                    String.format(" " + tempstart.toString("dd/MM/yy HH:mm:ss") + " - " + tempend.toString("dd/MM/yy HH:mm:ss")));
                            Log.v(TAG, "After eventStrings: " + tempstart.toString("dd/MM/yy HH:mm:ss") + " : " + tempend.toString("dd/MM/yy HH:mm:ss"));
                            int hour=Integer.valueOf(tempstart.toString("HH"));
                            int mminute=Integer.valueOf(tempstart.toString("mm"));
                            Log.v(TAG,"Alarm Time "+hour+":"+mminute);
                            startAlarm(hour,mminute);
                        }
                        val++;
                        tempstart=null;
                        tempend=null;
                    }
                }
                freeHours--;
            }
        }
        Log.v(TAG,"Event Strings : "+eventStrings);
        return eventStrings;
    }

MainActivity.java(Part of code2):

In this code segment, I create the Alarm for each of the free time slots start time.

 int broadcastCode=0;
        public void startAlarm(int hour,int mminute){
            broadcastCode++;
            Intent intent=new Intent(MainActivity.this,MyBroadcastReceiver.class);
            PendingIntent pendingIntent=PendingIntent.getBroadcast(MainActivity.this,broadcastCode,intent,0);
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            Calendar cal_alarm=Calendar.getInstance();
            cal_alarm.set(Calendar.HOUR_OF_DAY,hour);
            cal_alarm.set(Calendar.MINUTE,mminute);
            cal_alarm.set(Calendar.SECOND,00);


            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
                alarmManager.setExact(AlarmManager.RTC_WAKEUP,cal_alarm.getTimeInMillis(),pendingIntent);
                Toast.makeText(MainActivity.this,"Alarm > KITKAT & Alarm Set For: "+hour+" : "+mminute,Toast.LENGTH_SHORT).show();
            }
            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT){
                alarmManager.set(AlarmManager.RTC_WAKEUP,cal_alarm.getTimeInMillis(),pendingIntent);
                Toast.makeText(MainActivity.this,"Alarm < KITKAT & Alarm Set For: "+hour+" : "+mminute,Toast.LENGTH_SHORT).show();
            }
        }

When i call the startAlarm() function inside the while loop of getDataFromApi() function,

I get this Error:

can't create handler inside thread that has not called Looper.prepare()

I will be glad if anyone can give me a solution or guidance. Thank you.


Solution

  • Checkout this link here: Can't create handler inside thread that has not called Looper.prepare()

    But the problem is the 'toast' lines inside your startAlarm method like this one:

    Toast.makeText(MainActivity.this,"Alarm > KITKAT & Alarm Set For: "+hour+" : "+mminute,Toast.LENGTH_SHORT).show();
    

    Any time a view is updated in Android, it must be done on the 'main thread' also known as the 'UI thread'.

    It might be better to use logging here rather than toast.