Java tutorial
package com.bellman.bible.android.view.activity.base; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import com.bellman.bible.android.activity.R; import com.bellman.bible.android.view.util.UiUtils; import com.bellman.bible.util.SharedConstants; import org.apache.commons.lang3.StringUtils; import org.crosswire.common.progress.JobManager; import org.crosswire.common.progress.Progress; import org.crosswire.common.progress.WorkEvent; import org.crosswire.common.progress.WorkListener; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * Base class for any screen that shows job progress indicators * * @author Martin Denham [mjdenham at gmail dot com] * @see gnu.lgpl.License for license details.<br> * The copyright to this program is held by it's author. */ public class ProgressActivityBase extends CustomTitlebarActivityBase { private static final String TAG = "ProgressActivityBase"; private Map<Progress, ProgressUIControl> progressMap = new HashMap<Progress, ProgressUIControl>(); private LinearLayout progressControlContainer; private WorkListener workListener; private Queue<Progress> progressNotificationQueue = new ConcurrentLinkedQueue<Progress>(); private TextView taskKillWarningView; private TextView noTasksMessageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); UiUtils.applyTheme(this); } /** * Wait until subclass has setContentView before looking for controls. */ @Override public void onResume() { super.onResume(); Log.i(TAG, "Displaying " + TAG + " view"); progressControlContainer = (LinearLayout) findViewById(R.id.progressControlContainer); initialiseView(); } private void initialiseView() { // prepare to show no tasks msg noTasksMessageView = (TextView) findViewById(R.id.noTasksRunning); taskKillWarningView = (TextView) findViewById(R.id.progressStatusMessage); Iterator<Progress> jobsIterator = JobManager.iterator(); while (jobsIterator.hasNext()) { Progress job = jobsIterator.next(); findOrCreateUIControl(job); } // allow call back and continuation in the ui thread after JSword has been initialised final Handler uiHandler = new Handler(); final Runnable uiUpdaterRunnable = new Runnable() { @Override public void run() { Progress prog = progressNotificationQueue.poll(); if (prog != null) { updateProgress(prog); } } }; // listen for Progress changes and call the above Runnable to update the ui workListener = new WorkListener() { @Override public void workProgressed(WorkEvent ev) { callUiThreadUpdateHandler(ev); } @Override public void workStateChanged(WorkEvent ev) { callUiThreadUpdateHandler(ev); } private void callUiThreadUpdateHandler(WorkEvent ev) { Progress prog = ev.getJob(); progressNotificationQueue.offer(prog); // switch back to ui thread to continue uiHandler.post(uiUpdaterRunnable); } }; JobManager.addWorkListener(workListener); // give new jobs a chance to start then show 'No Job' msg if nothing running uiHandler.postDelayed(new Runnable() { @Override public void run() { if (!JobManager.iterator().hasNext()) { showNoTaskMsg(true); } } }, 4000); } /** * virtual method called on ui thread to update progress. Can be overridden for subclass specific ui updates br make sure this method is called to update progres controls */ protected void updateProgress(Progress prog) { // if this is called then ensure the no tasks msg is not also displayed showNoTaskMsg(false); int done = prog.getWork(); String status = getStatusDesc(prog); final ProgressUIControl progressUIControl = findOrCreateUIControl(prog); progressUIControl.showMsg(status); progressUIControl.showPercent(done); if (prog.isFinished() && !progressUIControl.isFinishNotified) { Log.i(TAG, "Job finished:" + prog.getJobName()); progressUIControl.isFinishNotified = true; jobFinished(prog); } } protected void jobFinished(Progress job) { // do nothing by default } /** * helper method that returns true if alll jobs are finished * * @return true if all jobs finished or no jobs */ protected boolean isAllJobsFinished() { Iterator<Progress> jobsIterator = JobManager.iterator(); while (jobsIterator.hasNext()) { Progress job = jobsIterator.next(); if (!job.isFinished()) { return false; } } return true; } /** * format a descriptive string from a Progress object * * @param prog * @return */ protected String getStatusDesc(Progress prog) { // compose a descriptive string showing job name and current section if relevant String status = prog.getJobName() + SharedConstants.LINE_SEPARATOR; if (!StringUtils.isEmpty(prog.getSectionName()) && !prog.getSectionName().equalsIgnoreCase(prog.getJobName())) { status += prog.getSectionName(); } return status; } protected void hideButtons() { View buttonPanel = findViewById(R.id.button_panel); if (buttonPanel != null) { buttonPanel.setVisibility(View.INVISIBLE); } } protected void setMainText(String text) { ((TextView) findViewById(R.id.progressStatusMessage)).setText(text); } private void showNoTaskMsg(boolean bShow) { if (noTasksMessageView != null && taskKillWarningView != null) { if (bShow) { noTasksMessageView.setVisibility(View.VISIBLE); // if the no-tasks msg is show then hide the warning relating to running tasks taskKillWarningView.setVisibility(View.INVISIBLE); } else { noTasksMessageView.setVisibility(View.GONE); taskKillWarningView.setVisibility(View.VISIBLE); } } } /** * get a UI control for the current prog from the previously created controls, or create one * * @param prog * @return */ protected ProgressUIControl findOrCreateUIControl(Progress prog) { ProgressUIControl uiControl = progressMap.get(prog); if (uiControl == null) { uiControl = new ProgressUIControl(); progressMap.put(prog, uiControl); progressControlContainer.addView(uiControl.parent); uiControl.showMsg(prog.getJobName()); uiControl.showPercent(prog.getWork()); } return uiControl; } @Override protected void onPause() { super.onPause(); JobManager.removeWorkListener(workListener); } /** * contains a TextView desc and ProgressBar for a single Job */ class ProgressUIControl { LinearLayout parent = new LinearLayout(ProgressActivityBase.this); TextView status = new TextView(ProgressActivityBase.this); ProgressBar progressBar = new ProgressBar(ProgressActivityBase.this, null, android.R.attr.progressBarStyleHorizontal); boolean isFinishNotified; public ProgressUIControl() { parent.setOrientation(LinearLayout.VERTICAL); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); parent.addView(status, lp); parent.addView(progressBar, lp); progressBar.setMax(100); showMsg("Starting..."); } void showMsg(String msg) { status.setText(msg); } void showPercent(int percent) { progressBar.setIndeterminate(percent == 0); progressBar.setProgress(percent); } } }