Handler handleMessage not being called - android

I am running a simple handler and even when I do a handler.sendMessage(), the handleMessage method is not called.
Here is the Handler definition:
protected static class TimeoutHandler extends Handler {
private final WeakReference<PROQuestion> activity;
public TimeoutHandler(PROQuestion activity) {
this.activity = new WeakReference<PROQuestion>(activity);
}
#Override
public void handleMessage(Message msg) { //never gets called
boolean firstScreen = true;
if (activity.get() == null) {
removeCallbacksAndMessages(0);
} else {
Intent startNewActivityOpen = null;
startNewActivityOpen = new Intent(activity.get(), Home.class);
startNewActivityOpen.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle bundle = activity.get().getIntent().getExtras();
if (bundle != null) startNewActivityOpen.putExtras(bundle);
activity.get().startActivity(startNewActivityOpen);
activity.get().finish();
}
}
I am calling the handler on the main thread of my onCreate():
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TimeoutHandler handlerTimeout = new TimeoutHandler(this);
if (handlerTimeout != null) {
removeTimeout();
Message message = handlerTimeout.obtainMessage();
message.what = 100;
handlerTimeout.sendMessage(message);
//handlerTimeout.sendMessageAtTime(message, SystemClock.uptimeMillis() + GlobalVars.longTimeout);
}
if (handlerTimeout.hasMessages(100)) { //returns true
Log.d(getClass().getSimpleName(),"messages found");
}
}
Why is the handleMessage method never called? There are no error messages or crashes.

Related

Run the tasks in background ( AsyncTask )

In NoteInfoactivity I have a code below, but
Note allNote = NoteDatabase.getInstance(getApplicationContext()).noteDao().getAllNoteId(noteID);
is executed in main thread. How can i execute it in background? what is the best way?
public class NoteInfoActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note_info);
TextView textViewTitle = findViewById(R.id.textViewNoteTitle);
TextView textViewPriority = findViewById(R.id.textViewPriority);
Intent intent = getIntent();
if (intent != null && intent.hasExtra("NoteID")) {
long noteID = intent.getIntExtra("NoteID", -1);
Note allNote = NoteDatabase.getInstance(getApplicationContext()).noteDao().getAllNoteId(noteID);
String title = allNote.getTitle();
int priority = allNote.getPriority();
textViewTitle.setText(title);
textViewPriority.setText(String.valueOf(priority));
} else {
Toast.makeText(getApplicationContext(), R.string.empty_not_saved, Toast.LENGTH_SHORT).show();
}
}
}
You can put it in a thread and then call for a handler to do the UI changes on the main thread.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note_info);
TextView textViewTitle = findViewById(R.id.textViewNoteTitle);
TextView textViewPriority = findViewById(R.id.textViewPriority);
Intent intent = getIntent();
Handler handler = new Handler();
if (intent != null && intent.hasExtra("NoteID")) {
long noteID = intent.getIntExtra("NoteID", -1);
new Thread(new Runnable() {
#Override
public void run() {
Note allNote = NoteDatabase.getInstance(getApplicationContext()).noteDao().getAllNoteId(noteID);
handler.post((Runnable) () -> {
String title = allNote.getTitle();
int priority = allNote.getPriority();
textViewTitle.setText(title);
textViewPriority.setText(String.valueOf(priority));
});
}
}).start();
} else {
Toast.makeText(getApplicationContext(), R.string.empty_not_saved, Toast.LENGTH_SHORT).show();
}
}

What is the solution of "This Handler Class Should Be Static Or Leaks Might Occur"?

I am working on a Bluetooth communication project where I need to transfer data among devices.Upon receiving an InputStream I pass the data to the UI thread from the worker thread using the following code:-
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = handler.obtainMessage(MessageConstants.MESSAGE_READ,numBytes, -1,mmBuffer);
readMsg.sendToTarget();
Below is my handler class:-
public Handler mHandler = new Handler() {
public synchronized void handleMessage(Message msg) {
byte[] readBuf=(byte[])msg.obj;
String readMsg=new String(readBuf,0,msg.arg1);
TextView textView=findViewById(R.id.textview);
textView.setText(readMsg);
}
}
But This shows the following warning:
This Handler class should be static or leaks might occur(anonymous android.os.Handler).
I tried making the class static but then it gives the following error:-
Non-static method findViewById(int) can't be referenced from a static context.
What should I do to resolve this?
public MyHandler mHandler;
public static class MyHandler extends Handler {
WeakReference<TextView> mTextViewReference;
public MyHandler(TextView textView) {
mTextViewReference = new WeakReference<TextView>(textView);
}
public synchronized void handleMessage(Message msg) {
byte[] readBuf=(byte[])msg.obj;
String readMsg = new String(readBuf,0,msg.arg1);
TextView textView = mTextViewReference.get();
if(textView != null) {
textView.setText(readMsg);
};
}
public void clear() {
mTextViewReference.clear();
mTextViewReference = null;
}
}
protected void onCreate(final Bundle savedInstanceState) {
....
mHandler = new MyHandler(findViewById(R.id.textView));
....
}
#Override
public void onDestroy() {
if(mHandler != null) {
mHandler.clear();
mHandler = null;
}
super.onDestroy();
}
EDIT
Fix above works fine if you just want to update one single TextView. However, very often, you need to take more actions and update more stuff (not only a single TextView). So, I think you can create a Interface that is invoked every time a message is received. Something like:
public class MyActivity extends Activity {
public MyHandler mHandler;
protected final void onCreate(final Bundle savedInstanceState) {
//....
mHandler = new MyHandler(new MyHandler.OnMessageReceivedListener() {
#Override
public void handleMessage(final String message) {
// Update the views as you with
}
});
//....
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.clear();
}
public static class MyHandler extends Handler {
WeakReference<OnMessageReceivedListener> mListenerReference;
public MyHandler(OnMessageReceivedListener listener) {
mListenerReference = new WeakReference<>(listener);
}
public synchronized void handleMessage(Message msg) {
byte[] readBuf=(byte[])msg.obj;
String readMsg = new String(readBuf,0,msg.arg1);
OnMessageReceivedListener listener = mListenerReference.get();
if(listener != null) {
listener.handleMessage(readMsg);
};
}
public void clear() {
mListenerReference.clear();
}
public interface OnMessageReceivedListener {
void handleMessage(String message);
}
}
}
You're not doing very heavy staff in your handleMessage part, so no need to extend Handler keep it simple and ligthweight; just add a callback instead. Create a callback in your Activity/Fragment:
private class MessageCallback implements Handler.Callback {
#Override
public boolean handleMessage(#NonNull Message message) {
// Here you can call any UI component you want
TextView textView=findViewById(R.id.textview);
textView.setText(readMsg);
return true;
}
}
Then call it as:
Handler handler = new Handler(getMainLooper(), new MessageCallback());
Message readMsg = handler.obtainMessage(what, arg1, arg2, object);
readMsg.sendToTarget();

ProgressDialog misbehaviour after activity rotation

I need to show a ProgressDialog which will show even after rotation of activity. After rotation of the activity progressDialog is keep displaying, it doesn't get dismissed even after I signal it to dismiss by invoking idle(). what could be the reason. Thanks in advance!
public abstract class BaseActivity extends AppCompatActivity {
private final int command = 1;
private final String action = "show-progress-dialog";
private boolean showProgress = false;
private volatile ProgressDialog progressDialog;
private Handler mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
if (message.getData() != null && message.what == command) {
if (message.getData().getBoolean("show")) {
showProgressDialog();
} else {
safeDismiss();
}
}
}
};
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("showProgress", showProgress);
safeDismiss();
super.onSaveInstanceState(outState);
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showProgress = savedInstanceState != null && savedInstanceState.getBoolean("showProgress", false);
if (showProgress) {
showProgressDialog();
}
}
protected void busy() {
if (Looper.getMainLooper() == Looper.myLooper()) {//in ui thread
showProgressDialog();
return;
}
Message message = mHandler.obtainMessage(command);
Bundle data = new Bundle();
data.putBoolean("show", true);
data.putString("action", action);
message.setData(data);
message.sendToTarget();
}
protected void idle() {
if (Looper.getMainLooper() == Looper.myLooper()) {//in ui thread
safeDismiss();
return;
}
Message message = mHandler.obtainMessage(command);
Bundle data = new Bundle();
data.putBoolean("show", false);
data.putString("action", action);
message.setData(data);
message.sendToTarget();
}
private void showProgressDialog() {
safeDismiss();
progressDialog = ProgressDialog.show(this, null, "please wait…", true, false);
showProgress = true;
}
private void safeDismiss() {
if (progressDialog != null) {
progressDialog.dismiss();
showProgress = false;
progressDialog = null;
}
}
}
Read android:configChanges
When a configuration change occurs at runtime, the activity is shut
down and restarted by default, but declaring a configuration with this
attribute will prevent the activity from being restarted.
<activity
android:name=".ActivityName"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name" >
</activity>
Then
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
if (progressDialog.isShowing())
{
progressDialog .dismiss();
}
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
if (progressDialog.isShowing())
{
progressDialog .dismiss();
}
}
}

Android: Execute http requests via Service

I have a trouble with getting Activity(Nullpointerexception) after that I have rotate screen and received callback from AsyncTask to update my views of the fragment. If I wont change orientation then everything is OK(but not all the time, sometimes this bug appears)
My main activity:
public class MainActivity extends SherlockFragmentActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager_layout);
fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(this);
session = new SessionManager(getApplicationContext());
if (session.isAuthorizated()) {
disableTabs();
FragmentTransaction ft = fm.beginTransaction();
if (session.termsAndConditions()) {
ft.replace(android.R.id.content, new TermsAndConditionsFragment(), "terms-and-conditions").commit();
}
}
} else {
enableTabs();
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(actionBar.newTab().setText("Log in"), LoginFragment.class, null);
mTabsAdapter.addTab(actionBar.newTab().setText("Calculator"), CalculatorFragment.class, null);
}
}
That`s my fragment:
public class TermsAndConditionsFragment extends SherlockFragment implements OnClickListener, OnTouchListener, OnEditorActionListener, ValueSelectedListener, AsyncUpdateViewsListener {
private static final String TAG = "TermsAndConditionsFragment";
private TermsAndConditionsManager termsAndConditionsM;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prepareData();
}
public void prepareData() {
if (getSherlockActivity() == null)
Log.d(TAG, "Activity is null");
termsAndConditionsM = new TermsAndConditionsManager(getSherlockActivity().getApplicationContext());
termsAndConditions = termsAndConditionsM.getTermsAndConditions();
...
// some stuff
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = init(inflater, container);
return rootView;
}
private View init(LayoutInflater inflater, ViewGroup container) {
rootView = inflater.inflate(R.layout.fragment_terms_and_conditions, container, false);
//bla bla bla
return rootView;
}
public void updateTermsAndConditionsView() {
//update views here
}
#Override
public void onClick(View v) {
ft = fm.beginTransaction();
switch (v.getId()) {
case R.id.etHowMuch:
d = NumberPaymentsPickerFragment.newInstance(getSherlockActivity(), Integer.valueOf(howMuch.replace("£", "")), 0);
d.setValueSelectedListener(this);
d.show(getFragmentManager(), Const.HOW_MUCH);
break;
}
}
#Override
public void onValueSelected() {
Bundle args = new Bundle();
...
ExecuteServerTaskBackground task = new ExecuteServerTaskBackground(getSherlockActivity());
task.setAsyncUpdateViewsListener(this);
task.action = ServerAPI.GET_TERMS_AND_CONDITIONS;
task.args = args;
task.execute();
}
#Override
public void onUpdateViews() {
prepareData();
updateTermsAndConditionsView();
}
}
My AsyncTask with callback:
public class ExecuteServerTaskBackground extends AsyncTask<Void, Void, Void> {
private static final String TAG = "ExecuteServerTaskBackground";
Activity mActivity;
Context mContext;
private AsyncUpdateViewsListener callback;
public ExecuteServerTaskBackground(Activity activity) {
this.mActivity = activity;
this.mContext = activity.getApplicationContext();
}
public void setAsyncUpdateViewsListener(AsyncUpdateViewsListener listener) {
callback = listener;
}
#Override
protected Void doInBackground(Void... params) {
ServerAPI server = new ServerAPI(mContext);
if (!args.isEmpty())
msg = server.serverRequest(action, args);
else
msg = server.serverRequest(action, null);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
callback.onUpdateViews();
}
}
Why does it behave so? How can I get activity correctly if I change orientation.
EDIT:
As I understand correctly nullpointer appears after orientation changed and asynctask executed due to wrong reference between asyctask and Activity. Recreated activity doesnt have this reference thats why when I receive callback I use wrong activity reference which isn`t exist anymore. But how can I save current activity reference?
EDIT:
I have decided to try realize my task throughout Service and that`s what I have done.
Activity:
public class MainFragment extends Fragment implements ServiceExecutorListener, OnClickListener {
private static final String TAG = MainFragment.class.getName();
Button btnSend, btnCheck;
TextView serviceStatus;
Intent intent;
Boolean bound = false;
ServiceConnection sConn;
RESTService service;
ProgressDialog pd = new ProgressDialog();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
intent = new Intent(getActivity(), RESTService.class);
getActivity().startService(intent);
sConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(TAG, "MainFragment onServiceConnected");
service = ((RESTService.MyBinder) binder).getService();
service.registerListener(MainFragment.this);
if (service.taskIsDone())
serviceStatus.setText(service.getResult());
bound = true;
}
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "MainFragment onServiceDisconnected");
bound = false;
}
};
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.main_fragment, container, false);
serviceStatus = (TextView) rootView.findViewById(R.id.tvServiceStatusValue);
btnSend = (Button) rootView.findViewById(R.id.btnSend);
btnCheck = (Button) rootView.findViewById(R.id.btnCheck);
btnSend.setOnClickListener(this);
btnCheck.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnSend:
pd.show(getFragmentManager(), "ProgressDialog");
service.run(7);
service.run(2);
service.run(4);
break;
case R.id.btnCheck:
if (service != null)
serviceStatus.setText(String.valueOf(service.taskIsDone()) + service.getTasksCount());
break;
}
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, "Bind service");
getActivity().bindService(intent, sConn, 0);
}
#Override
public void onPause() {
super.onDestroy();
Log.d(TAG, "onDestroy: Unbind service");
if (!bound)
return;
getActivity().unbindService(sConn);
service.unregisterListener(this);
bound = false;
}
#Override
public void onComplete(String result) {
Log.d(TAG, "Task Completed");
pd.dismiss();
serviceStatus.setText(result);
}
}
Dialog:
public class ProgressDialog extends DialogFragment implements OnClickListener {
final String TAG = ProgressDialog.class.getName();
public Dialog onCreateDialog(Bundle savedInstanceState) {
setRetainInstance(true);
AlertDialog.Builder adb = new AlertDialog.Builder(getActivity())
.setTitle("Title!")
.setPositiveButton(R.string.yes, this)
.setNegativeButton(R.string.no, this)
.setNeutralButton(R.string.maybe, this)
.setCancelable(false)
.setMessage(R.string.message_text)
.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
return true;
}
});
return adb.create();
}
public void onClick(DialogInterface dialog, int which) {
int i = 0;
switch (which) {
case Dialog.BUTTON_POSITIVE:
i = R.string.yes;
break;
case Dialog.BUTTON_NEGATIVE:
i = R.string.no;
break;
case Dialog.BUTTON_NEUTRAL:
i = R.string.maybe;
break;
}
if (i > 0)
Log.d(TAG, "Dialog 2: " + getResources().getString(i));
}
public void onDismiss(DialogInterface dialog) {
Log.d(TAG, "Dialog 2: onDismiss");
// Fix to avoid simple dialog dismiss in orientation change
if ((getDialog() != null) && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
Log.d(TAG, "Dialog 2: onCancel");
}
}
Service:
public class RESTService extends Service {
final String TAG = RESTService.class.getName();
MyBinder binder = new MyBinder();
ArrayList<ServiceExecutorListener> listeners = new ArrayList<ServiceExecutorListener>();
Handler h = new Handler();
RequestManager mRequest;
ExecutorService es;
Object obj;
int time;
StringBuilder builder;
String result = null;
public void onCreate() {
super.onCreate();
Log.d(TAG, "RESTService onCreate");
es = Executors.newFixedThreadPool(1);
obj = new Object();
builder = new StringBuilder();
}
public void run(int time) {
RunRequest rr = new RunRequest(time);
es.execute(rr);
}
class RunRequest implements Runnable {
int time;
public RunRequest(int time) {
this.time = time;
Log.d(TAG, "RunRequest create");
}
public void run() {
Log.d(TAG, "RunRequest start, time = " + time);
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Log.d(TAG, "RunRequest obj = " + obj.getClass());
} catch (NullPointerException e) {
Log.d(TAG, "RunRequest error, null pointer");
}
builder.append("result " + time + ", ");
result = builder.toString();
sendCallback();
}
}
private void sendCallback() {
h.post(new Runnable() {
#Override
public void run() {
for (ServiceExecutorListener listener : listeners)
listener.onComplete();
}
});
}
public boolean taskIsDone() {
if (result != null)
return true;
return false;
}
public String getResult() {
return result;
}
public void registerListener(ServiceExecutorListener listener) {
listeners.add(listener);
}
public void unregisterListener(ServiceExecutorListener listener) {
listeners.remove(listener);
}
public IBinder onBind(Intent intent) {
Log.d(TAG, "RESTService onBind");
return binder;
}
public boolean onUnbind(Intent intent) {
Log.d(TAG, "RESTService onUnbind");
return true;
}
public class MyBinder extends Binder {
public RESTService getService() {
return RESTService.this;
}
}
}
As you mention in your edit, the current Activity is destroyed and recreated on orientation change.
But how can I save current activity reference?
You shouldn't. The previous Activity is no longer valid. This will not only cause NPEs but also memory leaks because the AsyncTask might hold the reference to old Activity, maybe forever.
Solution is to use Loaders.

Handler call to notifyDataSetChanged() not executing

I have an Handler registered in an Activity. handleMessage() calls notifyDataSetChanged on an Adapter. Things work while the Activity has initial focus. However, when I navigate out of the Activity and back in, notifyDataSetChanged() does not work.
FileAdapter is an ArrayAdapter. MergeAdapter is a custom class by CommonsWare. _mergeAdapter contains _fileAdapter.
Activity code:
public void setUpDownloadHandler() {
// Define the Handler that receives messages from the thread and update the progress
_downloadHandler = new Handler() {
public void handleMessage(Message message) {
super.handleMessage(message);
String fileId = (String) message.obj;
int progress = message.arg1;
FileInfo tempFile = null;
for (FileInfo file: _files) {
if (file.getFileId().equals(fileId)) {
file.setDownloadProgress(progress);
tempFile = file;
}
}
if (tempFile != null) {
_files.remove(tempFile);
_files.add(tempFile);
}
_fileAdapter.notifyDataSetChanged();
_mergeAdapter.notifyDataSetChanged();
}
};
}
Passing the handler:
RunnableTask task = new DownloadFileRunnableImpl(application, the_workspace_url, the_file_info, the_workspace_info.getTitle(), the_internal_storage_directory,
_downloadHandler);
Background thread code:
if(temp > previous) {
Message message = new Message();
message.arg1 = _currentProgress.intValue();
message.obj = _fileId;
_progressHandler.sendMessage(message);
previous = temp;
}
The other piece of information is that I'm passing the handler through a Binder and then into the runnable. I do this to run the background thread in a Service. I don't think this is the problem.
EDIT:
It seems like the handler is not associated with the activity the second time it is navigated to (perhaps because onCreate creates a new handler). Is there a way to re-associate or retain the old handler?
Update
The activity is being destroyed when it loses focus to another activity.
I would try putting a log message in your activity's onDestroy method to see if it is getting destroyed, when you navigate away from your activity. So your task may have the handler from the old activity.
Here is my answer, I relied heavily on http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentRetainInstance.html
Really just took their code and changed it so that I have to remake the fragment everytime I want to start the thread (work) again. And it communicates with the Activity through a handler.
public class Main extends Activity implements WorkProgressListener {
private static final String TAG = "tag";
private Handler handler;
private Button startWorkBtn;
private ProgressDialog progressDialog;
private boolean onSaveInstanceFlag = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG,"Main onCreate " + Utils.getThreadId());
setContentView(R.layout.main);
handler = new ProgressHandler();
startWorkBtn = (Button)this.findViewById(R.id.start_work_btn);
startWorkBtn.setEnabled(false);
startWorkBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
Log.i("tag","Main: startWorkBtn onClick ");
startWorkBtn.setEnabled(false);
FragmentManager fm = getFragmentManager();
Fragment workF = (Fragment)fm.findFragmentByTag("work");
if (null == workF) {
workF = new WorkFragment();
Log.i(TAG,"Main new WorkF" + Utils.getThreadId());
startProgressDialog(true);
startWorkBtn.setEnabled(false);
fm.beginTransaction().add(workF, "work").commit();
Log.i(TAG,"Main add(workF) " + Utils.getThreadId());
}
else {
// should never be able to get here.
}
}
});
FragmentManager fm = getFragmentManager();
Fragment loadingFragment = fm.findFragmentByTag("work");
Log.i(TAG,"Main findFragment " + Utils.getThreadId());
if (null == loadingFragment) {
this.startWorkBtn.setEnabled(true);
}
else {
// could also decide to show progress dialog based on savedInstanceState
this.startProgressDialog(true);
}
} // end onCreate
#Override
public void onRestart() {
Log.i(TAG,"Main onRestart " + Utils.getThreadId() );
super.onRestart();
this.onSaveInstanceFlag = false;
}
#Override
public void onResume () {
Log.i(TAG,"Main onResume " + Utils.getThreadId());
super.onResume();
this.onSaveInstanceFlag = false;
}
#Override
public void onSaveInstanceState (Bundle savedInstanceState) {
Log.i(TAG,"Main onSaveInstanceState "+ Utils.getThreadId());
this.onSaveInstanceFlag = true;
super.onSaveInstanceState(savedInstanceState);
if (null != this.progressDialog) {
savedInstanceState.putBoolean("progressDialog", true);
}
else {
savedInstanceState.putBoolean("progressDialog", false);
}
}
#Override
public void onStop () {
Log.i(TAG,"Main onStop " + Utils.getThreadId());
super.onStop();
}
#Override
public void onDestroy () {
Log.i(TAG,"Main onDestroy " + Utils.getThreadId());
super.onDestroy();
this.closeProgressDialog();
this.handler.removeCallbacksAndMessages(null);
}
public class ProgressHandler extends Handler {
#Override
public void handleMessage (Message msg) {
Log.i(TAG,"Main ProgressDialogHandler handleMessage");
Bundle b = msg.getData();
boolean isDone = b.getBoolean("isDone");
String tag = b.getString("tag");
if (isDone && !onSaveInstanceFlag) {
FragmentManager fm = getFragmentManager();
Fragment loader = (Fragment)fm.findFragmentByTag(tag);
fm.beginTransaction().remove(loader).commit();
closeProgressDialog();
Main.this.startWorkBtn.setEnabled(true);
}
}
}
#Override
public void sendProgress(String tag, int progress, int max) {
if ( progress == max) {
Log.i(TAG,"Main sendProgress " + Utils.getThreadId());
Message message = handler.obtainMessage();
Bundle b = new Bundle();
b.putBoolean("isDone", true);
b.putString("tag",tag);
message.setData(b);
this.handler.sendMessage(message);
}
}
private void startProgressDialog(boolean show) {
this.progressDialog = new ProgressDialog(this);
this.progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
this.progressDialog.setMessage("loading");
this.progressDialog.setCancelable(false);
this.progressDialog.show();
}
private void closeProgressDialog() {
if (null != this.progressDialog) {
progressDialog.cancel();
this.progressDialog = null;
}
}
} // end Main
public class WorkFragment extends Fragment {
private static final String TAG = "tag";
private boolean mReady = false;
private boolean mQuiting = false;
private boolean done = false;
public WorkFragment () {}
final Thread mThread = new Thread() {
#Override
public void run () {
synchronized(this) {
while (!mReady) {
Log.i(TAG,"WorkF notReady"+ Utils.getThreadId());
if (mQuiting) {
return;
}
try {
wait();
} catch (InterruptedException e) {
}
}
} // end synchronized
Log.i(TAG,"WorkF starting work "+ Utils.getThreadId());
try {
Log.i(TAG,"WorkF about to sleep"+ Utils.getThreadId());
Thread.currentThread().sleep(10000l);
Log.i(TAG,"WorkF almost finished "+ Utils.getThreadId());
done = true;
} catch (InterruptedException e1) {
e1.printStackTrace();
}
synchronized(this) {
while (!mReady) {
Log.i(TAG,"Activity notReady"+ Utils.getThreadId());
if (mQuiting) {
return;
}
try {
wait();
} catch (InterruptedException e) {
}
}
((WorkProgressListener)getActivity()).sendProgress(WorkFragment.this.getTag(), 100, 100);
} // end synchronized 2
}
};
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.i(TAG,"WorkF, onAttach: "+ Utils.getThreadId());
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG,"WorkF, onCreate: "+ Utils.getThreadId());
setRetainInstance(true);
mThread.start();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(TAG,"WorkF, onActivityCreated: "+ Utils.getThreadId());
if (done) {
((WorkProgressListener)getActivity()).sendProgress(WorkFragment.this.getTag(), 100, 100);
}
synchronized (mThread) {
mReady = true;
mThread.notify();
}
}
#Override
public void onStart()
{
super.onStart();
Log.i(TAG,"WorkF, onStart: "+ Utils.getThreadId() );
}
#Override
public void onDestroy() {
synchronized (mThread) {
mReady = false;
mQuiting = true;
mThread.notify();
}
super.onDestroy();
}
#Override
public void onDetach() {
synchronized (mThread) {
mReady = false;
mThread.notify();
}
super.onDetach();
}
public void restart() {
synchronized (mThread) {
mThread.notify();
}
}
}// end WorkFragment
public interface WorkProgressListener {
public void sendProgress (String tag, int progress, int max);
}

Categories

Resources