I am trying to notify the main thread that all Callables executed by a Executor Service have completed.
At the moment I got a splash screen activity showing just an animated image. In the method OnCreate of this activity I load the application data in multithreading. Now I want to execute the goToMainMenu() method without locking the UI Thread.
With the following code as expected the method task.get() stop the UI Thread.
I could accomplish what I want with an Async Task by calling ((ApplicationClass) getApplication()).getApplicationData().LoadApplicationData();
on the doInBackground() method, however mixing up threads inside a Async thread doesn't sound the correct practice for this.
My Application Class:
public class ApplicationClass extends Application {
private ApplicationData applicationData;
public ApplicationData getApplicationData()
{
return applicationData;
}
#Override
public void onCreate()
{
super.onCreate();
applicationData = new ApplicationData(this);
}
}
My Activity:
public class SplashScreenActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((ApplicationClass) getApplication()).getApplicationData().LoadApplicationData();
goToMainMenu();
}
private void goToMainMenu() {
Intent content = new Intent(SplashScreenActivity.this, ContentActivity.class);
content.putExtra("menu", getString(R.string.nav_title_news));
startActivity(content);
finish();
}
}
My ApplicationData Class:
public final class ApplicationData {
Context c;
//There are more Variables to store work by Callables methods
public ApplicationData(Context context) {
this.c = context;
}
public void LoadApplicationData() throws Exception {
int PROCESSES = 6;
ExecutorService executor = Executors.newFixedThreadPool(PROCESSES);
List<Callable<Void>> callables = Arrays.asList(
new Callable<Void>() {
#Override
public Void call() throws Exception {
LoadEventsLocations(c.getResources().getString(R.string.webserviceeventslocations));
return null;
}
}, new Callable<Void>() {
#Override
public Void call() throws Exception {
LoadTags(c.getResources().getString(R.string.webservicetags));
return null;
}
}, new Callable<Void>() {
#Override
public Void call() throws Exception {
homehtml = LoadHtml(c.getResources().getString(R.string.urlhome), c.getResources().getString(R.string.classarticletext), "home");
return null;
}
}, new Callable<Void>() {
#Override
public Void call() throws Exception {
objhtml = LoadHtml(c.getResources().getString(R.string.urlobjectives), c.getResources().getString(R.string.classarticletext), "obj");
return null;
}
}, new Callable<Void>() {
#Override
public Void call() throws Exception {
contactshtml = LoadHtml(c.getResources().getString(R.string.urlcontacts), c.getResources().getString(R.string.classcontacts), "contacts");
return null;
}
}, new Callable<Void>() {
#Override
public Void call() throws Exception {
commissionhtml = LoadHtml(c.getResources().getString(R.string.urlcommission), c.getResources().getString(R.string.classarticletext), "commission");
return null;
}
});
for (Future<Void> task : executor.invokeAll(callables))
task.get();
executor.shutdown();
}
//There are more methods but keep it simple :)
}
What you guys advise me to do?
Related
I have the following AsyncTask class which I want to handle multiple api calls and return a List back to my activity. I am having a problems trying to make this work.
How can I return an object back to my activity when onPostExecute() method does not return anything?
public class NetworkCall extends AsyncTask<Call, Void, List<Student>> {
#Override
protected List<Students> doInBackground(Call... calls) {
try {
Call<Students> call = calls[0];
Response<Students> response = call.execute();
return response.body().getStudents();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(List<Students> students) {
}
}
One of the options is to create interface and use as callback.
In async task class :
public class NetworkCall extends AsyncTask<Call, Void, List<Student>> {
public interface NetworkCallback{
void onResponse(List<Students> students);
}
private NetworkCallback callback;
public void setCallback(NetworkCallback callback){
this.callback = callback;
}
#Override
protected List<Students> doInBackground(Call... calls) {
try {
Call<Students> call = calls[0];
Response<Students> response = call.execute();
return response.body().getStudents();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(List<Students> students) {
callback.onResponse(students)
}
}
and now in your activity implement the interface and provide to the async task via setter.
public class StudentsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//.... you setup for activity
NetworkCall networkCall = new NetworkCall();
networkCall.setCallback(new NetworkCall.NetworkCallback() {
#Override
public void onResponse(List<Students> students) {
//update your UI here
}
});
}
}
Based on the Docs onPostExecute runs on the main UI thread so no need to the runOnUiThread and Runnable
you can implement like this:
Your interface:
public interface OnTaskCompleted{
void onTaskCompleted(Object o);
}
Your Activity:
public class YourActivity implements OnTaskCompleted{
// your Activity
#Override
void onTaskCompleted(Object o){
}
And your AsyncTask:
public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object
to required type
private OnTaskCompleted listener;
public YourTask(OnTaskCompleted listener){
this.listener=listener;
}
// required methods
protected void onPostExecute(Object o){
// your stuff
listener.onTaskCompleted(o);
}
}
I have a method:
/**
* Call event without a value
*/
#MainThread
public void call() {
setValue(null);
}
And I call it here:
new Thread(new Runnable() {
#Override
public void run() {
stopNavigation.call();
}
}).start();
Why is no error thrown because I am making this call from outside of the main thread? I have read everything I can about the #MainThread annotation (from android.support.annotation) but nothing has informed me on what the annotation actually does.
As far as I know, AndroidStudio only show the warning about thread when we specific all thread like
Here is an example in Activity to make annotations work
public class AActivity extends Activity {
#MainThread
protected void onCreate(Bundle savedInstanceState) {
...
getData();
}
#AnyThread
private void getData() {
new Thread(new Runnable() {
#WorkerThread // MUST DEFINE THREAD HERE
#Override
public void run() {
updateUI(); // annotation error here
}
}).start();
}
#MainThread
void updateUI() {
}
class A extends AsyncTask<Void, Void, Void> {
#WorkerThread // MUST DEFINE THREAD HERE
#Override
protected Void doInBackground(Void... voids) {
updateUI(); // annotation error here
return null;
}
}
}
I have an async Retrofit-based API call in Android and need to wait with the DB calls until the API call finishes, so that I am sure the proper data gets entered into the DB.
I read that you can use Futures to accomplish this task, however with my current implementation I get a null pointer exception.
Below is the API method:
public Future<Void> postPrintMode(String authorization, final int userid, String deviceuid, final Map payload){
api.postPrintMode(authorization, userid, deviceuid, payload, new Callback<PrintMode>() {
#Override
public void success(PrintMode printMode, Response response) {
if (printMode.get_id() != 0) {
dbOps.writePrintMode(userid, printMode);
bus.getBus().post(new EVTNewPrintMode(printMode));
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
APIUtils.showAPIResponseBody(retrofitError);
}
});
return null;
}
And here the block where I want to ensure that the async code is executed BEFORE I continue to read the DB results.
Future<Void> f = APIExec.getInstance().postPrintMode(IConstants.authorization, IConstants.userId, IConstants.deviceUid, payload);
// here I get the null pointer exception
f.get();
// the code below needs to be executed after the postPrintMode(...) async method;
DBPrintMode printMode = APIDBOps.getInstance().readPrintModeByPrintModeID(6);
assertNotNull("Print Mode does not exist", printMode);
You can make your class that calls public Future<Void> postPrintMode method implement the new Callback<PrintMode> interface. After, you can your postPrintMode from it and pass a reference to itself into the method.
Here is a rough example (code not tested)
class Foo implements Callback<PrintMode> {
Future<Void> f;
public Foo(){
f = APIExec.getInstance().postPrintMode(IConstants.authorization, IConstants.userId, IConstants.deviceUid, this);
}
#Override
public void success(PrintMode printMode, Response response) {
if (printMode.get_id() != 0) {
dbOps.writePrintMode(userid, printMode);
bus.getBus().post(new EVTNewPrintMode(printMode));
}
if (f != null){
f.get();
// the code below needs to be executed after the postPrintMode(...) async method;
DBPrintMode printMode = APIDBOps.getInstance().readPrintModeByPrintModeID(6);
assertNotNull("Print Mode does not exist", printMode);
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
APIUtils.showAPIResponseBody(retrofitError);
}
}
Create a AsyncTaskThread class as below,
public class AsyncTaskThread extends AsyncTask<Void, Void, Void> {
Context context;
Handler myHandler;
public AsyncTaskThread( Context activityContext, Handler handler ) {
this.context = activityContext;
this.myHandler = handler;
}
#Override
protected void onPreExecute() {
// before starting thread you can pre process few things here if needed
}
#Override
protected Void doInBackground(Void... params) {
// do whatever you want to do here like calling your API and return your result
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// after doIn Background this method is called which will set the meesage object and give it back to handler
Message message = new Message();
message.obj = result;
myHandler.sendMessage(message);
}
}
call this async class as,
new AsyncTaskThread(this, new MyHandler()).execute();
and You will have to put this handler class inside the class you are putting above line, depending upon the result you get in handle you can perform further operations,
private class MyHandler extends Handler {
#Override
public void handleMessage(Message msg) {
}
}
I have an issue with runOnuiThread and AsyncTask getting called together.
My AsynchTask gets data to populate a listView through runOnUIThread call.
This Asych Task can get data even when UI is not in focus . It starts from a UI screen and runs until application is logged out.
Now data coming from this Task can populate only a particular listview.
Now if i invoke another Asynch Task from another view using call executeOnExecutor call for AsynchTask, the Asynch Task does not run to compeltion. It locks up.
If I comment out code for the never ending AsychTask called Receiver.. then all UI's listview get populated and no Asych Task locks.
This Receiver waits on a REST API call for response to return but since I am running through executeonExecutor call, it should be parallel processing.
I need to have the receiver running all the time as that is an integral of my application.
What strategy can I use here to fix this issue.
Here are my code snippets.
public class Receiver {
private final static String QUEUE_NAME = "hello";
private String m_ErrorMessage;
private IRunOnUIThreadCallback iRunOnUIThreadCallback;
private Send m_Received;
private int m_TimeoutDuration;//how long the reading of new message waits in milli seconds
public void SetCallback(IRunOnUIThreadCallback runOnUIThreadCallback)
{
iRunOnUIThreadCallback = runOnUIThreadCallback;
}
public void SetTimeoutDuration(int timeout)
{
m_TimeoutDuration = timeout;
}
public void StartReceiver(Send receiverInfo)
{
String receivedInfo = null;
try {
new ReceiveInfo ().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, receiverInfo);
}
catch(Exception exp)
{
m_ErrorMessage = exp.getMessage();
}
}
private class ReceiveInfo extends AsyncTask<Send, Void, Send>
{
//initiate vars
public receive() {
super();
//my params here
}
protected Message doInBackground(Send... receiverInfo)
{
Send recv=null;
try {
PreferenceSingleton single = PreferenceSingleton.getInstance();
final User user = single.getUser();
final SvcApi svc = LoginAuthSvc.init();
Send send=(Send)receiverInfo[0];
send.setUserId(user.getUsername());
//dxbrem
while (true) {
recv=svc.receive(send);
String str= recv.get();
if ((str == null || (str.trim().length() == 0))) {
continue;
}
//DJ uncomment
iRunOnUIThreadCallback.RunAfterIsReceived(recv);
//messages.add(message);
System.out.println(" [x] Received '" + recv + "'");
}
}catch(Exception exp)
{
m_ErrorMessage = exp.getMessage();
}
return recv;
}
}
public String getErrorMessage() {
return m_ErrorMessage;
}
}
public interface IRunOnUIThreadCallback {
public void RunAfterIsReceived(ByteSent m);
public void RunAfterIsReceived(Send m);
}
The class that handles this.. has the following code and
public class MainFragment extends Fragment implements MFragment.OnFragmentInteractionListener, IRunOnUIThreadCallback {
private Receiver mReceiver;
public void SetUICallbackOnMessageReceiver()
{
mReceiver.SetCallback(this);
}
private void callRunUIThread(final SentInfo m) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
if (m!= null) {
mGridArray.add(message);
if (mListAdapter != null) {
mListAdapter.notifyDataSetChanged();
mListView.setSelection(mListAdapter.getCount());
mListView.smoothScrollToPosition(mListAdapter.getCount());
}
}
}
}); // end of runOnUiThread
}
#Override
public void RunAfterIsReceived(ByteSent m) {
}
#Override
public void RunAfterIsReceived(Sent m) {
SentInfo m= new SentInfo(false, recv.getInfo());
callRunUIThread(msg);
}
mListAdapter is the ListAdapater
mListView is the ListView
Here is the AsynchTask code
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
public class CallableTask<T> extends AsyncTask<Void,Double,T> {
private static final String TAG = CallableTask.class.getName();
public static <V> void invoke(Callable<V> call,Activity activity, TaskCallback<V> callback){
new CallableTask<V>(activity,call, callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
private Callable<T> callable_;
private AsyncTask<Void, Void, String> asyncTask_;
private Context context;
private Activity activity;
private Fragment fragmentActivity;
private android.support.v4.app.Fragment dynamicFragment;
private TaskCallback<T> callback_;
private Exception error_;
public CallableTask(Fragment actvy,Callable<T> callable, TaskCallback<T> callback) {
callable_ = callable;
callback_ = callback;
fragmentActivity=actvy;
}
public CallableTask(Activity actvy,Callable<T> callable, TaskCallback<T> callback) {
callable_ = callable;
callback_ = callback;
activity=actvy;
}
#Override
protected T doInBackground(Void... ts) {
T result = null;
try{
result = callable_.call();
} catch (Exception e){
Log.e(TAG, "Error invoking callable in AsyncTask callable: " + callable_, e);
error_ = e;
}
return result;
}
#Override
protected void onPostExecute(T r) {
if(error_ != null){
callback_.error(error_);
}
else {
callback_.success(r,activity);
}
}
public static <V> void invoke(Callable<V> call, Fragment _frg, TaskCallback<V> callback) {
new CallableTask<V>(_frg,call, callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
// public CallableTask(android.support.v4.app.Fragment chatActivity,Callable<T> callable, TaskCallback<T> callback) {
// callable_ = callable;
// callback_ = callback;
// dynamicFragment=chatActivity;
// }
public CallableTask(android.support.v4.app.Fragment actvy,Callable<T> callable, TaskCallback<T> callback) {
callable_ = callable;
callback_ = callback;
dynamicFragment=actvy;
}
public static <V> void invoke(Callable<V> call, android.support.v4.app.Fragment _frg, TaskCallback<V> callback) {
new CallableTask<V>(_frg,call, callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
}
This gets called here... only when clicking on a button Send.
CallableTask.invoke(new Callable<Sent>() {
#Override
public Sent call() throws Exception {
}, this, new TaskCallback<Sent>() {
#Override
public void success(Sent result, Context context) {
mGridArray.add(result);
if (mListAdapter != null) {
mListAdapter.notifyDataSetChanged();
mListView.setSelection(mListAdapter.getCount());
mListView.smoothScrollToPosition(mListAdapter.getCount());
}
#Override
public void error(Exception e) {
}
});
Thanks
Dhiren
I finally resolved this by running a Asynch.cancel call on the thread from the activity fragment that started this thread. when I move away from activity. If I did not , it blocked any other tasks from running,
I have implemented a callback/listener in my android app as below:
public interface class OnListener() {
public void onReceive();
}
public class CLASSA {
private OnListener l = new OnListener() {
#Override
public void OnReceive() {
Log.v(TAG, "Received response");
};
CLASSB obj = new CLASSB();
obj.methodA(l);
}
public class CLASSB {
void methodA(OnListener l) {
<define a new thread t> {
loop (<some condition>) {
l.OnReceive();
}
}
t.start();
}
Now if the loop is running and CLASSA is getting continuous callbacks/responses and obj is set to null while the loop is running, I still keep getting callbacks i.e. I still see "Received response" in my logs. Why? Should I not get some exception? What's the reasoning behind this?
I made this into a runnable Java program - and yes it continues to output "Response Received" forever. The reason is the program still maintains a reference to the ThreadGroup - see this answer. Within that a reference still is maintained to the listener, because it's part of the run() method. What happens outside of the thread is irrelevant.
class CLASSB
{
public void methodA(final OnListener l)
{
new Thread(new Runnable()
{
#Override
public void run()
{
while (true)
{
l.OnReceive();
}
}
})
.start();
}
}
interface OnListener
{
public void OnReceive();
}
public class CLASSA
{
public static void main(String[] args)
{
CLASSB obj = new CLASSB();
OnListener l = new OnListener() {
#Override
public void OnReceive() {
System.out.println("Received response");
}
};
obj.methodA(l);
obj = null;
l = null;
}
}