简体   繁体   中英

How can I run this class in the UI thread?

I have the class ScheduleTimer that works on the array of dates. Here it is:

class ScheduleTimer {

    public TextView textView;

    private Timer dateTimer;

    private Timer remainderTimer;

    private Date formatDate = new Date();

    private Date nextDate;

    private boolean remainderTimerStarted;

    private static final long REMINDER_UPDATE_INTERVAL = 1000;

    private static String[] DATES;

    private int currentIndex;

    public ScheduleTimer(final TextView t) {
        textView = t;
        dateTimer = new Timer();
    }

    public void main(String[] dates) throws ParseException {
        checkDates(dates);
        run();
    }

    private void checkDates(String[] dates) throws ParseException {
        List<String> list = new ArrayList<>();
        DateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.ENGLISH);
        for(String date : dates) {
            long current = System.currentTimeMillis() + 1000;
            if(format.parse(date).getTime() - current > 0) {
                list.add(date);
            }
        }
        DATES = new String[list.size()];
        list.toArray(DATES);
    }

    private void run() {
        nextDate = parseDate(DATES[currentIndex]);
        schedule();
    }

    public void schedule() {
        runSecondsCounter();
        dateTimer.schedule(new TimerTask() {

            @Override
            public void run() {

                System.out.println("Current date is:" + new Date());
                currentIndex++;
                if (currentIndex < DATES.length) {
                    nextDate = parseDate(DATES[currentIndex]);
                    System.out.println("Next date is:" + nextDate);
                    schedule();
                } else {
                    remainderTimer.cancel();
                }
            }
        }, nextDate);

    }

    private Date parseDate(String nextDate) {
        Date date = null;
        DateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm",
                Locale.ENGLISH);
        try {
            date = format.parse(nextDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    private void runSecondsCounter() {
        if (remainderTimerStarted) {
            remainderTimer.cancel();
        }

        remainderTimer = new Timer();
        remainderTimer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                remainderTimerStarted = true;
                long remains = nextDate.getTime() - new Date().getTime();
                System.out.println("Remains: " + (remains / 1000) + " seconds");
                formatDate.setTime(remains);
                textView.setText(formatDate.toString());
            }
        }, REMINDER_UPDATE_INTERVAL, REMINDER_UPDATE_INTERVAL);
    }
}

It works fine if I run it just like a Java application, not android, and it prints out every counted second in the console. But when it comes to run it in the android environment, it either says that the UI thread cannot be touched from any other thread, or it gives me NullPointerException in the method run() of the class ScheduleTimer .

I'm using it like this: new ScheduleTimer(textView).main(new String[] {"13.04.2015 13:59", "13.04.2015 14:14", "13.04.2015 14:15"});

I tried using AsyncTask or Handler , but probably, I didn't do it right. Anyway, I need to find the way to update my TextView somehow using this class.

Could anybody help me with that? How can I run it normally in my onCreateView method and pass the needed TextView correctly?

runOnUiThread() method will send your Runnable to execute onto the main thread. In run() , you can manipulate UI controls:

@Override
public void run() {
     remainderTimerStarted = true;
     long remains = nextDate.getTime() - new Date().getTime();
     formatDate.setTime(remains);
     runOnUiThread(new Runnable() {    // <= here!
          @Override
          public void run() {
              textView.setText(formatDate.toString());
          }
     });
 }

Check this for more explanation.

A skeleton of your AsyncTask would be:

public class ListLoader extends AsyncTask<Void, Void, String> {

        ProgressDialog Asycdialog = new ProgressDialog(CreateGroup.this);
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            System.out.println("Pre Execute");
            Asycdialog.setMessage("Working");
            Asycdialog.getWindow().setGravity(Gravity.CENTER_VERTICAL);
            Asycdialog.getWindow().setGravity(Gravity.CENTER_HORIZONTAL);
            Asycdialog.setCancelable(false);
            Asycdialog.show();
            super.onPreExecute();
        }

        protected void onPostExecute(String result) {
            Asycdialog.cancel();

            //Play with result here - Update UI
        }

        @Override
        protected String doInBackground(Context... params) {

            //Memory intense or long running operation here
            publishProgress(progress); //Publish your progress - update a textView

            return "result will be sent to onPostExecute()";

        }

        protected void onProgressUpdate(String... values) {

            super.onProgressUpdate(values);
            Asycdialog.setMessage("" + values[0]);
        }


    }

The complete answer is: Your fragment:

public class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);

            TextView textView = (TextView) rootView.findViewById(R.id.tv);

            try {
                new ScheduleTimer(textView, getActivity())
                        .main(new String[] {"13.04.2015 13:59", "13.04.2015 14:14", "13.04.2015 14:15"});
            } catch (ParseException e) {
                e.printStackTrace();
            }

            return rootView;
        }
    }

Your ScheduleTimer class:

class ScheduleTimer {

    public TextView textView;

    private Timer dateTimer;

    private Timer remainderTimer;

    private Date formatDate = new Date();

    private Date nextDate;

    private boolean remainderTimerStarted;

    private static final long REMINDER_UPDATE_INTERVAL = 1000;

    private static String[] DATES;

    private int currentIndex;

    private Activity activity;

    public ScheduleTimer(final TextView t, Activity a) {
        textView = t;
        activity = a;
        dateTimer = new Timer();
    }

    public void main(String[] dates) throws ParseException {
        checkDates(dates);
        run();
    }

    private void checkDates(String[] dates) throws ParseException {
        List<String> list = new ArrayList<>();
        DateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.ENGLISH);
        for(String date : dates) {
            long current = System.currentTimeMillis() + 1000;
            if(format.parse(date).getTime() - current > 0) {
                list.add(date);
            }
        }
        DATES = new String[list.size()];
        list.toArray(DATES);
    }

    private void run() {
        nextDate = parseDate(DATES[currentIndex]);
        schedule();
    }

    public void schedule() {
        runSecondsCounter();
        dateTimer.schedule(new TimerTask() {

            @Override
            public void run() {

                System.out.println("Current date is:" + new Date());
                currentIndex++;
                if (currentIndex < DATES.length) {
                    nextDate = parseDate(DATES[currentIndex]);
                    System.out.println("Next date is:" + nextDate);
                    schedule();
                } else {
                    remainderTimer.cancel();
                }
            }
        }, nextDate);

    }

    private Date parseDate(String nextDate) {
        Date date = null;
        DateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm",
                Locale.ENGLISH);
        try {
            date = format.parse(nextDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    private void runSecondsCounter() {
        if (remainderTimerStarted) {
            remainderTimer.cancel();
        }

        remainderTimer = new Timer();
        remainderTimer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                remainderTimerStarted = true;
                long remains = nextDate.getTime() - new Date().getTime();
                System.out.println("Remains: " + (remains / 1000) + " seconds");
                formatDate.setTime(remains);

                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(formatDate.toString());
                    }
                });

            }
        }, REMINDER_UPDATE_INTERVAL, REMINDER_UPDATE_INTERVAL);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM