Question

I have a custom calendar. For its month view I use grid view. On each day of the calendar the number of day of month and the number of events on each day are shown. To reach that goal I ask for the events of each day in getView. To increase performance I use an holder within get view. But unfortunately my app crashes quite often and if I switch from one month to the next it is very slow. If the user clicks on a button for next month setGridCellAdapterToDate is called.

public void setGridCellAdapterToDate(int month, int year)
{
    adapter = new GridCellAdapter(getActivity().getApplicationContext(), calendarView,R.id.calendar_day_gridcell, month, year);
    _calendar.set(year, month - 1, _calendar.get(Calendar.DAY_OF_MONTH));
    currentMonth.setText(dateFormatter.format(dateTemplate, _calendar.getTime()));
    adapter.notifyDataSetChanged();
    calendarView.setAdapter(adapter);
    calendarView.setSelected(true);

}

Is there a way to increase the performance of my calendar?

public class GridCellAdapter extends BaseAdapter implements OnClickListener, OnLongClickListener
{
    private static final String tag = "GridCellAdapter";
    private final Context _context;

    private final List<String> list;
    private static final int DAY_OFFSET = 1;
    private final String[] weekdays = new String[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    private final String[] months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
    private final int[] daysOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    private final int month, year;
    private int daysInMonth, prevMonthDays;
    private int currentDayOfMonth;
    private int currentWeekDay;
    private Button gridcell;
    private TextView num_events_per_day;
    private final HashMap eventsPerMonthMap;
    SimpleDateFormat("dd-MMM-yyyy");
    public GridCellAdapter(Context context, GridView gv, int textViewResourceId, int month, int year)
        {
            super();
            this._context = context;
            this.list = new ArrayList<String>();
            this.month = month;
            this.year = year;
                                    this.mGv = gv;
            Log.d(tag, "==> Passed in Date FOR Month: " +                  month + " " + "Year: " + year);
            Calendar calendar = Calendar.getInstance();
            setCurrentDayOfMonth(calendar.get(Calendar.DAY_OF_MONTH));
            setCurrentWeekDay(calendar.get(Calendar.DAY_OF_WEEK));
            Log.d(tag, "New Calendar:= " + calendar.getTime().toString());
            Log.d(tag, "CurrentDayOfWeek :" + getCurrentWeekDay());
            Log.d(tag, "CurrentDayOfMonth :" + getCurrentDayOfMonth());

            // Print Month
            printMonth(month, year);

            // Find Number of Events
            eventsPerMonthMap = findNumberOfEventsPerMonth(year, month);
        }
    private String getMonthAsString(int i)
        {
            return months[i];
        }

    private String getWeekDayAsString(int i)
        {
            return weekdays[i];
        }

    private int getNumberOfDaysOfMonth(int i)
        {
            return daysOfMonth[i];
        }

    public String getItem(int position)
        {
            return list.get(position);
        }

    public int getCount()
        {
            return list.size();
        }

    /**
     * Prints Month
     * 
     * @param mm
     * @param yy
     */
    private void printMonth(int mm, int yy)
        {

            Log.d(tag, "==> printMonth: mm: " + mm + " " + "yy: " + yy);
            // The number of days to leave blank at
            // the start of this month.
            int trailingSpaces = 0;
            int leadSpaces = 0;
            int daysInPrevMonth = 0;
            int prevMonth = 0;
            int prevYear = 0;
            int nextMonth = 0;
            int nextYear = 0;

            int currentMonth = mm - 1;
            String currentMonthName = getMonthAsString(currentMonth);
            daysInMonth = getNumberOfDaysOfMonth(currentMonth);

            Log.d(tag, "Current Month: " + " " + currentMonthName + " having " + daysInMonth + " days.");

            // Gregorian Calendar : MINUS 1, set to FIRST OF MONTH
            GregorianCalendar cal = new GregorianCalendar(yy, currentMonth, 1);
            Log.d(tag, "Gregorian Calendar:= " + cal.getTime().toString());
            Calendar caltemp = Calendar.getInstance();
            Integer intMonat = caltemp.get(Calendar.MONTH);
            if (currentMonth == 11)
                {
                    prevMonth = currentMonth - 1;
                    daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
                    nextMonth = 0;
                    prevYear = yy;
                    nextYear = yy + 1;
                    Log.d(tag, "*->PrevYear: " + prevYear + " PrevMonth:" + prevMonth + " NextMonth: " + nextMonth + " NextYear: " + nextYear);
                }
            else if (currentMonth == 0)
                {
                    prevMonth = 11;
                    prevYear = yy - 1;
                    nextYear = yy;
                    daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
                    nextMonth = 1;
                    Log.d(tag, "**--> PrevYear: " + prevYear + " PrevMonth:" + prevMonth + " NextMonth: " + nextMonth + " NextYear: " + nextYear);
                }
            else
                {
                    prevMonth = currentMonth - 1;
                    nextMonth = currentMonth + 1;
                    nextYear = yy;
                    prevYear = yy;
                    daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
                    Log.d(tag, "***---> PrevYear: " + prevYear + " PrevMonth:" + prevMonth + " NextMonth: " + nextMonth + " NextYear: " + nextYear);
                }

            // Compute how much to leave before before the first day of the
            // month.
            // getDay() returns 0 for Sunday.
            int currentWeekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
            trailingSpaces = currentWeekDay;

            Log.d(tag, "Week Day:" + currentWeekDay + " is " + getWeekDayAsString(currentWeekDay));
            Log.d(tag, "No. Trailing space to Add: " + trailingSpaces);
            Log.d(tag, "No. of Days in Previous Month: " + daysInPrevMonth);

            if (cal.isLeapYear(cal.get(Calendar.YEAR)) && mm == 1)
                {
                    ++daysInMonth;
                }

            // Trailing Month days
            for (int i = 0; i < trailingSpaces; i++)
                {
                    Log.d(tag, "PREV MONTH:= " + prevMonth + " => " + getMonthAsString(prevMonth) + " " + String.valueOf((daysInPrevMonth - trailingSpaces + DAY_OFFSET) + i));
                    list.add(String.valueOf((daysInPrevMonth - trailingSpaces + DAY_OFFSET) + i) + "-GREY" + "-" + getMonthAsString(prevMonth) + "-" + prevYear);
                }

            // Current Month Days
            for (int i = 1; i <= daysInMonth; i++)
                {
                    Log.d(currentMonthName, String.valueOf(i) + " " + getMonthAsString(currentMonth) + " " + yy);
                    if (i == getCurrentDayOfMonth() && mm  == intMonat+1)
                        {
                            list.add(String.valueOf(i) + "-BLUE" + "-" + getMonthAsString(currentMonth) + "-" + yy);
                        }
                    else
                        {
                            list.add(String.valueOf(i) + "-WHITE" + "-" + getMonthAsString(currentMonth) + "-" + yy);
                        }

                }

            // Leading Month days
            for (int i = 0; i < list.size() % 7; i++)
                {
                    Log.d(tag, "NEXT MONTH:= " + getMonthAsString(nextMonth));
                    list.add(String.valueOf(i + 1) + "-GREY" + "-" + getMonthAsString(nextMonth) + "-" + nextYear);
                }
        }

    /**
     * NOTE: YOU NEED TO IMPLEMENT THIS PART Given the YEAR, MONTH, retrieve
     * ALL entries from a SQLite database for that month. Iterate over the
     * List of All entries, and get the dateCreated, which is converted into
     * day.
     * 
     * @param year
     * @param month
     * @return
     */
    private HashMap findNumberOfEventsPerMonth(int year, int month)
        {
            HashMap map = new HashMap<String, Integer>();
            // DateFormat dateFormatter2 = new DateFormat();
            //                      
            // String day = dateFormatter2.format("dd", dateCreated).toString();
            //
            // if (map.containsKey(day))
            // {
            // Integer val = (Integer) map.get(day) + 1;
            // map.put(day, val);
            // }
            // else
            // {
            // map.put(day, 1);
            // }
            return map;
        }



    public long getItemId(int position)
        {
            return position;
        }


    public View getView(int position, View convertView, ViewGroup parent)
        {
        ViewHolder holder;
        Integer intRowNumber = 5;
            View row = convertView;
            if (row == null)
                {
                    LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    row = inflater.inflate(R.layout.calendar_day_gridcell, parent, false);
                    //convertView = inflater.inflate(R.layout.calendar_day_gridcell,parent,false);
                    holder = new ViewHolder();
                    holder.text = (TextView)row.findViewById(R.id.num_events_per_day);
                    holder.gridcell= (Button)row.findViewById(R.id.calendar_day_gridcell);
                    //holder.EventsofMonth = openCalendar.getEventsOfMonth(getActivity(), caltemp.getTimeInMillis(),strCalendarId);
                    row.setTag(holder);
                } else {
                    holder = (ViewHolder)row.getTag();
                }
            int intHeight = mGv.getHeight();
            intHeight = intHeight/intRowNumber;
            AbsListView.LayoutParams param = new AbsListView.LayoutParams(
                    android.view.ViewGroup.LayoutParams.FILL_PARENT,
                    mGv.getHeight()/intRowNumber);

            //row.setLayoutParams(param);
            row.setLayoutParams(param);
            // Get a reference to the Day gridcell
            //gridcell = (Button) row.findViewById(R.id.calendar_day_gridcell);
            //gridcell.setOnClickListener(new MyOnClickListener(position));  
            holder.gridcell.setOnClickListener(this);  
            holder.gridcell.setOnLongClickListener(this);  

            // ACCOUNT FOR SPACING

            Log.d(tag, "Current Day: " + getCurrentDayOfMonth());
            String[] day_color = list.get(position).split("-");
            String theday = day_color[0];
            String themonth = day_color[2];
            String theyear = day_color[3];
            String selection = "((" + CalendarContract.Events.DTSTART
                    + " >= ?) AND (" + CalendarContract.Events.DTEND + " <= ?) AND (" + CalendarContract.Events.DELETED + " = ?) AND (" + CalendarContract.Events.CALENDAR_ID + " = ?))";

            if ((!eventsPerMonthMap.isEmpty()) && (eventsPerMonthMap != null))
                {
                    if (eventsPerMonthMap.containsKey(theday))
                        {
                            //num_events_per_day = (TextView) row.findViewById(R.id.num_events_per_day);
                            Integer numEvents = (Integer) eventsPerMonthMap.get(theday);
                            //num_events_per_day.setText(numEvents.toString());


                        }
                }

            // Set the Day GridCell


            holder.gridcell.setText(theday);

            holder.gridcell.setTag(theday + "-" + themonth + "-" + theyear);
            Log.d(tag, "Setting GridCell " + theday + "-" + themonth + "-" + theyear);

            if (day_color[1].equals("GREY"))
                {
                    holder.gridcell.setTextColor(Color.LTGRAY);
                }
            if (day_color[1].equals("WHITE"))
                {
                    holder.gridcell.setTextColor(Color.WHITE);
                }
            if (day_color[1].equals("BLUE"))
                {
                    //gridcell.setTextColor(getResources().getColor(R.color.static_text_color));


                holder.gridcell.setTextColor(Color.BLUE);
                DisplayMetrics metrics;
                metrics = getActivity().getApplicationContext().getResources().getDisplayMetrics();
                float Textsize = 0;
                Textsize = holder.gridcell.getTextSize()/metrics.density;
                holder.gridcell.setTextSize(Textsize+4);                                    

                }

                //ermittle die Anzahl der Events an diesem Tag und schreibe sie in num_events_per_day
                Integer intAnzEventsonSelectedDay = 0;
                //num_events_per_day = (TextView) row.findViewById(R.id.num_events_per_day);
                String strCurrentDatum = theday + "-" + month + "-" + year;
                SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

                Date dateObj = null;
                try {
                    dateObj = sdf.parse(strCurrentDatum);
                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                String temp = dateObj.toString();

                caltemp.setTime(dateObj);
                Cursor curCalendar = openCalendar.getEventsOfDay(getActivity(), caltemp.getTimeInMillis(),strCalendarId);
                curCalendar.moveToFirst();
                intAnzEventsonSelectedDay = curCalendar.getCount();
                if (intAnzEventsonSelectedDay > 4){
                    holder.text.setTextColor(Color.RED);
                } else{
                    //
                }

                holder.text.setText(intAnzEventsonSelectedDay.toString());
             return row;
        }
Was it helpful?

Solution

I think part of the issue with performance is actually with how much work you are doing to get to a single month. The best thing I can tell you is firstly switch from using Calendar to using MonthDisplayHelper. Its a built in Android class that basically helps you layout a single month. Its a in a great format too, splitting each week into an int array. Though still have the Calendar there as its a great way to keep the current day info at hand. More importantly, instead of loading every event from a single day, load the month first, then use an AsyncTask to load the individual events after off the UI thread. Imagine having a few events a month, thats a lot of computation before you ever show just a month view to the user. A great example of this would be googles default calendar. If you have enough events you will notice they start to load up after the month view shows up. Its great functionality from usability standpoint.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top