Java Observer Pattern finding sender? - java

observer.update();
Above method makes the visibility of observers "GONE", but i want to change all other observers except sender observer. How can i control this ?
My all actions are observer and register themself in their constructor like below,
public class ParentAction extends AbstractAction implements IActionObserver{
private ArrayList<IAction> lSubItems;
private View subView;
public ParentAction( String ItemText,int drawable,ArrayList<IAction> SubItems) {
super(ItemText,drawable);
lSubItems = SubItems;
ActionHolder.getInstance().registerObserver(this);
}
#Override
public void update() {
getSubView().setVisibility(View.GONE);
} ...
ActionHolder
public class ActionHolder implements IActionSubject {
private static ActionHolder uniqueActionHolder;
private ArrayList observers;
private ActionHolder() {
observers = new ArrayList();
}
public static synchronized ActionHolder getInstance() {
if (uniqueActionHolder == null) {
uniqueActionHolder = new ActionHolder();
}
return uniqueActionHolder;
}
public void registerObserver(IActionObserver o) {
observers.add(o);
}
public void removeObserver(IActionObserver o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
public void notifyObserver() {
for (int i = 0; i < observers.size(); i++) {
IActionObserver observer = (IActionObserver) observers.get(i);
observer.update();
}
}
public void actionClicked(View view) {
notifyObserver();
}
}

Is this your own implementation of the observer pattern? If so, you can modify the notify method, for instance:
public void notifyObserver(IAction sender) {
for (int i = 0; i < observers.size(); i++) {
IActionObserver observer = (IActionObserver) observers.get(i);
if (observer != sender)
observer.update();
}
}
and call this as
ActionHolder.getInstance().notifyObserver(this);
Alternatively, you could add a flag in your action class:
private bool sender = false;
set the flag before notifying:
sender = true;
ActionHolder.getInstance().notifyObserver();
and use this flag in the update:
#Override
public void update() {
if (!sender) {
getSubView().setVisibility(View.GONE);
}
sender = false;
}

You raising event in actionClicked method and then notifying all observers. Just pass a reference to your sender observer to skip its refreshing later.
If i got your code correctly, you can achieve that by controlling sender with your view
public void actionClicked(View view) {
notifyObserver(view);
}
public void notifyObserver(View view) {
for (int i = 0; i < observers.size(); i++) {
IActionObserver observer = (IActionObserver) observers.get(i);
observer.update(view);
}
}
And update method skips current view
#Override
public void update(View view) {
if (!getSubView().equals(view)) {
getSubView().setVisibility(View.GONE);
}
}

Related

How to use Saved State module for ViewModel in Background Thread

How to use Saved State module for ViewModel in Background Thread
For MutableLiveData we have the option to use setvalue and postvalue , where Postvalue can be used in background thread.
How ever How can we use BACKGROUND THREAD FOR Saved State module for ViewModel
here Is the code I am trying
public class CommonViewModel extends ViewModel {
private SavedStateHandle mState;
public CommonViewModel(SavedStateHandle savedStateHandle) {
mState = savedStateHandle;
}
private static final String NAME_KEY = "name";
private Executor mExecutor = Executors.newSingleThreadExecutor();
public LiveData<ArrayList<CommonOwn>> getCart() {
if (mState.getLiveData(NAME_KEY) == null) {
initCart();
}
return mState.getLiveData(NAME_KEY);
}
public void initCart() {
mState.set(NAME_KEY, new ArrayList<CommonOwn>());
}
public void addItemToCart(CommonOwn commonOwn) {
if (getCart().getValue() == null) {
initCart();
}
ArrayList<CommonOwn> cartItemList = new ArrayList<CommonOwn>(getCart().getValue());
if (cartItemList.contains(commonOwn)) {
int a = cartItemList.indexOf(commonOwn);
cartItemList.remove(a);
} else {
cartItemList.add(commonOwn);
}
// mState.set(NAME_KEY, cartItemList);
mExecutor.execute(new Runnable() {
#Override
public void run() {
mState.set(NAME_KEY, cartItemList);
}
});
}
}
when using background thread The following error occurs
java.lang.IllegalStateException: Cannot invoke setValue on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487)
at androidx.lifecycle.LiveData.setValue(LiveData.java:306)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at androidx.lifecycle.SavedStateHandle$SavingStateLiveData.setValue(SavedStateHandle.java:367)
at androidx.lifecycle.SavedStateHandle.set(SavedStateHandle.java:256)
at com.example.CommonViewModel$1.run(CommonViewModel.java:63)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
how can we solve this issue.
The following line can never be null:
mState.getLiveData(NAME_KEY) == null
Hope this illustrates the solution. You just rely on the MutableLiveData from SavedStateHandle:
public class CommonViewModel extends ViewModel {
private MutableLiveData<ArrayList<CommonOwn>> cart;
public CommonViewModel(SavedStateHandle savedStateHandle) {
cart = savedStateHandle.getLiveData(NAME_KEY);
}
private static final String NAME_KEY = "name";
private Executor mExecutor = Executors.newSingleThreadExecutor();
public MutableLiveData<ArrayList<CommonOwn>> getCart() {
return cart;
}
public void addItemToCart(CommonOwn commonOwn) {
ArrayList<CommonOwn> cartItemList;
if(cart.getValue() == null) {
cartItemList = new ArrayList<CommonOwn>();
} else {
cartItemList = cart.getValue();
}
if (cartItemList.contains(commonOwn)) {
int a = cartItemList.indexOf(commonOwn);
cartItemList.remove(a);
} else {
cartItemList.add(commonOwn);
}
// mState.set(NAME_KEY, cartItemList);
mExecutor.execute(new Runnable() {
#Override
public void run() {
cart.postValue(cartItemList);
}
});
}
}

Pass Activity context in onCreate method

I need to pass the activity context to my service as soon as the activity is being constructed. Here is my code:
public class myService extends Service
{
private AppCompatActivity activity;
public void setActivity(AppCompatActivity activity)
{
this.activity = activity;
}
}
public class myActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
// ... some things are being executed and myService is being bound
mService.setActivity(this);
}
}
I get NullPointerException as - I suppose - the myActivity class is still being constructed and the reference cannot be passed. How can I make Android run this method after onCreate? I found some solutions for Java involving factory pattern but I'm not sure how can I use it, if I can use it in my case at all.
Service is a Context by itself. So if you need the Context only, you can just call this in your Serviceclass.
Alternatively, you should pass the Activity to the service before starting it. Make sure you pass the Activity after calling super.onCreate(bundle);
However, you should not manipulate your Activity or it's views from a Service. A better way is notifying your Activity from your Service.
Notify activity from service
Edit: Observer pattern
Create a new class called NotificationCenter.java
public class NotificationCenter {
private static int totalEvents = 1;
public static final int updateActivity = totalEvents++;
// you can add more events
// public static final int anotherEvent = totalEvents++;
private final SparseArray<ArrayList<Object>> observers = new SparseArray<>();
private final SparseArray<ArrayList<Object>> removeAfterBroadcast = new SparseArray<>();
private final SparseArray<ArrayList<Object>> addAfterBroadcast = new SparseArray<>();
private int broadcasting = 0;
public interface NotificationCenterDelegate {
void didReceivedNotification(int id, Object... args);
}
private static volatile NotificationCenter Instance = null;
public static NotificationCenter getInstance() {
NotificationCenter localInstance = Instance;
if (localInstance == null) {
synchronized (NotificationCenter.class) {
localInstance = Instance;
if (localInstance == null) {
Instance = localInstance = new NotificationCenter();
}
}
}
return localInstance;
}
public void postNotificationName(int id, Object... args) {
broadcasting++;
ArrayList<Object> objects = observers.get(id);
if (objects != null && !objects.isEmpty()) {
for (int a = 0; a < objects.size(); a++) {
Object obj = objects.get(a);
((NotificationCenterDelegate) obj).didReceivedNotification(id, args);
}
}
broadcasting--;
if (broadcasting == 0) {
if (removeAfterBroadcast.size() != 0) {
for (int a = 0; a < removeAfterBroadcast.size(); a++) {
int key = removeAfterBroadcast.keyAt(a);
ArrayList<Object> arrayList = removeAfterBroadcast.get(key);
for (int b = 0; b < arrayList.size(); b++) {
removeObserver(arrayList.get(b), key);
}
}
removeAfterBroadcast.clear();
}
if (addAfterBroadcast.size() != 0) {
for (int a = 0; a < addAfterBroadcast.size(); a++) {
int key = addAfterBroadcast.keyAt(a);
ArrayList<Object> arrayList = addAfterBroadcast.get(key);
for (int b = 0; b < arrayList.size(); b++) {
addObserver(arrayList.get(b), key);
}
}
addAfterBroadcast.clear();
}
}
}
public void addObserver(Object observer, int id) {
if (broadcasting != 0) {
ArrayList<Object> arrayList = addAfterBroadcast.get(id);
if (arrayList == null) {
arrayList = new ArrayList<>();
addAfterBroadcast.put(id, arrayList);
}
arrayList.add(observer);
return;
}
ArrayList<Object> objects = observers.get(id);
if (objects == null) {
observers.put(id, (objects = new ArrayList<>()));
}
if (objects.contains(observer)) {
return;
}
objects.add(observer);
}
public void removeObserver(Object observer, int id) {
if (broadcasting != 0) {
ArrayList<Object> arrayList = removeAfterBroadcast.get(id);
if (arrayList == null) {
arrayList = new ArrayList<>();
removeAfterBroadcast.put(id, arrayList);
}
arrayList.add(observer);
return;
}
ArrayList<Object> objects = observers.get(id);
if (objects != null) {
objects.remove(observer);
}
}
}
Then make your Activities look like this, you receive messages from the Service in didReceivedNotification()
public class YourActivity implements NotificationCenter.NotificationCenterDelegate {
#Override
public void onPause() {
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateActivity);
super.onPause();
}
#Override
public void onResume() {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateActivity);
super.onResume();
}
#Override
public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.updateActivity) {
// do something with your activity, your service called this
}
}
}
Finally send messages in your Service to all the Activities which are listening:
NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateActivity, optionalData);
Which is very nice, you don't have to pass Activity instances.
NotificationCenter source is from Telegram.
public class myService extends Service
{
public static myActivity activity;
public static void setActivity(myActivity activity)
{
this.activity = activity;
}
public void useActivityExample()
{
myService.myActivity.update();
}
}
public class myActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
// ... some things are being executed and myService is being bound
mService.setActivity(getActivity());
}
}

Method get() pass value but set() return null

As follows, constructors are generally used to create and assign values to object instance variables
And the accessors and modifiers allow you to capture and configure things, in this case instance variables
I pass the set but when I call get it returns null
here I create a class and its constructor with their instance variables:
public class Esquema {
private int goleiro;
private Atleta goleiroobj;
public Esquema()
{
}
public Atleta getGoleiroobj() {
return goleiroobj;
}
public void setGoleiroobj(Atleta goleiroobj) {
this.goleiroobj = goleiroobj;
}
public int getGoleiro() {
return goleiro;
}
public void setGoleiro(int goleiro) {
this.goleiro = goleiro;
}
}
I call my set() here :
private static Esquema getEsquemaOrganize(Atleta atleta, Esquema esquema) {
switch (atleta.getPosicaoId()){
//GOLEIRO
case 1 : esquema.setGoleiro(atleta.atleta_id);
esquema.setGoleiroobj(MercadoManager.getAtleta(esquema.getGoleiro()));
break;
I call my get here :
public class EsquemaTaticoViewHolder {
private LinearLayout lay_goleiro;
private TextView nome_goleiro;
public EsquemaTaticoViewHolder() {
}
public EsquemaTaticoViewHolder(View view, Esquema esquema) {
nome_goleiro = (TextView) view.findViewById(R.id.nome_goleiro);
lay_goleiro = (LinearLayout) view.findViewById(R.id.lay_goleiro);
if(esquema.getGoleiro() > 0){
nome_goleiro.setText(esquema.getGoleiroobj().apelido);
lay_goleiro.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
}
}

Excessive Internal memory consumed while using two different asyncTask on same RealmObject Android

1.. If i run two methods create2YearsDatabse(); at one anpplication run session
then kill the program completely and then in the next run run the method :
updateAutoGeneratedCalendar();
then the result is as expected it takes about
2-3 MB of memory
2. But if i run create2YearsDatabse() and onSuccess() callback of async Task it is using then the memory it takes in internal memory suddenly goes to more than 400 MB.
// The methods are managed in this way:
public void create2YearsDatabase() {
new BGAsyncTasks(context, new ThreadCallBack() {
#Override
public void onSuccess() {
final SettingAndStatusDTO settingDto = realm.where(SettingAndStatusDTO.class).findFirst();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
//because two years has more or equal to 730 days
if (realm.where(CalendarDto.class).findAll().size() >= 730) {
settingDto.setIs2YearsFullDBCreated(true);
context.getSharedPreferences(context.getString(R.string.shared_pref_name),Context.MODE_PRIVATE).edit().putBoolean(SplashActivity.FIRST_TIME_RUN,false).apply();
}
}
});
SplashActivity.freshRun = false;
startDashBoard();
}
#Override
public void onFailure() {
}
}, BGAsyncTasks.CREATE_INITIALIZE_2_YEARS_CALENDAR).execute();
}
public void updateAutoGeneratedCalendar() {
new BGAsyncTasks(context, new ThreadCallBack() {
#Override
public void onSuccess() {
Log.i("datatest", "full data size" + realm.where(CalendarDto.class).findAll().size());
final SettingAndStatusDTO settingDto = realm.where(SettingAndStatusDTO.class).findFirst();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
if (realm.where(CalendarDto.class).findAll().size() >= 32000)
settingDto.setIs90YearsDBCreated(true);
}
});
}
#Override
public void onFailure() {
}
}, BGAsyncTasks.CREATE_AUTO_GENERATE_CALENDAR).execute();
}
And My Async Task Looks like this :
public class BGAsyncTasks extends AsyncTask<Void, Void, Void> {
// Intention variables
public static final int CREATE_INITIALIZE_2_YEARS_CALENDAR = 0;
public static final int CREATE_AUTO_GENERATE_CALENDAR = 1;
// Message from the Activity/Fragment.
ThreadCallBack callBack;
Context context;
int intention;
IParseData parser ;
//Constructor for bg processes.
public BGAsyncTasks(Context c, ThreadCallBack callBack, int DATA_TYPE_FROM_RES) {
this.callBack = callBack;
this.context = c;
this.intention = DATA_TYPE_FROM_RES;
this.parser = new ParseData(context);
}
#Override
protected Void doInBackground(Void... params) {
switch (intention) {
case CREATE_AUTO_GENERATE_CALENDAR: {
final Realm asyncRealm = Realm.getDefaultInstance();
for (int i = 2000; i <= 2090; i++) {
if (i < 2072 || i > 2073) {
for (int j = 0; j < 12; j++) {
parser.setOnemonthData(i, j);
}
}
Log.i("datatest", "year:" + i);
}
}
case CREATE_INITIALIZE_2_YEARS_CALENDAR: {
String thisMonthString;
for (int i = 2072; i <=2073; i++) {
for (int j = 0; j < 12; j++) {
thisMonthString = getStringByMonth(i, j);// returns the json string
parser.parseOneMonthData(fixFormatting(thisMonthString));
}
}
}
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
callBack.onSuccess();
}
}
And my Parse and saving to Database methods look like this:
public class ParseData implements IParseData {
Context context;
Realm realm;
CalendarDto mCalendarDto;
public ParseData(Context c) {
context = c;
mCalendarDto = new CalendarDto();
}
public void parseOneMonthData(String monthData) {
//parse json data of one month and return as DTO of size equal
//to no of days in that month
try {
JSONArray oneMonthJsonData = new JSONArray(monthData);
int length = oneMonthJsonData.length();
for (int i = 0; i < length; i++) {
saveOneDayData(oneMonthJsonData.optJSONObject(i));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void saveOneDayData(final JSONObject singleTouple) {
realm = Realm.getDefaultInstance();
// parsing the data of one day so that it can be used everywhere.
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
mCalendarDto.setDayInfo(singleTouple.optString(DataItems.DAY_INFO));
mCalendarDto.setMahina(singleTouple.optString(DataItems.MAHINA));
realm.copyToRealmOrUpdate(mCalendarDto);
}
});
}
// saving data by month and year
public void setOnemonthData(final int yr, final int mnt) {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
mCalendarDto.setMonthEnId(currentEngMonth);
mCalendarDto.setMonthNpId(month);
realm.copyToRealmOrUpdate(mCalendarDto);
}
}
});
}
}
Here is my Calendar Realm Object :
public class CalendarDto extends RealmObject {
public CalendarDto() {
}
#PrimaryKey
private int primaryDayId
private String sakey;
private String raja;
private String mantri;
private String nepalSambat;
// more variables and ...........
//// autogenerated getters and settetrs
////////
}
#Override
protected Void doInBackground(Void... params) {
switch (intention) {
case CREATE_AUTO_GENERATE_CALENDAR: {
final Realm asyncRealm = Realm.getDefaultInstance(); // <--- this line
and
public void saveOneDayData(final JSONObject singleTouple) {
realm = Realm.getDefaultInstance(); // <--- this line
and
public void setOnemonthData(final int yr, final int mnt) {
realm = Realm.getDefaultInstance(); // <--- this line
On background threads, you should close the Realm instance after using them in a finally block.
In this case, you are opening a new Realm instance for every single day twice, and you're not closing any of them.
On a background thread, best practice is to open only one Realm instance, and then close it after the execution is complete.
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
//do things
} finally {
if(realm != null) {
realm.close();
}
}

What is wrong with my Game Thread?

I have been trying for a while to implement a Game Thread to utilise a loop to implement logic. I posted a question here not long ago, I hope no one minds the follow up.
I have managed to scrape together this code from my research:
public class GameView extends SurfaceView implements SurfaceHolder.Callback
{
class GameThread extends Thread
{
//states
public static final int STATE_LOSE = 1;
public static final int STATE_PAUSE = 2;
public static final int STATE_READY = 3;
public static final int STATE_RUNNING = 4;
private Paint m_paint;
//canvas dimensions
private int m_canvasWidth;
private int m_canvasHeight;
private long m_lastTime;
private boolean m_run = false;
private int m_mode;
public ImageView ship;
RelativeLayout.LayoutParams shipParams;
// Handle to the surface manager
private SurfaceHolder m_surfaceHolder;
public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler)
{
m_surfaceHolder = surfaceHolder;
}
//Initialise the game
public void doStart()
{
synchronized (m_surfaceHolder)
{
resetGame();
m_lastTime = System.currentTimeMillis() + 100;
setState(STATE_RUNNING);
ship = (ImageView) findViewById(R.id.imageView1);
shipParams = (RelativeLayout.LayoutParams)ship.getLayoutParams();
}
}
public void pause()
{
synchronized (m_surfaceHolder)
{
if (m_mode == STATE_RUNNING)
setState(STATE_PAUSE);
}
}
#Override
public void run()
{
while (m_run)
{
Canvas c = null;
try
{
c = m_surfaceHolder.lockCanvas(null);
synchronized (m_surfaceHolder)
{
if (m_mode == STATE_RUNNING)
{
updateGame();
}
doDraw(c);
}
}
catch(Exception e){}
finally
{
if (c != null)
{
m_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
public void setRunning(boolean b)
{
m_run = b;
}
public void setState(int mode)
{
synchronized (m_surfaceHolder)
{
setState(mode, null);
}
}
public void setState(int mode, CharSequence message)
{
synchronized (m_surfaceHolder)
{
m_mode = mode;
}
}
public void setPlayers(boolean onePlayer)
{
}
public void setSurfaceSize(int width, int height)
{
synchronized (m_surfaceHolder)
{
m_canvasWidth = width;
m_canvasHeight = height;
}
}
public void unpause()
{
synchronized (m_surfaceHolder)
{
m_lastTime = System.currentTimeMillis() + 100;
}
setState(STATE_RUNNING);
}
private void doDraw(Canvas canvas)
{
canvas.drawARGB(255, 0, 0, 0);
}
private void updateGame()
{
long now = System.currentTimeMillis();
if (m_lastTime > now)
return;
double elapsed = (now - m_lastTime) / 1000.0;
m_lastTime = now;
System.out.print("HELLO WORLD");
shipParams.topMargin++;
ship.setLayoutParams(shipParams);
}
private boolean collided(Rect rectangle)
{
return false;
}
public boolean foundWinner()
{
return false;
}
public void resetGame()
{
}
public void handleInput(MotionEvent event)
{
}
}
private Context m_context;
private GameThread m_thread;
private Handler m_handler;
public GameView(Context context, AttributeSet attrs)
{
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
m_handler = new Handler() {
#Override
public void handleMessage(Message m) {
Bundle b = m.getData();
MotionEvent e = b.getParcelable("event");
m_thread.handleInput(e);
}
};
m_thread = new GameThread(holder, context, m_handler);
setFocusable(true);
};
public GameThread getThread()
{
return m_thread;
}
#Override
public void onWindowFocusChanged(boolean hasWindowFocus)
{
if (!hasWindowFocus)
m_thread.pause();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
m_thread.setSurfaceSize(width, height);
}
public void surfaceCreated(SurfaceHolder holder)
{
if(m_thread.getState() == State.TERMINATED)
{
m_thread = new GameThread(getHolder(), m_context, m_handler);
m_thread.setRunning(true);
m_thread.start();
m_thread.doStart();
}
else
{
m_thread.setRunning(true);
m_thread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
m_thread.setRunning(false);
while (retry)
{
try
{
m_thread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
return true;
}
}
I am fairly certain that my issue lies here and it is merely a logical one. Everything does seem fine to me, however and I am in need of assistance.
I have attempted to draw an image at line 47 and defined a movement to take place in the update method at line 153. I also have placed a print line for extra debug, but the line doesn't show.
I am stumped.
Any help would be great, thanks.
Here are my other codes, if neccessary:
MainActivity.java
GameSetup.java
game_setup.xml
edit: I should note that I'm not getting any kind of errors within the code, it merely doesn't respond
You are initializing m_run as false,then in the while cycle in the run() method you must have set to true. Change it to true and the thread will work normally.
set m_run to true in your doStart() procedure

Categories

Resources