Equivalent of iOS NSNotificationCenter in Android? - android

Is there an equivalent of the iOS class NSNotificationCenter in Android ? Are there any libraries or useful code available to me ?

In Android there is not a central notification center as in ios.
But you can basically use Observable and Observer objects to achieve your task.
You can define a class like something below, just modify it for singleton use and add synchronized for concurrent use but the idea is the same:
public class ObservingService {
HashMap<String, Observable> observables;
public ObservingService() {
observables = new HashMap<String, Observable>();
}
public void addObserver(String notification, Observer observer) {
Observable observable = observables.get(notification);
if (observable==null) {
observable = new Observable();
observables.put(notification, observable);
}
observable.addObserver(observer);
}
public void removeObserver(String notification, Observer observer) {
Observable observable = observables.get(notification);
if (observable!=null) {
observable.deleteObserver(observer);
}
}
public void postNotification(String notification, Object object) {
Observable observable = observables.get(notification);
if (observable!=null) {
observable.setChanged();
observable.notifyObservers(object);
}
}
}

Take a look at the Otto event bus from Square:
http://square.github.com/otto/
It has essentially the same features as NSNotificationCenter but thanks to annotations and static typing it is easier to follow the dependencies of components and paths that events follow. It's much simpler to use than the stock Android broadcast API, IMO.

i had the same wondrings.. so i wrote this:
public class NotificationCenter {
//static reference for singleton
private static NotificationCenter _instance;
private HashMap<String, ArrayList<Runnable>> registredObjects;
//default c'tor for singleton
private NotificationCenter(){
registredObjects = new HashMap<String, ArrayList<Runnable>>();
}
//returning the reference
public static synchronized NotificationCenter defaultCenter(){
if(_instance == null)
_instance = new NotificationCenter();
return _instance;
}
public synchronized void addFucntionForNotification(String notificationName, Runnable r){
ArrayList<Runnable> list = registredObjects.get(notificationName);
if(list == null) {
list = new ArrayList<Runnable>();
registredObjects.put(notificationName, list);
}
list.add(r);
}
public synchronized void removeFucntionForNotification(String notificationName, Runnable r){
ArrayList<Runnable> list = registredObjects.get(notificationName);
if(list != null) {
list.remove(r);
}
}
public synchronized void postNotification(String notificationName){
ArrayList<Runnable> list = registredObjects.get(notificationName);
if(list != null) {
for(Runnable r: list)
r.run();
}
}
}
and a usage for this will be:
NotificationCenter.defaultCenter().addFucntionForNotification("buttonClick", new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "Hello There", Toast.LENGTH_LONG).show();
}
});
tried to make the interface as similar to IOS as possible, but simpler (no object registration needed).
hope that helps:)

If you don't want to use Observer - it can be problematic in cases you want a Fragment to be your Observer cause you can't extend more then one class-
You can use google's Guava Library (https://code.google.com/p/guava-libraries/)
for "Function" and "Multimap" - although you can use as well HashMap> for the subscibersCollection
and implement something like this:
import java.util.Collection;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.base.Function;
public class EventService {
ArrayListMultimap<String, Function<Object, Void>> subscibersCollection;
private static EventService instance = null;
private static final Object locker = new Object();
private EventService() {
subscibersCollection = ArrayListMultimap.create();
}
public static EventService getInstance() {
if (instance == null) {
synchronized (locker) {
if (instance == null) {
instance = new EventService();
}
}
}
return instance;
}
/**
* Subscribe to the notification, and provide the callback functions in case
* notification is raised.
*
* #param notification
* - notification name
* #param func
* - function to apply when notification is raised
*/
public void addSubscription(String notification, Function<Object, Void> func) {
synchronized (subscibersCollection) {
if (!subscibersCollection.containsEntry(notification, func)) {
subscibersCollection.put(notification, func);
}
}
}
/**
* Remove subscription from notification
*/
public void removeSubscription(String notification,
Function<Object, Void> func) {
synchronized (subscibersCollection) {
subscibersCollection.remove(notification, func);
}
}
/**
* raise notification for all its subscribers
*
* #param notification
* - notification name
* #param data
* - update data
*/
public void publish(String notification, Object data) {
Collection<Function<Object, Void>> observableList = subscibersCollection
.get(notification);
for (Function<Object, Void> func : observableList) {
func.apply(data);
}
}
}

On the basis of Behlül answer, I change the code to make it closer to iOS NSNotificationCenter.
Another thing: the notifications will fire on the main thread
package com.oxygen.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.os.Handler;
public class NotificationCenter {
//---------------- event type list ---------------------
public static enum NotificationID{
IMAGES_CACHE_READY
}
//---------------- singelton ---------------------------
private static NotificationCenter instance = null;
private NotificationCenter() { observables = new HashMap<NotificationID, MyObservable>(); }
public static synchronized NotificationCenter singelton() {
if (instance == null) {
instance = new NotificationCenter ();
}
return instance;
}
//-------------------------------------------
public class Notification {
private Object poster; // the object that post the event
private Object info; // event specific data
private NotificationID id; // event name
public Notification(Object poster, NotificationID id, Object info) {
super();
this.poster = poster;
this.info = info;
this.id = id;
}
public Object getPoster() {
return poster;
}
public Object getInfo() {
return info;
}
public NotificationID getId() {
return id;
}
}
//-------------------------------------------
public interface Notifiable {
public void onNotification(Notification notify);
}
//-------------------------------------------
protected class MyObservable {
List<Notifiable> observers = new ArrayList<Notifiable>();
public MyObservable() {
}
public void addObserver(Notifiable observer) {
if (observer == null) {
throw new NullPointerException("observer == null");
}
synchronized (this) {
if (!observers.contains(observer))
observers.add(observer);
}
}
public int countObservers() {
return observers.size();
}
public synchronized void deleteObserver(Notifiable observer) {
observers.remove(observer);
}
public synchronized void deleteObservers() {
observers.clear();
}
public void notifyObservers(Notification notify) {
int size = 0;
Notifiable[] arrays = null;
synchronized (this) {
size = observers.size();
arrays = new Notifiable[size];
observers.toArray(arrays);
}
if (arrays != null) {
for (Notifiable observer : arrays) {
observer.onNotification(notify);
}
}
}
}
//-------------------------------------------
HashMap<NotificationID, MyObservable > observables;
public void addObserver(NotificationID id, Notifiable observer) {
MyObservable observable = observables.get(id);
if (observable==null) {
observable = new MyObservable ();
observables.put(id, observable);
}
observable.addObserver(observer);
}
public void removeObserver(NotificationID id, Notifiable observer) {
MyObservable observable = observables.get(id);
if (observable!=null) {
observable.deleteObserver(observer);
}
}
public void removeObserver(Notifiable observer) {
for (MyObservable observable : observables.values()) {
if (observable!=null) {
observable.deleteObserver(observer);
}
}
}
public void postNotification(final Object notificationPoster, final NotificationID id, final Object notificationInfo) {
final MyObservable observable = observables.get(id);
if (observable!=null) {
// notification post to the maim (UI) thread
// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(AppContext.get().getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
observable.notifyObservers(new Notification(notificationPoster, id, notificationInfo) );
}
};
mainHandler.post(myRunnable);
}
}
}
Listener sample:
public class CustomGridViewAdapter extends ArrayAdapter<Category> implements Notifiable {
int layoutResourceId;
public CustomGridViewAdapter(Context context, int layoutResourceId) {
super(context, layoutResourceId);
this.layoutResourceId = layoutResourceId;
loadCategories(false);
NotificationCenter.singelton().addObserver(NotificationID.IMAGES_CACHE_READY, this);
}
public void onDestroy() {
NotificationCenter.singelton().removeObserver(this);
}
#Override
public void onNotification(Notification notify) {
switch (notify.getId()) {
case IMAGES_CACHE_READY:
loadCategories(true);
break;
}
}
...
}

Related

LiveData query is not being run the second time I initialise it

I have a list of different mines. Each mine has a list of blocks.
I have the mines in a spinner and the blocks in a recyclerview.
I want to display the different lists of blocks whenever the user changes the mine in the mine spinner
I am using Firebase in the backend as my database.
When I change the mine in the spinner, I update the block list by creating a new MutableLiveData which I've extended in a class called FirebaseQueryLiveData
The first time that I initialise the FirebaseQueryLiveData with the quesry containing the mine name, all the events inside it fire. However, after that, I call it and nothing fires. It breaks in the constructor if I have a breakpoint there, but it never reaches the run() method, onActive() method or the onDataChanged in the ValueEventListener.
I have done some research, and I have seen suggestions to replace the LiveData with MutableLiveData. I've done this, and it doesn't seem to make a difference.
Can anyone see anything in the code which I might be missing? I'm not very familiar with the android architecture components and I got the FirebaseQueryLiveData class from another helpful website with a tutorial, so I'm battling to understand where I have gone wrong.
I have done some research, and I have seen suggestions to replace the LiveData with MutableLiveData. I've done this, and it doesn't seem to make a difference.
public class BlockListActivityViewModel extends ViewModel {
private static DatabaseReference blockOutlineRef; // = FirebaseDatabase.getInstance().getReference(FireBasePaths.BLOCKOUTLINE.getPath("Therisa"));
private static DatabaseReference mineListRef;
private FirebaseQueryLiveData blockOutlineLiveDataQuery = null;
private LiveData<BlockOutlineList> blockOutlineLiveData = null;
private MediatorLiveData<String> selectedBlockNameMutableLiveData;
private MediatorLiveData<ArrayList<String>> mineListMutableLiveData;
public BlockListActivityViewModel() {
User loggedInUser = UserSingleton.getInstance();
setUpFirebasePersistance();
setupMineLiveData(loggedInUser);
// setupBlockOutlineListLiveData();
}
private void setupBlockOutlineListLiveData(String mineName) {
if (mineName != "") {
blockOutlineRef = FirebaseDatabase.getInstance().getReference(FireBasePaths.BLOCKOUTLINE.getPath(mineName));
blockOutlineLiveDataQuery = new FirebaseQueryLiveData(blockOutlineRef);
blockOutlineLiveData = Transformations.map(blockOutlineLiveDataQuery, new BlockOutlineHashMapDeserialiser());
}
}
private void setupMineLiveData(User user) {
ArrayList<String> mineNames = new ArrayList<>();
if (user != null) {
if (user.getWriteMines() != null) {
for (String mineName : user.getWriteMines().values()) {
mineNames.add(mineName);
}
}
}
setMineListMutableLiveData(mineNames);
if (mineNames.size() > 0) {
updateMineLiveData(mineNames.get(0));
}
}
public void updateMineLiveData(String mineName) {
SelectedMineSingleton.setMineName(mineName);
setupBlockOutlineListLiveData(SelectedMineSingleton.getInstance());
}
public void setUpFirebasePersistance() {
int i = 0;
// FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
private MutableLiveData<NamedBlockOutline> selectedBlockOutlineMutableLiveData;
public MutableLiveData<NamedBlockOutline> getSelectedBlockOutlineMutableLiveData() {
if (selectedBlockOutlineMutableLiveData == null) {
selectedBlockOutlineMutableLiveData = new MutableLiveData<>();
}
return selectedBlockOutlineMutableLiveData;
}
public void setSelectedBlockOutlineMutableLiveData(NamedBlockOutline namedBlockOutline) {
getSelectedBlockOutlineMutableLiveData().postValue(namedBlockOutline);
}
public MediatorLiveData<String> getSelectedBlockNameMutableLiveData() {
if (selectedBlockNameMutableLiveData == null)
selectedBlockNameMutableLiveData = new MediatorLiveData<>();
return selectedBlockNameMutableLiveData;
}
public void setSelectedBlockNameMutableLiveData(String blockName) {
selectedBlockNameMutableLiveData.postValue(blockName);
}
public MediatorLiveData<ArrayList<String>> getMineListMutableLiveData() {
if (mineListMutableLiveData == null)
mineListMutableLiveData = new MediatorLiveData<>();
return mineListMutableLiveData;
}
public void setMineListMutableLiveData(ArrayList<String> mineListString) {
getMineListMutableLiveData().postValue(mineListString);
}
private class BlockOutlineHashMapDeserialiser implements Function<DataSnapshot, BlockOutlineList>, android.arch.core.util.Function<DataSnapshot, BlockOutlineList> {
#Override
public BlockOutlineList apply(DataSnapshot dataSnapshot) {
BlockOutlineList blockOutlineList = new BlockOutlineList();
HashMap<String, NamedBlockOutline> blockOutlineStringHashMap = new HashMap<>();
for (DataSnapshot childData : dataSnapshot.getChildren()) {
NamedBlockOutline thisNamedOutline = new NamedBlockOutline();
HashMap<String, Object> blockOutlinePointHeader = (HashMap<String, Object>) childData.getValue();
HashMap<String, BlockPoint> blockOutlinePoints = (HashMap<String, BlockPoint>) blockOutlinePointHeader.get("blockOutlinePoints");
thisNamedOutline.setBlockName(childData.getKey());
thisNamedOutline.setBlockOutlinePoints(blockOutlinePoints);
blockOutlineStringHashMap.put(childData.getKey(), thisNamedOutline);
}
blockOutlineList.setBlockOutlineHashMap(blockOutlineStringHashMap);
return blockOutlineList;
}
}
#NonNull
public LiveData<BlockOutlineList> getBlockOutlineLiveData() {
return blockOutlineLiveData;
}
}
LiveData
public class FirebaseQueryLiveData extends MutableLiveData<DataSnapshot> {
private static final String LOG_TAG = "FirebaseQueryLiveData";
private final Query query;
private final MyValueEventListener listener = new MyValueEventListener();
private boolean listenerRemovePending = false;
private final Handler handler = new Handler();
public FirebaseQueryLiveData(Query query) {
this.query = query;
}
public FirebaseQueryLiveData(DatabaseReference ref) {
this.query = ref;
}
private final Runnable removeListener = new Runnable() {
#Override
public void run() {
query.removeEventListener(listener);
listenerRemovePending = false;
Log.d(LOG_TAG, "run");
}
};
#Override
protected void onActive() {
super.onActive();
if (listenerRemovePending) {
handler.removeCallbacks(removeListener);
Log.d(LOG_TAG, "listenerRemovePending");
}
else {
query.addValueEventListener(listener);
Log.d(LOG_TAG, "addValueEventListener");
}
listenerRemovePending = false;
Log.d(LOG_TAG, "listenerRemovePending");
}
#Override
protected void onInactive() {
super.onInactive();
// Listener removal is schedule on a two second delay
handler.postDelayed(removeListener, 4000);
listenerRemovePending = true;
Log.d(LOG_TAG, "listenerRemovePending");
}
private class MyValueEventListener implements ValueEventListener {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
setValue(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(LOG_TAG, "Can't listen to query " + query, databaseError.toException());
}
}
}

notifyPropertyChanged on MutableRealmInteger

I'm using Realm and data binding.
Before MutableRealmInteger, I used regular primitive type and used its setter, and UI changed automatically with the new value.
Now I want to use MutableRealmInteger type, but I don't know how to notify the UI of changes.
This is a part of my model:
public class MyModel extends RealmObject implements Observable {
...
public final MutableRealmInteger NewWayAAA = MutableRealmInteger.valueOf(0);
private String oldWayAAA = "0";
...
#Bindable
public String getOldWayAAA() {
return oldWayAAA.isEmpty() ? "0" : oldWayAAA;
}
public void setOldWayAAA (String param) {
if (!param.isEmpty()) {
this.oldWayAAA= param;
notifyPropertyChanged(BR.oldwayaaa);
}
}
...
/**
* Notifies listeners that all properties of this instance have changed.
*/
public synchronized void notifyChange() {
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, 0, null);
}
}
/**
* Notifies listeners that a specific property has changed. The getter for the property
* that changes should be marked with {#link Bindable} to generate a field in
* <code>BR</code> to be used as <code>fieldId</code>.
*
* #param fieldId The generated BR id for the Bindable field.
*/
public void notifyPropertyChanged(int fieldId) {
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, fieldId, null);
}
}
#Override
public void addOnPropertyChangedCallback(OnPropertyChangedCallback onPropertyChangedCallback) {
if (mCallbacks == null) {
mCallbacks = new PropertyChangeRegistry();
}
mCallbacks.add(onPropertyChangedCallback);
}
#Override
public void removeOnPropertyChangedCallback(OnPropertyChangedCallback onPropertyChangedCallback) {
if (mCallbacks != null) {
mCallbacks.remove(onPropertyChangedCallback);
}
}
MutableRealmInteger doesn't have setter and the usage of it is:
myModelIns.NewWayAAA.increment(10);
public class MyModel extends RealmObject implements Observable {
...
private final MutableRealmInteger NewWayAAA = MutableRealmInteger.valueOf(0);
...
#Bindable
public int getNewWayAAA() {
return NewWayAAA.getValue();
}
public void incrementNewWayAAA() {
NewWayAAA.increment();
notifyPropertyChanged(BR.newwayaaa);
}
...

Change Observable List to Hashmap Singleton

I have a singleton to cache objects, from here I create an observable from a List, this List is a response from the API which is filled with objects. (JSON)
private static BehaviorSubject<List<Model>> observableModelsList;
private static Observable<List<Model>> observable = myAPI.loadModelsRx();
private static Subscription subscription;
private PoiSingleton() {
}
public static PoiSingleton getInstance() {
return ourInstance;
}
public static void resetObservable() {
observablePoisList = BehaviorSubject.create();
if (subscription != null && !subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
subscription = observable.subscribe(new Subscriber<List<Model>>() {
#Override
public void onCompleted() {
// do nothing
}
#Override
public void onError(Throwable e) {
observablePoisList.onError(e);
}
#Override
public void onNext(List<Model> models) {
observablePoisList.onNext(models);
}
});
}
public static Observable<List<Poi>> getPoisObservable() {
if (observablePoisList == null) {
resetObservable();
}
return observablePoisList;
}
What I want to achieve is create a HashMap from the List, the key should be the ID of the object and the value the object itself.
I am new to Android and Retrofit/RxJava so in what method/stage is it responsible to create the HashMap?

Configuring RxJava to Send Data to activity from GCMListenerService

I am trying to send an update to my Activity from my GCMServiceListener so, I am using RxJava/RxAndroid And created a BusClass for handling sending and Observers
public class ClientBus {
//private final PublishSubject<Object> _bus = PublishSubject.create();
// If multiple threads are going to emit events to this
// then it must be made thread-safe like this instead
private final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) {
_bus.onNext(o);
}
public Observable<Object> toObserverable() {
return _bus;
}
public boolean hasObservers() {
return _bus.hasObservers();
}
}
And in my Application Class I did this to initialize the BusClass
private ClientBus clientBus;
public ClientBus getRxBusSingleton() {
if (clientBus == null) {
clientBus = new ClientBus();
}
return clientBus;
}
In the activity I want to receive the message, I registered a CompositeSubscription and get a reference to my ClientBus class from the Application Class
clientBus = ((MyApplication) getApplicationContext()).getRxBusSingleton();
#Override
protected void onStart() {
super.onStart();
initSubscriptions();
}
#Override
protected void onStop() {
super.onStop();
_subscriptions.unsubscribe();
}
void initSubscriptions() {
_subscriptions = new CompositeSubscription();
_subscriptions.add(clientBus.toObserverable().subscribe(new Action1<Object>() {
#Override
public void call(Object event) {
Log.e("New Event", "Event Received");
if (event instanceof MyGcmListenerService.Message) {
String msg = ((MyGcmListenerService.Message) event).getMessage();
if (msg.equals("Update Available")) {
scheduleArrayList = getSchedules();
scheduleAdapter = new ScheduleAdapter(getApplicationContext(), scheduleArrayList, ScheduledUberActivity.this);
scheduledList.setAdapter(scheduleAdapter);
scheduleAdapter.notifyDataSetChanged();
} else if (msg.equals("Refresh")) {
fetchTrips();
}
}
}
}));
}
And from the MyGcmListenerService class I did this when I get a new notification
private void sendRefreshNotif() {
if (clientBus.hasObservers()) {<--It enters the if cause the Log prints. But, the activity doesn't get the message
Log.e("Obervers", "Observers aren't null");
clientBus.send(new Message("Refresh"));
}
}
What I don't understand is why isn't it working here? I use it to interact between activities and fragments. I closed my application to check if the notification comes in, It'll enter this block if (clientBus.hasObservers()) { but it didn't and starting the app and testing the Observer, it notices there's an active Observer. Any help? Thanks.
It seems like you used different instances of the ClientBus class in CompositeSubscription and MyApplication.
Try to make a singleton from ClientBus class, it works fine for me.
public class ClientBus {
public ClientBus(SingletonAccessor accessor) {}
private static ClientBus instance;
private static class SingletonAccessor{}
public static ClientBus getInstance() {
if (instance == null) instance = new ClientBus(new SingletonAccessor());
return instance;
}
private final Subject<Object, Object> mBus = new SerializedSubject<>(PublishSubject.create());
public void send(Object o) {
mBus.onNext(o);
}
public Observable<Object> toObserverable() {
return mBus;
}
public boolean hasObservers() {
return mBus.hasObservers();
}
}

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,

Categories

Resources