Notification handling in android - java

I am developing a multi player game, which have a module which works on the basis of notifications send by server. For example: Action of other player, score update, action to do etc.
I am receiving notification in json format. I am wondering if there is some codding pattern exist which automatically deliver different notifications to their corresponding handlers. Many thanks for your help.

Well, cannot say if this classifies as a pattern:
My take on it would be to simply create a separate class, lets call it JSONGameStateFilter, to filter the JSON object based on the received value plus the state of the game
Something like:
public class JSONGameStateFilter() {
public interface GameInterface1 {
// callback methods for activity 1
// example: public void newPlayerArrived(String name, int score);
// ...
}
public interface GameInterface2 {
// callback methods for activity 2
}
public interface GameInterface3 {
// callback methods for activity 3
}
private GameInterface1 callback1;
private GameInterface2 callback2;
private GameInterface3 callback3;
private JSONGameStateFilter instance;
public static JSONGameStateFilter getInstance() {
if (instance != null) {
return instance = new JSONGameStateFilter();
}
}
private JSONGameStateFilter() {}
public void registerListener(GameInterface1 callback) {
// called by Activity1 implementing GameInterface1
// by JSONGameStateFilter.newInstance().registerListener(this);
this.callback1 = callback;
}
public void registerListener(GameInterface2 callback) {
this.callback2 = callback;
}
public void registerListener(GameInterface3 callback) {
this.callback3 = callback;
}
public void filterJSON(JSONObject object) {
// read JSON and gamestate
// depending on situation call the right callback
// example: if (callback1 != null) callback1.newPlayerArrived(name, score)
}
}
The design of this approach would be to implement varies of callbacks on each activity (known pattern for fragments to communicate back to activity).
This is untested and written just now but I am pretty confident that it would work well.

Related

in PreferenceFragmentCompat Bluetooth's object open Android Java

I'm writing an app and I'm not really getting anywhere.
I have a class called SettingsFragmentForBLT that derives from PreferenceFragmentCompat. In it I handle user input from onPreferenceChange. Here you have the option of making settings for the Bluetooth device with which the smartphone is already paired when the class is called up. I rule the BLT matters in the class called DeviceControlActivity.
I need to expose THE handling object from DeviceControlActivity in the SettingsFragmentForBLT class so that I can pass the data to the BLT device at the time of input from the user. As far as I know, I have to overload the constructor of the DeviceControlActivity for this. My attempt refers to this website:
https://sciodoo.de/konstruktor-im-java-programm-ein-objekt-uebermachen/#
Here is the code from the SettingsFragmentForBLT class:
public static class SettingsFragmentForBLT extends PreferenceFragmentCompat implements
Preference.OnPreferenceChangeListener {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.blt_preferences);
// A listener is used to monitor preference changes in PreferencFragmnt (BLT).
Preference preferenceFeedbackIstAn = findPreference("FeedbackIstAn");
preferenceFeedbackIstAn.setOnPreferenceChangeListener(this);
Preference preferenceSwitchfeedback = findPreference("seek_bar_key");
preferenceSwitchfeedback.setOnPreferenceChangeListener(this);
}
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String preferenceKey = preference.getKey();
DeviceControlActivity deviceControlActivity = new DeviceControlActivity();
DeviceControlActivity msBluetoothLeService = new deviceControlActivity.getmBluetoothLeService(deviceControlActivity);
// BluetoothLeService mBluetoothLeService
Boolean switchOn = (boolean) newValue;
if (preferenceKey.equals("FeedbackIsAn")) {
deviceControlActivity.toggleLEDGren();
Log.w(TAG, "preferenceValue: " + newValue);
if (switchOn) {
if (msBluetoothLeService != null) {
msBluetoothLeService.writeCustomCharacteristic(53);
Log.w(TAG, "Green has been turned on");
}
...
Here is the code from DeviceControlActivity:
public class DeviceControlActivity extends AppCompatActivity{
...
public DeviceControlActivity(BluetoothLeService mBluetoothLeService) {
this.mBluetoothLeService = mBluetoothLeService;//Assignment with this
}
public void getmBluetoothLeService(DeviceControlActivity createdObject){
this.mBluetoothLeService = createdObject.mBluetoothLeService;
}
...
Thank you for your support and I wish you a pleasant time
I tried to create an object from DeviceControllActivity class in SettingsFragmentForBLT class

When to use member variables vs design by composition?

I am trying to wrap my head around how to best design the system I am working on.
Let’s say it’s an application similar to a pawn store. I have abstructed the flow of purchasing and reselling into something called an ExecutionStrategy. There are four ExecutionStrategy implementations in this application: registering a customer, bidding and purchasing, pricing, and posting to store.
There a basic steps that each one of the strategies follow including the main execution workflow and recording what we’ve done in a data store.
in addition to these bidding and purchasing as well as pricing require a consultation of an expert before we can do anything in the execution workflow.
this is where I am a little bit confused on the decision that I would like to make in terms of design. it appears as if there are three options to go with and I’m not too sure which one is most correct. 1) Extending Execution strategy with something like ExecutionStrategy with ExecutionStrategyWithConsultation, which wraps the execution workflow of the strategy with a consultation phase. 2) Creating a Decorator pattern for ExecutionStrategy and extends that with something like ConsultationServiceDecorator. 3) create a member variable in the implementation of purchasing/bidding and pricing to call the consultation service at any time with an interface around the service.
I will outline the design below.
Some considerations:
ConsultationService is very, very slow. Caching is not really an option here as the data is very loosely formed and we do not want to create a document datastore just for this.
ConsultationService returns an object that matches what was given. So it ends up having 1 method that looks like T consultOn(T item)
There could be some desire to call ConsultationService at any time in the execution workflow. Currently the only use case is to call the service before the main flow, but this is not necessarily the only use case right now.
Pros/cons of each approach above:
Extending ExecutionStrategy directly:
PRO: We can have access to a protected ConsultationService variable in the code
PRO: We have an understanding from reading the code that a, say, PurchasingExecutionStrategy extends ExecutionStrategyWithConsultation, so we know a bit about what kind of workflow it is just from that.
CON: This seems to break the "composition over inheritance" pattern. We are using inheritance for storing member variables.
CON: The service returns a whole new object, so after the first line of code when we make the call to the service, we are dealing with an entirely different object than the one passed originally.
Creating a Decorator:
PRO: We are more closely conforming with the composition over inheritance principal.
PRO: We can enforce that the service is called first, and pass that new object to the main workflow, so it only executes its main workflow on the object passed.
CON: I have not figured out a way to design this in a way to allow for potentially multiple or any time service calls.
CON: When looking at the code, we lose the knowledge gained from PurchasingExecutionStrategy extends ExecutionStrategyWithConsultation, unless we look at where PurchasingExecutionStrategy is actually being instantiated as a constructor arg of ConsultationServiceDecorator
Create a member variable with interface:
PRO: Same pros as #1. Easy to understand fully what code is doing without digging.
CON: Same cons as #1. Cannot enforce order. Execution deals with inheritenly different object than the one passed.
CON: If we need to make multiple calls in the same workflow, this would be very slow due to service speed and no cache.
Examples of each:
//Number 1
public interface ExecutionStrategy<T> {
/**
* Perform the main execution workflow
*/
public T execute(T item);
}
public interface ConsultationService {
public StoreItem consultOn (StoreItem item);
}
public abstract class ExecutionStrategyWithConsultation implements ExecutionStrategy<StoreItem> {
protected ConsultationService consultationService;
}
public class ListingExecutionStrategy extends ExecutionStrategyWithConsultation {
public StoreItem execute(StoreItem item) {
if (item.hasDirectBuyer()) { //hasDirectBuyer is populated by ConsultationService
item.sellTo = item.directBuyer.getId();
} else {
//no direct buyer
SuggestedPriceRange priceRange = item.getConsultationPriceRange(); //consultationPriceRange is populated by ConsultationService
item.priceRange = priceRange;
item.listToWebsite = true;
}
return item;
}
}
//Number 2
public interface ExecutionStrategy<T> {
/**
* Perform the main execution workflow
*/
public T execute(T item);
}
public abstract class ExecutionStrategyDecorator<T> implements ExecutionStrategy<T>{
protected final ExecutionStrategy<T> executionStrategy;
public ExecutionStrategyDecorator(ExecutionStrategy<T> execStrategy) {
executionStrategy = execStrategy;
};
}
public class ExecutionStrategyWithConsultation extends ExecutionStrategyDecorator<StoreItem> {
protected ConsultationService consultationService;
public ExecutionStrategyWithConsultation(ExecutionStrategy<StoreItem> execStrat, ConsultationService service) {
super(execStrat);
consultationService = service;
}
public StoreItem execute(StoreItem item) {
StoreItem itemAfterConsultation = consultationService.consultOn(item);
return execStrategy.execute(itemAfterConsultation);
}
}
public class ListingExecutionStrategy implements ExecutionStrategy<StoreItem> {
public StoreItem execute(StoreItem item) {
if (item.hasDirectBuyer()) { //hasDirectBuyer is populated by ConsultationService
item.sellTo = buyer.getId();
} else {
//no direct buyer
SuggestedPriceRange priceRange = item.getConsultationPriceRange(); //consultationPriceRange is populated by ConsultationService
item.priceRange = priceRange;
item.listToWebsite = true;
}
return item;
}
}
public class ListingExecutionStrategyFactory {
public ExecutionStrategy instantiate() {
return new ExecutionStrategyWithConsultation(new ListingExecutionStrategy(), new ConsultationServiceImpl());
}
}
//Number 3
public interface ExecutionStrategy<T> {
/**
* Perform the main execution workflow
*/
public T execute(T item);
}
public interface ConsultationService {
public DirectBuyer getDirectBuyerIfExists(StoreItemType itemType);
public SuggestedPriceRange getSuggestedPriceRange(StoreItem item);
}
public class ListingExecutionStrategy implements ExecutionStrategy<StoreItem> {
ConsultationService service;
public PurchasingExecutionStrategy(ConsultationService consultService) {
service = ConsultationService;
}
public StoreItem execute(StoreItem item) {
DirectBuyer buyer = service.getDirectBuyerIfExists(item.getItemType())
if (Optional.ofNullable(buyer).isPresent()) {
item.sellTo = buyer.getId();
return item;
} else {
//no direct buyer
SuggestedPriceRange priceRange = service.getSuggestedPriceRange(item);
item.priceRange = priceRange;
item.listToWebsite = true;
return item;
}
}
}
Thanks for the input. Appreciate the help.
As an alternative to your ConsultationService, you might consider building a chain of ExecutionService instances to allow creation of complex processing scenarios:
public interface ExecutionStrategy<T> {
public T execute(T item);
}
public interface ExecutionStrategyChain<T> extends ExecutionStrategy<T> {
public static <T> ExecutionStrategyChain<T> newInstance(ExecutionStrategy<T> executionStrategy) {
return new ExecutionStrategyChainImpl<T>(executionStrategy);
}
public ExecutionStrategyChain<C> chainTo(ExecutionStrategy<C> executionStrategy);
}
public abstract class AbstractExecutionStrategyChain<T> implements ExecutionStrategyChain<T> {
protected AbstractExecutionStrategyChain() {
this(null);
}
public abstract T execute(T item);
public ExecutionStrategyChain<T> chainTo(ExecutionStrategy<T> executionStrategy) {
return new ExecutionStrategyChainImpl<T>(this, executionStrategy);
}
}
public final class ExecutionStrategyChainImpl<T> extends AbstractExecutionStrategyChain<T> {
private final ExecutionStrategy<T> firstExecutionStrategy;
private final Executionstrategy<T> secondExecutionStrategy;
public ExecutionStrategyChainImpl(ExecutionStrategy<T> first, ExecutionStrategy<T> second) {
if(first == null) throw new NullPointerException();
this.firstExecutionStrategy = first;
this.secondExecutionStrategy = second;
}
public ExecutionStrategyChainImpl(ExecutionStrategy<T> first) {
this(first, null);
}
#Override
public final T execute(T item) {
if(item == null) {
return null;
}
T result = firstExecutionStrategy.execute(item);
if(result != null && secondExecutionStrategy != null) {
result = secondExecutionStrategy.execute(result);
}
return result;
}
}
public class PreProcessor<T> implements ExecutionStrategy<T> {
public PreProcessor() {
}
#Override
public T execute(T item) {
//Do some pre-processing of item
return item;
}
}
public class PostProcessor<T> implements ExecutionStrategy<T> {
public PostProcessor() {
}
#Override
public T execute(T item) {
//Do some post-processing of item
return item;
}
}
public class MyNormalProcessor<T> extends AbstractExecutionStrategyChain<T> {
public MyNormalProcessor() {
}
#Override
public T execute(T item) {
//Do something normal with the item
return item;
}
}
public static final ExecutionStrategy<StoreItem> COMPLEX_EXECUTION_STRATEGY =
ExecutionStrategyChain<StoreItem>.newInstance(new PreProcessor<StoreItem>())
.chainTo(new MyNormalProcessor<StoreItem>())
.chainTo(new PostProcessor<StoreItem>());

android - Check if the room database is populated on startup without Livedata

I'm fairly new to Android and I want to have a database in my app.
I'm introduced to Room the documents say it's the best way to implement databases in the android.
Now I have to pre-populate some data in the database, and make sure that it gets populated before the app startup.
I see that there are many things like LiveData, Repositories, ViewModels and MediatorLiveData.
But I just want to keep it plain and simple, without using the said things how can one find if the database has been populated before the application launch.
I'm getting loads of NullPointerExceptions.
I'm using onCreateCallback() to populate the database but when I try to get the item from database it produces NullPointerException and after some time it may or may not produce the same warning, and the question remains the same what is the best way to know when the database is populated completely.
Here is a Minimal Example
public class MainActivity extends AppCompatActivity {
private TextView nameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nameView = findViewById(R.id.name);
new NamesAsyncTask().execute();
}
private class NamesAsyncTask extends AsyncTask<Void,Void,String> {
private NameDao mNameDao;
#Override
public String doInBackground(Void... params) {
NameDatabase db = NameDatabase.getDatabase(MainActivity.this);
mNameDao = db.nameDao();
String name = mNameDao.getNameByName("Body").name;
return name;
}
#Override
public void onPostExecute(String name) {
nameView.setText(name);
}
}
}
Entity
#Entity(tableName = "name")
public class Name {
#NonNull
#PrimaryKey(autoGenerate = true)
public Integer id;
#NonNull
#ColumnInfo(name = "name")
public String name ;
public Name(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id ) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Dao
#Dao
public interface NameDao {
#Insert
void insertAll(List<Name> names);
#Query("SELECT * from name")
List<Name> getAllNames();
#Query("DELETE FROM name")
void deleteAll();
#Query("SELECT * FROM name WHERE name = :name LIMIT 1")
Name getNameByName(String name);
#Query("SELECT * FROM name WHERE id = :id LIMIT 1")
Name getNameById(int id);
}
Database
#Database(entities = {Name.class}, version = 1)
public abstract class NameDatabase extends RoomDatabase {
public abstract NameDao nameDao();
private static NameDatabase INSTANCE;
public boolean setDatabaseCreated = false;
public static NameDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (NameDatabase.class) {
if (INSTANCE == null) {
INSTANCE = buildDatabase(context);
INSTANCE.updateDatabaseCreated(context);
}
}
}
return INSTANCE;
}
private static NameDatabase buildDatabase(final Context appContext) {
return Room.databaseBuilder(appContext, NameDatabase.class,
"name_database").addCallback(new Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
Executors.newSingleThreadScheduledExecutor().execute(() -> {
// Add Delay to stimulate a long running opeartion
addDelay();
// Generate the data for pre-population
NameDatabase database = NameDatabase.getDatabase(appContext);
List<Name> names = createNames();
insertData(database, names);
// notify that the database was created and it's ready to be used
database.setDatabaseCreated();
});
}
}
).build();
}
private void updateDatabaseCreated(final Context context) {
if (context.getDatabasePath("name_database").exists()) {
setDatabaseCreated();
}
}
private boolean setDatabaseCreated() {
return this.setDatabaseCreated = true;
}
protected static List<Name> createNames() {
List<Name> cList = new ArrayList<>();
cList.add(new Name(1, "Body"));
cList.add(new Name(2, "Mind"));
cList.add(new Name(3, "Love"));
cList.add(new Name(4, "Community"));
cList.add(new Name(5, "Career"));
cList.add(new Name(6, "Money"));
cList.add(new Name(7, "Fun"));
cList.add(new Name(8, "Home"));
return cList;
}
private static void insertData(final NameDatabase database, final List<Name> names) {
database.runInTransaction(() -> {
database.nameDao().insertAll(names);
});
}
private static void addDelay() {
try {
Thread.sleep(4000);
} catch (InterruptedException ignored) {
}
}
}
Gives me the exception on String name = mNameDao.getNameByName("Body").name; this line, when I install the app for first time, however if I close the app and start again it does not give the exception anymore. I think because the database has not been populated yet.
I read a post Pre-Populate Database that says on the first call to db.getInstance(context); the database will be populated on in my case NameDatabase.getDatabase(MainActivity.this).
So what shall I do to know if the database has finished populating after the call?
I think because the database has not been populated yet.
Correct. You have forked one background thread (AsyncTask). That thread is forking a second background thread, via your getDatabase() call, as your database callback is forking its own thread via Executors.newSingleThreadScheduledExecutor().execute(). Your AsyncTask is not going to wait for that second thread.
Remove Executors.newSingleThreadScheduledExecutor().execute() from your callback. Initialize your database on the current thread (which, in this case, will be the AsyncTask thread). Make sure that you only access the database from a background thread, such as by having your database access be managed by a repository.
I hope I'm not late! Just a bit of a background before I answer.
I was also searching for a solution regarding this problem. I wanted a loading screen at startup of my application then it will go away when the database has finished pre-populating.
And I have come up with this (brilliant) solution: Have a thread that checks the sizes of the tables to wait. And if all entities are not size 0 then notify the main UI thread. (The 0 could also be the size of your entities when they finished inserting. And it's also better that way.)
One thing I want to note is that you don't have to make the variables in your entity class public. You already have getters/setters for them. I also removed your setDatabaseCreated boolean variable. (Believe me, I also tried to have a volatile variable for checking but it didn't work.)
Here's the solution: Create a Notifier class that notifies the main UI thread when the database has finished pre-populating. One problem that arises from this is memory leaks. Your database might take a long time to pre-populate and the user might do some configuration (like rotating the device for example) that will create multiple instances of the same activity. However, we can solve it with WeakReference.
And here's the code...
Notifier class
public abstract class DBPrePopulateNotifier {
private Activity activity;
public DBPrePopulateNotifier(Activity activity) {
this.activity = activity;
}
public void execute() {
new WaitDBToPrePopulateAsyncTask(this, activity).execute();
}
// This method will be called to set your UI controllers
// No memory leaks will be caused by this because we will use
// a weak reference of the activity
public abstract void onFinished(String name);
private static class WaitDBToPrePopulateAsyncTask extends AsyncTask<Void, Void, String> {
private static final int SLEEP_BY_MILLISECONDS = 500;
private WeakReference<Activity> weakReference;
private DBPrePopulateNotifier notifier;
private WaitDBToPrePopulateAsyncTask(DBPrePopulateNotifier notifier, Activity activity) {
// We use a weak reference of the activity to prevent memory leaks
weakReference = new WeakReference<>(activity);
this.notifier = notifier;
}
#Override
protected String doInBackground(Void... voids) {
int count;
Activity activity;
while (true) {
try {
// This is to prevent giving the pc too much unnecessary load
Thread.sleep(SLEEP_BY_MILLISECONDS);
}
catch (InterruptedException e) {
e.printStackTrace();
break;
}
// We check if the activity still exists, if not then stop looping
activity = weakReference.get();
if (activity == null || activity.isFinishing()) {
return null;
}
count = NameDatabase.getDatabase(activity).nameDao().getAllNames().size();
if (count == 0) {
continue;
}
// Add more if statements here if you have more tables.
// E.g.
// count = NameDatabase.getDatabase(activity).anotherDao().getAll().size();
// if (count == 0) continue;
break;
}
activity = weakReference.get();
// Just to make sure that the activity is still there
if (activity == null || activity.isFinishing()) {
return null;
}
// This is the piece of code you wanted to execute
NameDatabase db = NameDatabase.getDatabase(activity);
NameDao nameDao = db.nameDao();
return nameDao.getNameByName("Body").getName();
}
#Override
protected void onPostExecute(String name) {
super.onPostExecute(name);
// Check whether activity is still alive if not then return
Activity activity = weakReference.get();
if (activity == null|| activity.isFinishing()) {
return;
}
// No need worry about memory leaks because
// the code below won't be executed anyway
// if a configuration has been made to the
// activity because of the return statement
// above
notifier.onFinished(name);
}
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private TextView nameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nameView = findViewById(R.id.name);
new DBPrePopulateNotifier(this) {
#Override
public void onFinished(String name) {
// You set your UI controllers here
// Don't worry and this won't cause any memory leaks
nameView.setText(name);
}
}.execute();
}
}
As you can see, our Notifier class has a thread in it that checks if the entities are not empty.
I didn't change anything in your other classes: Name, NameDao and NameDatabase except that I removed the boolean variable in NameDatabase and made private the variables in Name.
I hope that this answers your question perfectly. As you said, no LiveData, Repository, etc.
And I really hope I ain't late to answer!
Now I want to write down what I tried before I came up to the final solution.
Keep in mind that what I am trying to do here is for my app to show a progress bar (that infinite spinning circle) and put it away after the database has finished pre-populating.
Tried:
1. Thread inside thread
Practically, there's a thread that checks if the size of an entity is still 0. The query is done by another thread.
Outcome: Failed. Due to my lack of knowledge, you cannot start a thread within another thread. Threads can only be started from the main thread.
Tables' sizes loop checker
A thread that queries the tables to be checked if they have been initialized through an infinite loop. Only breaks if all sizes of the tables to be checked are greater than 0.
Outcome: Solution. This is by far the most elegant and working solution to this problem. It doesn't cause memory leaks because as soon as a configuration has been made, the thread that loops continually will break.
Static variable
A static volatile variable in the database class in which will turn to true when the thread has finished inserting the values.
Outcome: Failed. For unknown reason that I still search for, it won't run the thread for initializing the database. I have tried 3 versions of the code implementation but to no avail. Hence, a failure.
Initialize database then notify
A listener that is defined in the UI thread then passed by argument to the repository. All database initialization is done also in the repository. After populating the database, it will then notify/call the listener.
Outcome: Failed. Can cause memory leaks.
As always, happy coding!
Logging in onCreateCallback ofc!

Refactoring a class implementing an interface by creating subclasses in GWT /java

I am implementing the frontend of an application in GWT (see attached picture) and I have view class which is getting bigger as more widgets are added to the frontend.
As stated in GWT tutorial, the view class must implement the Display interface of the presenter class. y problem is I have a lot a methods in that interface and as I implement them in the view class, it becomes too big. That's why I would like to refactor the code to reduce the size of the view class by implementing those methods in others
classes and reference them where needed in the view class;for instand by grouping them per group box (one class per group box).
Below is a sample code: Note that in the real application we have more widgets per group box.
The problem I am facing will be well explained as you read through the whole posting because I will be adding more details.
code to be refactored:
ContactPrewsenter.java
public class ContactPresenter {
public interface Display
{
void methodA();
void methodB();
void methodC();
void methodD();
void methodE();
void methodF();
.
.
.
void methodM();
}
public ContactPresenter()
{
//Some stuff here
}
......
......
#Override
public void bind(){
//Some stuff here
}
}
ContactView.java:
public class ContactView implements ContactPresenter.Display
{
private final Listbox listBoxA;
private final Listbox listBoxB;
private final Listbox listBoxC;
private final Listbox listBoxD;
private final Listbox listBoxE;
private final Listbox listBoxF;
private final Listbox listBoxG;
private final Listbox listBoxH;
private final Listbox listBoxI;
private final Listbox listBoxJ;
private final Listbox listBoxK;
private final Listbox listBoxL;
private final Listbox listBoxM;
public ContactView()
{
listBoxA = new ListBox();
listBoxB = new ListBox();
VerticalPanel vPanel1= new VerticalPanel();
vPanel1.add(listBoxA);
vPanel1.add(listBoxB);
GrooupBox groupBox1 = new GroupBox();
groupBox1.add(vPanel1);
listBoxC = new ListBox();
listBoxD = new ListBox();
VerticalPanel vPanel2 = new VerticalPanel();
vPanel2.add(listBoxC);
vPanel2.add(listBoxD);
GrooupBox groupBox2 = new GroupBox();
groupBox2.add(vPanel2);
listBoxE = new ListBox();
listBoxF = new ListBox();
VerticalPanel vPanel3 = new VerticalPanel();
vPanel3.add(listBoxE);
vPanel3.add(listBoxF);
GrooupBox groupBox3 = new GroupBox();
groupBox3.add(vPanel3);
listBoxE = new ListBox();
listBoxF = new ListBox();
VerticalPanel vPanel4 = new VerticalPanel();
vPanel4.add(ListBoxE);
vPanel4.add(ListBoxF);
....
GrooupBox groupBox3 = new GroupBox();
groupBox3.add(vPanel4);
listBoxG = new ListBox();
listBoxH = new ListBox();
....
VerticalPanel vPanel = new VerticalPanel();
vPanel.add(ListBoxG);
vPanel.add(ListBoxH);
....
GrooupBox groupBox4 = new GroupBox();
groupBox4.add(vPanel);
......
//create Horizontal/vertical panels, docklayout panel as well, to position the group boxes on the gui
....
}
#Override
void methodA(){
//uses listBoxA
}
#Override
void methodB(){
//used listBoxB
}
#Override
void methodC(){
//uses listBoxC
}
#Override
void methodD(){
//uses listBoxD
}
#Override
void methodE(){
//uses listBoxE
}
#Override
void methodF(){
//uses listBoxF
}
#Override
void methodG(){
//uses listBoxG
}
#Override
void methodH(){
//uses listBoxH
}
.
.
.
#Override
void methodM(){
//uses listBoxM
}
}
I have tried as follows:
ContactPreseter.java
public class ContactPresenter
{
public interface Display extends groupBox1View.Display, groupBox2View.Display, groupBox3View.Display, groupBox4View.Display
{
}
}
preseter classes of each group box
public class groupBox1Presenter
{
public interface Display
{
void methodA();
void methodB();
}
}
public class groupBox2Presenter
{
public interface Display
{
void methodC();
void methodD();
}
}
public class groupBox3Presenter
{
public interface Display
{
void methodE();
void methodF();
}
}
public class groupBox4Presenter
{
public interface Display
{
void methodG();
void methodH();
}
}
ContactView.java
public abstract class ContactView implements ContactPresenter.Display
{
// adds group boxes to horizontal/vertical panels, and docklayout panel
}
Below are the view classes for each group box:
But here I eclipse forces me to implement all the methods of the interface ContactPresenter.Display in each of these classes whereas , I wanted it to be the way you see implemented here.
I was wondering if there were a way to play with access modifiers in order to achieve that ? If not, please I would you to help with ideas how to do it ?
public groupBox1View extends ContactView implements groupBox1Presenter
{
public groupBox1View()
{
}
#Override
void methodA(){
//uses listBoxA
}
#Override
void methodB(){
//used listBoxB
}
}
public groupBox2View extends ContactView implements groupBox2Presenter
{
public groupBox2View()
{
}
#Override
void methodC(){
//uses listBoxC
}
#Override
void methodD(){
//used listBoxD
}
}
public groupBox3View extends ContactView implements groupBox3Presenter
{
public groupBox3View()
{
}
#Override
void methodE(){
//uses listBoxE
}
#Override
void methodF(){
//used listBoxF
}
}
public groupBox4View extends ContactView implements groupBox4Presenter
{
public groupBox4View()
{
}
#Override
void methodG(){
//uses listBoxG
}
#Override
void methodH(){
//used listBoxH
}
}
You are right, your view is growing too big. You need to cut it into components which are handling their own concerns.
The editor framework will prove helpful but has it's own caveats.
In the end, you have one presenter, working with the whole thing, but only reading and writing one contact object.
You build your view from multiple components, each may have it's own presenter and is responsible for one part of your large contact object.
An example: Instead of running 10 listboxes of generic type, make that 10 semantically different components, responsible for selection of different types of data: AgeListBox, CityListBox, FooListBox, BarListBox.
This will seperate the data provisioning for the boxes out of your central presenter, and into the specific presenters for each listbox.
Start at the lowest level and combine editing views for each semantic unit and combine them to larger return objects:
NameEditor, AgeEditor, FooEditor, BarEditor are combined into an AddressEditor, which assembles with a CVEditor into something bigger until you finally arrive at the contact level.
I hope this makes sense to you.
UPdate: You asked for code, let's try some pseudocode:
Let's say you have a profile you want to edit. It contains of
the user's personal data
contains the user address
a bunch of email or mobile addresses
an image or connection to Gravatar
payment information
the list of tags the user is interested in
the list of channels he subscribed
Newsletter/marketing information
public class UserProfile {
PersonalData person;
List<NewsTopic> topicsOfInterest;
List<NewsChannel> subscriptions;
MarketingInfo marketingInfo;
// bean stuff, constr, equals etc.
}
public class PersonalData {
String name;
String firstName;
List<ContactDevice>phoneAndMailList;
ImageContainer userImage;
BankAccount paymentData;
}
You get the idea, I guess...
You can now write ONE view class, detailing all the information you see here, resulting in a monolitic monster view and the matching monster presenter. Or you follow the advice in the gwtproject and cut the view in small as possible pieces (components). That is, subviews and presenters that form a hierarchy, matching the one of your UserProfile class. This is basically what the editor framework is really good at.
In the editor fw, the views are called "Editors" (makes sense), and they get fed the data from top editor down to the smallest part by an EditorDriver class. GWT will generate most of the code for you, which is very cool, but also is not working so perfect, if you have optional parts in the profile.
If we would implement this ourselves, you will build a structure like the following (I avoid the "Editor" and replaced by "Dialog"):
public class UserProfileDialogView extends Component implements HasValue<UserProfile> {
// subviews
#UiField
PersonalDataDialog personDataDlg;
#UiField
UserTopicListDialog topicListDlg;
#UiField
SubscriptionListDialog subscriptionListDlg;
#UiField
MarketingInfoDialog marketingInfoDlg;
#Overwrite
public UserProfile getValue() {
// we do not need to copy back the data from the sub-dialogs, because we gave them the values from the profile itself.
// Beware, substructures cannot be null in such a case!
return userProfile;
}
#Ovewrite
public void setValue(UserProfile profile) {
this.userProfile = profile;
// option one: manually distribute the profile parts
personDataDlg.getPresenter().setValue(profile.getPerson());
topicListDlg.getPresenter().setValue(profile.getTopicsOfInterest());
subscriptionListDlg.getPresenter().setValue(profile.getSubscriptions());
// option two: use eventbus and valuechanged event, dialogs are
}
}
There is now a variance of concerns: Who will set the value in the sub-dialogs. You can forward to the presenter of the sub-dialog, or you set it directly in the sub-dialog.
Anyway, what should get clear to you now, is that you do not have only one presenter to rule all parts of the view. You need to split the presenters to be responsible for one subview each. What I found useful in such a large dialog tree, was to have a separate model class, that keeps the object currently beeing edited and provides change communication logic for other dialogs. For example, if you add a list of topics, and you add one topic, the dialog for the channel subscription selection may want to know, that there is now one more topic to be shown in the topic-filter.

Restrict access to only necessary data-class accessors / getters

I have a data class that is created in one class, and can be passed to one of several Android UI Activities that implement a specific Interface.
Each UI uses the same data, however, not all the UIs need all of the data. I was wondering if there was a simple solution that allows each UI to only use a specific part of the data (only use specific accessors / getters)
ClickListener Handler Class
// ICalculatorAbstraction is what all my UI's implement. It has method... void updateResult(ExpressionState expression)
public final View.OnClickListener listenerOn(final ICalculatorAbstraction UI) {
return listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
// Calculations
ExpressionState expression = new ExpressionState.Builder()
.setFirstNumber(num1)
.setSecondNumber(num2)
.setTotal(total)
.setOperator(operator.getSign())
.build();
UI.updateResult(expression);
}
};
}
ICalculatorAbstraction Interface
Again, all of my Android Activities (UIs) implement this interface
public interface ICalculatorAbstraction {
...
void updateResult(ExpressionState result);
}
Needs All Accessors UI
#Override
public void updateResult(ExpressionState result) {
String results = String.format( // NOTE: this one needs ALL the accessors / getters!!
"%s %s %s = %s",
result.getFirstNumber(),
result.getOperator(),
result.getSecondNumber(),
result.getTotal()
);
this.txtResult.setText(results);
Needs One Accessor UI
#Override
public void updateResult(ExpressionState result) {
String results = String.format( // NOTE: this one needs ONE accessor / getter!!
"Wow. Such Calcuation. %s",
result.getTotal()
// NOTE: These should not be allowed in this instance because this UI does not use them
// result.getFirstNumber()
// result.getOperator()
// result.getSecondNumber()
);
this.txtResult.setText(results);
How can I change updateResult(...) (both in the interface and in the UI) so that the specific UI's updateResult(...) will only let me use the needed assessors / getters?
I have tried to create a blank interface, and then created 2 abstract classes that implement that blank interface. The abstract classes had only the accessors / getters I needed, but when I tried to modify the above code, nothing worked.
Is this possible?
Update
Here is what I would like to see - "my best possible solution" you can say.
Needs All Accessors UI
#Override
public void updateResult(IAllAccessors result) {
String results = String.format(
"%s %s %s = %s",
result.getFirstNumber(),
result.getOperator(),
result.getSecondNumber(),
result.getTotal()
);
this.txtResult.setText(results);
Needs One Accessor UI
#Override
public void updateResult(IOneAccessorOnly result) {
String results = String.format(
"Wow. Such Calcuation. %s",
result.getTotal() // I should not be able to do result.getFirstNumber(); for example
);
this.txtResult.setText(results);
ExpressionState / Builder Class
public class ExpressionState implements IOneAccessorOnly, IAllAccessors {
private ExpressionState(Builder builder) { ... }
public double getFirstNumber() { ... } // IAllAccessors
public double getSecondNumber() { ... } // IAllAccessors
public String getOperator() { ... } // IAllAccessors
public double getTotal() { ... } // IAllAccessors, IOneAccessorOnly
public static class Builder { ... }
}
The problem with this solution, is that I cannot figure out what to do with my interface that I have above! I cannot have a parameter that will make the compiler happy with both UIs.
Update 2
I cannot have...
In my ClickListener class when creating ExpressionState with the builder
IOneAccessorOnly var = new ExperssionState.Builder()...
This is because in my ClickListener class, I don't know which one to create. It has to be very generic. In my UI's I want to simplify what I can use. I cannot do that with this approach
Because it does not know what to be, it has to be "everything"
ExpressionState var = new ExpressionState.Builder()...
It really cannot be anything other than that. The solution will have to deal with the UIs (Activities) specifically to narrow down what is allowed!!
If Expression state is your own class I'd make it implement two different interfaces like so.
public class ExpressionState implements InterfaceOne, InterfaceTwo {
public void interfaceOneGetterMethod()
public void interfaceTwoGetterMethod()
}
in another file:
public interface InterfaceOne {
public void interfaceOneGetterMethod();
and final file:
public interface InterfaceTwo {
public void interfaceTwoGetterMethod();
Now when you create the ExpressionState objects assign them to objects defined as:
InterfaceTwo var = new ExperssionState(blah);
Or modify your builder to just return interfaces( even better )

Categories