GoogleApiClient.Builder.enableAutoManage in Fragment throws IllegalStateException: Recursive entry to executePendingTransactions - android-fragments

I have an AppCompatActivity that has 3 tabs using FragmentTabHost. One of the tabs uses LocationServices. I would like to have the smoothest possible user experience:
If the LocationService is off in the android system, and only if the user chooses the tab that needs the Location I would like to display the AlertDialog to let the user turn on the Location in the system settings.
I have a helper class that is supposed to do all this and it does work in 3 other places in my app. In those 3 places it works "directly" in the Activity, however in this place it needs to work "within" the Fragment of the tab.
The problem is that if I have the line:
builder.enableAutoManage(activity, 0, this);
then builder.build() throws an exception: IllegalStateException: Recursive entry to executePendingTransactions
Any idea how can I achieve my goal?
Here are some related code fragments:
public class CityPreferences extends AppCompatActivity {
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(
mTabHost.newTabSpec("available_cities")
.setIndicator(getString(R.string.tab_all_cities))
, AvailableCityFragment.class, null);
mTabHost.addTab(
mTabHost.newTabSpec("nearby_cities")
.setIndicator(getString(R.string.tab_nearby_cities))
, NearbyCityFragment.class, null);
}
}
In NearbyCityFragment I have this 1 line of code:
class NearbyCityFragment extends Fragment {
...
LocationServiceHelper.getInstance().startOrDisplayDialog(getActivity());
(I tried it in onAttach, onStart, onResume)
And here's my helper class' function:
public class LocationServiceHelper implements
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks {
public boolean startOrDisplayDialog(#NonNull final FragmentActivity activity) {
final boolean servicesConnected = GooglePlayServicesHelper.checkOrDisplayDialog(activity);
if (servicesConnected) {
final boolean isEnabled = isLocationEnabledInSystem(activity);
if (isEnabled) {
if (null == mGoogleApiClient) {
mContext = activity;
mActivity = activity;
final GoogleApiClient.Builder builder = new GoogleApiClient.Builder(mContext)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this);
// the next line seems to cause the problem:
builder.enableAutoManage(activity, 0, this);
mGoogleApiClient = builder
.build();
}
return start();
} else {
final Dialog dialog = getLocationDisabledDialog(activity);
GooglePlayServicesHelper.showDialog(dialog, activity);
}
}
return false;
}
And finally the exception:
06-10 10:23:04.831 26725-26725/com.fletech.android.redalert.debug E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.fletech.android.redalert.debug, PID: 26725
java.lang.IllegalStateException: Recursive entry to executePendingTransactions
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1473)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:490)
at com.google.android.gms.common.api.g.a(Unknown Source)
at com.google.android.gms.common.api.GoogleApiClient$Builder.gI(Unknown Source)
at com.google.android.gms.common.api.GoogleApiClient$Builder.build(Unknown Source)
at com.fletech.android.redalert.helper.LocationServiceHelper.startOrDisplayDialog(LocationServiceHelper.java:113)
at com.fletech.android.redalert.city.NearbyCityFragment.onAttach(NearbyCityFragment.java:44)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:907)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:740)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1501)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:458)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

I believe you must use a unique clientId each time you enable auto manager. From the documentation:
clientId - A non-negative identifier for this client. At any given time, only one auto-managed client is allowed per id. To reuse an id you must first call stopAutoManage(FragmentActivity) on the previous client.

Related

Why is ExecutorService not returning the results of my Task?

UPDATE:
I have a button on a JavaFx App that should do the login after user input email and password.
<Button fx:id="loginButton" layoutX="157.0" layoutY="254.0" mnemonicParsing="false" onAction="#login" prefHeight="30.0" prefWidth="172.0" text="Login" />
I have an ExecutorService on a JavaFX app. I created a task to search the DB. It executes the query well and gets the UserInfo object, the problem is, the ExecutorService is not passing the results to the main thread. This is the main code that is having a problem of null returned from the executor service:
public class LoginController {
#FXML
private Button loginButton;
#FXML
private Label afterLoginText;
#FXML
private TextField email;
#FXML
private PasswordField password;
#FXML
private Hyperlink hyperlink;
#FXML
private ProgressBar progressBar;
private Navegador navegador;
public void login(ActionEvent event) {
afterLoginText.setText("Login in, please wait...");
String emailText = email.getText();
String passwordText = password.getText();
DAOGeneric<UserInfo> dao = new DAOGeneric<>();
LoginAtDataBaseTask loginAtDataBaseTask = new LoginAtDataBaseTask(dao, emailText, passwordText);
progressBar.progressProperty().bind(loginAtDataBaseTask.progressProperty());
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(loginAtDataBaseTask);
loginAtDataBaseTask.setOnSucceeded(workerStateEvent -> {
UserInfo userInfo;
try {
userInfo = (UserInfo) future.get();
} catch (InterruptedException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ExecutionException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
if(userInfo == null){
System.out.println("User info is null");
}
else{
try {
changeToMainScreen(event, userInfo);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
//Set premium level if user have one
//Optional - show premium info
}
});
executorService.shutdown();
}
public void changeToMainScreen(ActionEvent event, UserInfo userInfo) throws IOException {
Stage stage = (Stage) ((Node)event.getSource()).getScene().getWindow();
runMainScreen("/mainScreen.fxml",stage, userInfo);
}
And here is the code of the LoginAtDataBaseTask Class:
public class LoginAtDataBaseTask extends Task <UserInfo> {
private static DAOGeneric<UserInfo> dao;
private static String email;
private static String password;
public LoginAtDataBaseTask(DAOGeneric<UserInfo> dao, String email, String password) {
this.dao = dao;
this.email = email;
this.password = password;
}
#Override
protected UserInfo call() {
return doLogin();
}
private UserInfo doLogin(){
final int maxProgress = 100;
List<UserInfo> usersList = dao.findByAnyParameter("email", email, UserInfo.class);
if(usersList.size() == 1){
updateProgress(99,maxProgress);
UserInfo user1 = usersList.get(0);
String passwordDecoded = DecoderMD5.StringToMD5(password);
if(user1.getUserPassword().equals(passwordDecoded)){
// afterLoginText.setText("Login Sucess!");
return user1;
}
else{
// afterLoginText.setText("Wrong Password!");
}
}
else if(usersList.size()>1){
//More than one user with same email on BD
// afterLoginText.setText("Error code 1 - report to administrator");
}
else if(usersList.size()==0){
// afterLoginText.setText("This email is not registered! Please register first!");
}
else{
//Erro at DAO Search
// afterLoginText.setText("Error code 2 - report to administrator");
}
return null;
}
}
I tried casting on many ways and using Future first to receive the submit and then calling get on the future object, but nothing seems to work. I have already readed the java documents of this related classes but i don't really understand why my object keeps null.
UPDATE: I put a setOnSucceeded but the future.get keeps returning null, and the main javafx ui keeps freezing. What am i keeping doing wrong and what can i do to solve it?
Why does get() return null?
This has to do with the fact that Task is, fundamentally, an implementation of Runnable. It is not an implementation of Callable. Therefore, you are calling #submit(Runnable) which returns a Future<?>1, meaning no result is expected. A Runnable cannot return a value. In other words, the call to #get() will always return null in this case.
But you should really be calling #execute(Runnable) when passing a Task to an ExecutorService, anyway. There's no reason to have a Future object representing the status of the Task. This is for at least two reasons:
The call to Future#get() is a blocking call. The whole purpose of Task is to communincate a result specifically back to the JavaFX Application Thread. And you must never block that thread, as doing so will lead to an unresponsive UI.
A Task is a FutureTask2, which means it is already a Future. If you really need to wait for a result (not on the FX thread), then you can just call #get() on the Task instance.
1. It really should have been defined to return Future<Void>
2. Note that the standard ExecutorService implementation, ThreadPoolExecutor, wraps all submitted Runnable and Callable objects in a FutureTask, at least by default.
How to get the result of a Task
As noted earlier, the purpose of Task (and the other javafx.concurrent classes) is to offload work to a background thread but communicate a result (as well as messages, progress, etc.) back to the JavaFX Application Thread. That thread specifically, not any other thread. But you must not block the FX thread. That means observing the task for completion, not waiting for it to complete. Then when it does complete, you react by doing what needs doing.
But how to get the value from a completed Task? You query its value property, which will be set to whatever is returned by the #call() method if and when the task succeeds. You can directly observe this property with a listener, if you want. Personally, I prefer using the onSucceeded and onFailed properties. For example:
Task<SomeObject> task = ...;
task.setOnSucceeded(e -> {
SomeObject result = task.getValue();
// do something with 'result'
});
task.setOnFailed(e -> {
task.getException().printStackTrace(); // or log it with a proper logging framework
// notify user of failure
});
executor.execute(task);
Note properties of Task like message, progress, value and so on are guaranteed to only be set by the FX thread. And the onXXX handlers are also guaranteed to be invoked only by the FX thread.
See Concurrency in JavaFX and javafx.concurrent documentation for more information.

Catching Message Handling Exceptions with the #Exceptionhandler

I have two application e.g) A, B
A has a Saga
B is just web application
A sent Command messages to B and
B sent exception for that Command to A's Saga and A's Saga received well
and B have a #ExceptionHandler which I hope to be invoked but it's not working
How can I make them be invoked?
EDIT
this is A application's Saga that sends command messages to B application
and deals with exception which B sent
#Saga
public class OrderSaga {
#Autowired
private transient CommandGateway commandGateway;
#StartSaga
#SagaEventHandler(associationProperty = "orderId")
public void handle(CreateOrderEvent evt) {
String paymentId = UUID.randomUUID().toString();
SagaLifecycle.associateWith("paymentId", paymentId);
commandGateway.send(new CreatedPaymentCommand(paymentId, evt.getUserId(),evt.getFoodPrice())).exceptionally(exp -> {
System.out.println("got it");
System.out.println(exp.getMessage());
return null;
});
}
}
this is B application that throws exception for test
#Aggregate
#NoArgsConstructor
public class PaymentAggregate {
#AggregateIdentifier
private String paymentId;
private String userId;
private PaymentStatus status;
#CommandHandler
public PaymentAggregate(CreatedPaymentCommand cmd) {
throw new IllegalStateException("this exception was came from payment aggregates");
// AggregateLifecycle.apply(new CreatedPaymentEvent(cmd.getPaymentId(),
// cmd.getUserId(),cmd.getMoney()));
}
#ExceptionHandler(resultType = IllegalStateException.class)
public void error(IllegalStateException exp) {
System.out.println(exp.getMessage());
}
// I want this #ExceptionHandler to be invoked
#EventSourcingHandler
public void on(CreatedPaymentEvent evt) {
this.paymentId = evt.getPaymentId();
this.userId = evt.getUserId();
}
}
A application catch exception well like below
2021-08-24 11:46:43.534 WARN 14244 --- [ault-executor-2] o.a.c.gateway.DefaultCommandGateway : Command 'com.common.cmd.CreatedPaymentCommand' resulted in org.axonframework.commandhandling.CommandExecutionException(this exception was came from payment aggregates)
got it
this exception was came from payment aggregates
but B is not I thought that B's #ExceptionHandler will catch that exception
in short, How can I make B's #ExceptionHandler to be invoked
It doesn't work right now because the exception is thrown from the constructor of your aggregate.
As you are using a constructor command handler, there is no instance present yet.
And without an instance, Axon Framework cannot spot the #ExceptionHandler annotated method you've set up.
This is the only missing point for the exception handlers at this stage. Honestly, the reference guide should be a bit more specific about this. I am sure this will change in the future, though.
There's a different approach for having a command handler that constructs the aggregate and that can use the #ExceptionHandler: with the #CreationPolicy annotation. The reference guide has this to say about it, by the way.
Thus, instead of having a constructor command handler, you would set up a regular command handler using the AggregateCreationPolicy.ALWAYS.
That would adjust your sample like so:
#Aggregate
#NoArgsConstructor
public class PaymentAggregate {
#AggregateIdentifier
private String paymentId;
private String userId;
private PaymentStatus status;
#CommandHandler
#CreationPolicy(AggregateCreationPolicy.ALWAYS)
public void handle(CreatedPaymentCommand cmd) {
throw new IllegalStateException("this exception was came from payment aggregates");
// AggregateLifecycle.apply(new CreatedPaymentEvent(cmd.getPaymentId(),
// cmd.getUserId(),cmd.getMoney()));
}
#ExceptionHandler(resultType = IllegalStateException.class)
public void error(IllegalStateException exp) {
System.out.println(exp.getMessage());
}
// I want this #ExceptionHandler to be invoked
#EventSourcingHandler
public void on(CreatedPaymentEvent evt) {
this.paymentId = evt.getPaymentId();
this.userId = evt.getUserId();
}
}
Please give this a try in your application, #YongD.

JavaFX - Call "updateMessage" for TextArea from background Task - Two problems found

I am having two problems when trying to use "updateMessage" in a JavaFX task.
Issue #1
seems to be a known behavior, but I am not yet sure how exactly I can workaround it.This one is not (yet) critical to me.
The problem is that not all the updates I am performing in a background Task are displayed in the UI (at least the UI does not hang/freezes anymore, which was my initial issue).
My Code of the UI part:
TextArea console = new TextArea();
Button button01 = new Button("Start");
button01.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
if (ms.getState() == State.READY) {
ms.messageProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
console.appendText(newValue+"\n");
}
});
ms.start();
}
}
});
My Service:
public class MyService extends Service<Object> {
#Override
protected Task createTask() {
//here we use "MyTask" first to show problem #1
MyTask ct = new MyTask();
//here we use "MyTask2" first to show problem #2
// MyTask2 ct = new MyTask2();
try {
ct.call();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("MyService end");
return ct;
}
}
My Task (#1)
public class MyTask extends Task<Object> {
#Override
public EventHandler<WorkerStateEvent> call() {
System.out.println("call() is called");
if (Thread.currentThread().getName().equals("JavaFX Application Thread")){//yes, this might not be right, but if I do not do this, my stuff is executed twice because "call()" is called twice, but the textarea area is just updated in the second run (the non javafx application thread).
return null;
} else{
//actually here I want to do some 'heavy' stuff in the background
//and many things of this heavy stuff should be displayed / logged within the UI
//but very likely (hopefully) new messages (updateMessage) will not be send as fast as in the following loop
for (int i=0;i<10000000;i++){
updateMessage("This is update number'"+i+"' from the background thread");
}
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//here is the chance to get back to the view
}finally{
}
}
});
return null;
}
}
This basically works, but not every single loop is displayed in the UI.
How do I (correctly) make sure every loop is displayed?
Screenshot: Messages are displayed but not for every loop
Issue #2
Currently blocks my attempt to bring my little text-based game into a JavaFX application.
The main problem is that I am able to call "updateMessage" from the Task directly (see above), but not from a another (sub-)class which I would need to bring all message updates from my game (each message describes the progress of the game) to the UI.
The Task I use (Task #2):
public class MyTask2 extends Task<Object> {
#Override
public EventHandler<WorkerStateEvent> call() {
// ...
UITools myTools = new UITools();
myTools.logToUITest("Just one simple message");
// ...
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//here is the chance to get back to the view
}finally{
}
}
});
return null;
}
and the (sub-)class that I want to use to do the updateMessage (actually in my little game there would be even more classes that are called during the game and almost all of them trigger an update/message).
public class UITools {
public void logToUITest(String message){
updateMessage(message);
//how to allow 'updateMessage' from the Task to be executed from here?
}
This already results in "The method updateMessage(String) is undefined...".
How could I make it possible to call the updateMessage outside of the Task itself?
updateMessage() can only be called from within the call() method of a Task. It's a constraint imposed by the design of the Task class.
The missed message updates are due to the fact that there are too many updates and not all of them are forwarded to the event queue. Try to reduce the number of updates or sleep for a little while to separate them out in time

WF 4 OnUnhandledException not hit

I've created a custom activity which contains as a Body another Activity.
[Browsable(false)]
public Activity Body { get; set; }
protected override void Execute(NativeActivityContext context)
{
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
}
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
throw new Exception(propagatedException.Message);
}
When an exception is thrown during the execution of the Body, ma handler for the OnFaulted is hit.
My execution starts with a call to static method Run of the WorkflowApplication class. My WorkflowApplication instance has a handler associated for the OnUnhandledException event.
instance.OnUnhandledException +=
delegate(WorkflowApplicationUnhandledExceptionEventArgs args)
{
Console.WriteLine(args.ExceptionSource);
waitEvent.Set();
return UnhandledExceptionAction.Cancel;
};
But regardless of what happens when the Activity hosted in the Body is executed, i never reach the handler defined above. I thought that if i throw an exception from the OnFaulted, i will be able to redirect the flow to the OnUnhandledException but i was wrong. Any ideas ?
I need this in order to centralize my errors, check them and display messages accordingly. Also i need a way to stop the execution and so on and i don't want to define handlers all over the application. Is there any way to accomplish this ?
As Will suggested, i will post what i did to handle my scenario.
Basically, in my custom activity i have hosted an Assign :
[Browsable(false)]
public Activity Body { get; set; }
Activity System.Activities.Presentation.IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
return new Assignment()
{
Body = new Assign() { DisplayName = "" }
};
}
I've added this code to my Execute method :
ActivityInstance res = context.ScheduleActivity(Body, new CompletionCallback(OnExecuteComplete), OnFaulted);
I was trying to run this Assignment by giving an array a negative value as index and and an exception was thrown. This, somehow ended my execution but no handler for the events of my WorkflowApplication instance were hit.
Here is the method given as a callback when executing the body ( in our case the Assign activity ) :
private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
{
faultContext.HandleFault();
CommunicationExtension ce = faultContext.GetExtension<CommunicationExtension>();
ITextExpression toTextExpression = (propagatedFrom.Activity as Assign).To.Expression as ITextExpression;
string valueTextExpression = string.Empty;
if ((propagatedFrom.Activity as Assign).Value != null)
{
if ((propagatedFrom.Activity as Assign).Value.Expression != null)
valueTextExpression = (propagatedFrom.Activity as Assign).Value.Expression.ToString();
}
if (ce != null)
{
ce.AddData(string.Format("{0} found on Assignment definition [{1} = {2}]", propagatedException.Message, toTextExpression.ExpressionText, valueTextExpression));
}
}
The trick was to call :
faultContext.HandleFault();
and use CommunicationExtension to allow me to to display the erros in the GUI.
The code for this class is trivial :
public class CommunicationExtension
{
public List<string> Messages { get; set; }
public CommunicationExtension()
{
Messages = new List<string>();
}
public void AddData(string message)
{
if (string.IsNullOrEmpty(message))
return;
Messages.Add(message);
}
}
Use this to add the extension:
CommunicationExtension ce = new CommunicationExtension();
instance.Extensions.Add(ce);
where instance is my WorkflowApplication instance.
I understood that for each instance of the workflow application we have one instance of its extension class. So i can send messages like this from all my custom activities in order to display their status.
I hope this scenario can help other people too.

commit fragment from onLoadFinished within activity

I have an activity which loads a data list from the server using loader callbacks. I have to list out the data into a fragment which extends
SherlockListFragment
i tried to commit the fragment using
Fragment newFragment = CategoryFragment.newInstance(mStackLevel,categoryList);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.simple_fragment, newFragment).commit();
in onLoadFinished and it gives an IllegalStateException saying
java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished
I have referred the example in actionbar sherlock, but those examples have loaders within the fragments and not the activity.
Can anybody help me with this o that I can fix it without calling the loader from the fragment!
Atlast, I have found a solution to this problem. Create a handle setting an empty message and call that handler onLoadFinished(). The code is similar to this.
#Override
public void onLoadFinished(Loader<List<Station>> arg0, List<Station> arg1) {
// do other actions
handler.sendEmptyMessage(2);
}
In the handler,
private Handler handler = new Handler() { // handler for commiting fragment after data is loaded
#Override
public void handleMessage(Message msg) {
if(msg.what == 2) {
Log.d(TAG, "onload finished : handler called. setting the fragment.");
// commit the fragment
}
}
};
The number of fragments depend on the requirement.
This method can be mainly used in case of stackFragments, where all fragments have different related functions.
As per the Android docs on the onLoadFinished() method:
Note that normally an application is not allowed to commit fragment transactions while in this call, since it can happen after an activity's state is saved. See FragmentManager.openTransaction() for further discussion on this.
https://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished(android.content.Loader, D)
(Note: copy/paste that link into your browser... StackOverflow is not handling it well..)
So you simply should never load a fragment in that state. If you really don't want to put the Loader in the Fragment, then you need to initialize the fragment in your onCreate() method of the Activity, and then when onLoadFinished occurs, simply call a method on your fragment.
Some rough pseudo code follows:
public class DummyFragment {
public void setData(Object someObject) {
//do stuff
}
public class DummyActivity extends LoaderCallbacks<Object> {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fragment newFragment = DummyFragment.newInstance();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.simple_fragment, newFragment).commit();
getSupportLoaderManager.initLoader(0, null, this)
}
// put your other LoaderCallbacks here... onCreateLoader() and onLoaderReset()
public void onLoadFinished(Loader<Object> loader, Object result) {
Fragment f = getSupportLoaderManager.findFragmentById(R.id.simple_fragment);
f.setData(result);
}
Obviously, you'd want to use the right object.. and the right loader, and probably define a useful setData() method to update your fragment. But hopefully this will point you in the right direction.
As #kwazi answered this is a bad user experience to call FragmentTransition.commit() from onLoadFinished(). I have found a solution for this event by using ProgressDialog.
First created ProgressDialog.setOnDismissListener(new listener) for watching the onLoadFinished().
Further i do progressDialog.show() before getLoaderManager().restartLoader().
And eventually place progressDialog.dismiss() in onLoadFinished().
Such approach allow do not bind main UI thread and Loader's thread.
public class FrPersonsListAnswer extends Fragment
implements
LoaderCallbacks<Cursor>{
private ProgressDialog progressDialog;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_persons_list, container, false);
//prepare progress Dialog
progressDialog = new ProgressDialog(curActivity);
progressDialog.setMessage("Wait...");
progressDialog.setIndeterminate(true);
progressDialog.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
//make FragmentTransaction.commit() here;
//but it's recommended to pass control to your Activity
//via an Interface and manage fragments there.
}
});
lv = (ListView) view.findViewById(R.id.lv_out1);
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view,
final int position, long id) {
//START PROGRESS DIALOG HERE
progressDialog.show();
Cursor c = (Cursor) parent.getAdapter().getItem(position);
// create Loader
getLoaderManager().restartLoader(1, null, curFragment);
}
});
return view;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case 1:
//dismiss dialog and call progressDialog.onDismiss() listener
progressDialog.dismiss();
break;
default:
break;
}
}

Resources