android custom listener/callback with loop - android

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;
}
}

Related

LiveData onChanged method called only first time

i have a simple app that polls a service to display country list in a recyclerview. Here i am using LiveData to update the recyclerview whenever there is any change in the country list. Trouble is, LiveData's onChanged method is invoked only the first time setValue is called. But after that if there are any further changes to the data the onChanged is not invoked??
Following is my code for more info -
CountryListFragment
//Setup observer
Observer<List<CountryModel>> myObserver = new Observer<List<CountryModel>>() {
#Override
public void onChanged(#Nullable List<CountryModel> countryModels) {
mCountryList = countryModels;
//Update recyclerview
myAdapter.updateRecyclerView(mCountryList);
}
};
//Set Observer for Viewmodel
countryViewModel.getmCountryList().observe(this,myObserver);
CountryViewModel
public class CountryViewModel extends AndroidViewModel {
private MutableLiveData> mCountryList;
private MyRetrofitClient myRetrofitClient;
public CountryViewModel(#NonNull Application application) {
super(application);
}
public void init(){
mCountryList = new MutableLiveData<>();
myRetrofitClient = new MyRetrofitClient();
**mCountryList = myRetrofitClient.getCountryList(); //This works**
pollCountryList();
}
//Create polling request for every 10 secs
private void pollCountryList(){
final Handler mHandler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<30;i++){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Call API on main thread
mHandler.post(new Runnable() {
#Override
public void run() {
**myRetrofitClient.getCountryList(); //NOT CALLING ONCHANGED??**
}
});
}
}
}).start();
}
public MutableLiveData<List<CountryModel>> getmCountryList() {
return mCountryList;
}
MyRetrofitClient.getCountryList()
public MutableLiveData<List<CountryModel>> getCountryList(){
final MutableLiveData<List<CountryModel>> lstResult = new MutableLiveData<>();
MockServiceInterface serviceInterface = mRetrofit.create(MockServiceInterface.class);
Call<List<CountryModel>> countryList = serviceInterface.getCountryList();
countryList.enqueue(new Callback<List<CountryModel>>() {
#Override
public void onResponse(Call<List<CountryModel>> call, Response<List<CountryModel>> response) {
if (response.isSuccessful()){
List<CountryModel> lstResponse = response.body();
lstResult.setValue(lstResponse);
}else {
System.out.print(response.errorBody());
}
}
#Override
public void onFailure(Call<List<CountryModel>> call, Throwable t) {
t.printStackTrace();
}
});
return lstResult;
}
Thanks!
EDIT:
Some additional observations-
When i call setValue method of MutableLiveData instance (mCountryList) inside my CountryViewModel it invokes the onChanged method each time.
However its different in case of MyRetrofitClient. The first time setValue is called in MyRetrofitClient.getCountryList(), it invokes the onChanged method. But later it does not.
Sorry, I misunderstood question at first.
You are not receiving changes because you never called setValue on mCountryList.
Method getCountryList() is returning new object MutableLiveData<List<CountryModel>> lstResult everything it is called, to which no one is observing.
Solution:
Instead of returning MutableLiveData object with getCountryList, set mCountryList in onResponse().
Code
public void init(){
mCountryList = new MutableLiveData<>();
myRetrofitClient = new MyRetrofitClient();
myRetrofitClient.getCountryList();
pollCountryList();
}
public LiveData<List<CountryModel>> getCountryListener() {
return mCountryList;
}
public void getCountryList(){
MockServiceInterface serviceInterface = mRetrofit.create(MockServiceInterface.class);
Call<List<CountryModel>> countryList = serviceInterface.getCountryList();
countryList.enqueue(new Callback<List<CountryModel>>() {
#Override
public void onResponse(Call<List<CountryModel>> call, Response<List<CountryModel>> response) {
if (response.isSuccessful()){
List<CountryModel> lstResponse = response.body();
mCountryList.setValue(lstResponse);
}else {
System.out.print(response.errorBody());
}
}
#Override
public void onFailure(Call<List<CountryModel>> call, Throwable t) {
t.printStackTrace();
}
});
}
Use getCountryListener() to observe.
Activity:
countryViewModel.getCountryListener().observe(this,myObserver);

Android Multi-threading - How to notify main thread from Executor service

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?

How to wait until an async method finishes using Futures?

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) {
}
}

RunonUI Thread blocks a AsynTask in android from executing to completion

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,

Perform requests with Retrofit inside custom Runnable

I am migrating from Volley to a custom implementation using Retrofit, but I'm trying to add to my implementation some of the Volley features that I liked, for example
RequestQueue.cancel(String tag)
If the Request has the requested tag, then it's canceled by setting a boolean value, mCanceled, to true. The run method checks this value and returns if it's true.
To be able to reproduce this with Retrofit I should be able to use my custom class implementing Runnable instead of the default one, where I have a mTag and a mCanceled field.
Moreover, Volley was also able to set such flag inside the active Threads and immediately stop them. My cancelAll method, that I've already implemented, just drains the queue to another queue, but isn't able to access the active threads.
Is it possible to achieve the same results with Retrofit and ThreadPoolExecutor?
I think I've found a nicer solution: instead of blocking the Runnable of the requests, I am blocking the Callback execution.
I have extended the Callback interface:
public interface CustomCallbackInterface<T> extends Callback<T> {
public String getTag();
public String setTag(String tag);
public void cancel();
public boolean isCanceled();
}
so that each Callback has a tag and a cancel flag. Then the success method starts with:
public class CustomCallback<ConvertedData> implements CustomCallbackInterface<ConvertedData>{
//failure...
#Override
public void success(ConvertedData cd, Response response) {
if(isCanceled()) return;
// ....
}
}
Every time I make a new request, I store the created CustomCallback inside a List cancel just iterates the list and calls cancel() on the items with the same tag.
I've implemented an easy to use class based on Vektor88 answer
public abstract class CancelableCallback<T> implements Callback<T> {
private static List<CancelableCallback> mList = new ArrayList<>();
private boolean isCanceled = false;
private Object mTag = null;
public static void cancelAll() {
Iterator<CancelableCallback> iterator = mList.iterator();
while (iterator.hasNext()){
iterator.next().isCanceled = true;
iterator.remove();
}
}
public static void cancel(Object tag) {
if (tag != null) {
Iterator<CancelableCallback> iterator = mList.iterator();
CancelableCallback item;
while (iterator.hasNext()) {
item = iterator.next();
if (tag.equals(item.mTag)) {
item.isCanceled = true;
iterator.remove();
}
}
}
}
public CancelableCallback() {
mList.add(this);
}
public CancelableCallback(Object tag) {
mTag = tag;
mList.add(this);
}
public void cancel() {
isCanceled = true;
mList.remove(this);
}
#Override
public final void success(T t, Response response) {
if (!isCanceled)
onSuccess(t, response);
mList.remove(this);
}
#Override
public final void failure(RetrofitError error) {
if (!isCanceled)
onFailure(error);
mList.remove(this);
}
public abstract void onSuccess(T t, Response response);
public abstract void onFailure(RetrofitError error);
}
Usage example
rest.request(..., new CancelableCallback<MyResponse>(TAG) {
#Override
public void onSuccess(MyResponse myResponse, Response response) {
...
}
#Override
public void onFailure(RetrofitError error) {
...
}
});
// if u need to cancel all
CancelableCallback.cancelAll();
// or cancel by tag
CancelableCallback.cancel(TAG);

Categories

Resources