Simplify multiple inheriting classes (with all same content) of abstract class - java

I like to count multiple things in my app and save the value to android sharedpreferences. Everything works, but I am not satisfied with the class design in general.
Very simple abstract class. Class parameter is used to name keys in sharedPreferences.
public abstract class Counter {
private Context mContext;
private Class mClass;
Counter(Class myClass, Context context) {
this.mClass = myClass;
this.mContext = context;
}
public Integer getValue() {
return PrefManager.with(mContext).getInt(mClass.getName(), 0);
//return UniversalPreferences.getInstance().get(counterName, 1);
}
public void increment() {
PrefManager.with(mContext).save(mClass.getName(), getValue() + 1);
//UniversalPreferences.getInstance().put(counterName, getCurrentValue(counterName) + 1);
}
}
So far I have already 5 classes inheriting from Counter with all the same content.
public class CounterAppLaunch extends Counter {
#SuppressLint("StaticFieldLeak")
private static CounterAppLaunch instance;
private CounterAppLaunch(Context context) {
super(CounterAppLaunch.class, context);
}
public static CounterAppLaunch getInstance(Context context) {
if(CounterAppLaunch.instance == null) {
CounterAppLaunch.instance = new CounterAppLaunch(context);
}
return CounterAppLaunch.instance;
}
}
I have counters I like to call from different classes and increment there (eg. CounterAPICall or CounterOnResumeCallExample). Which works with this code just fine.

This code might be useful to retrieve an appropriate counter:
public Counter{
private int count;
public Counter(){
count = 0;
}
public int getValue(){
return count;
}
public void increment(){
counter++;
}
}
public CounterStorage(){
private static HashMap<String, Counter> counterMap = new HashMap<>();
public static Counter getInstance(String str){
if (counterMap.containsKey(str)) return counterMap.get(str);
Counter newCounter = new Counter();
counterMap.add(str, newCounter);
return newCounter;
}
}
In this case, Counter isn't an abstract class. For any purpose, you can give a Counter a name, which is stored in the map.

With the help of Dependency injection and having HasA also, we can try,
public class CounterAppLaunch{
#Autowired
CounterAdapter counterAdapter;
#SuppressLint("StaticFieldLeak")
private static CounterAppLaunch instance;
private CounterAppLaunch(Context context) {
super(CounterAppLaunch.class, context);
}
public static CounterAppLaunch getInstance(Context context) {
if(CounterAppLaunch.instance == null) {
CounterAppLaunch.instance = new CounterAppLaunch(context);
}
return CounterAppLaunch.instance;
}
}
CounterAdapter extends Counter{
#Autowired
private Context mContext;
#Autowired
private Class mClass;
// getter and setter
}
public abstract class Counter {
private Context mContext;
private Class mClass;
Counter(Class myClass, Context context) {
this.mClass = myClass;
this.mContext = context;
}
public Integer getValue() {
return PrefManager.with(mContext).getInt(mClass.getName(), 0);
//return UniversalPreferences.getInstance().get(counterName, 1);
}
public void increment() {
PrefManager.with(mContext).save(mClass.getName(), getValue() + 1);
//UniversalPreferences.getInstance().put(counterName, getCurrentValue(counterName) + 1);
}
}

Related

Create class structure like glide and picasso in android

I want to create class structure like:
Glide.with(context).load("url").into(imageView);
Problem :-
public class Slider{
private static Activity context;
private static int Duration = 3000;
public static void setContext(Activity context) {
Slider.context = context;
}
public static void setDuration(Duration duration) {
Slider.Duration = duration;
}
}
// In Activity
Slider.setContext(this);
I declared all methods and required fields static but it can't work.
I tried with setter method but it allows only one setter.This class doesn't allow me to use second setter.
Requirement :
Slider.setContext(this).setDuration(3000);
I need class and method structure like glide and picasso library and some methods are compulsory.
You need to use Builder Pattern for this
public class Slider
{
private static Activity context;
private static int Duration = 3000;
private Slider(SliderBuilder builder) {
this.context = builder.context;
this.Duration = builder.Duration;
}
//All getter, and NO setter to provde immutability
public String getContext() {
return context;
}
public String getDuration() {
return Duration;
}
public static SliderBuilder with(Activity context){
return new SliderBuilder(context);
}
public static class SliderBuilder
{
private static Activity context;
private static int Duration = 3000;
public SliderBuilder(Activity context) {
this.context = context;
}
public SliderBuilder duration(int Duration) {
this.Duration = Duration;
return this;
}
//Return the finally constructed Slider object
public Slider build() {
Slider slider = new Slider(this);
validateSliderObject(slider);
return slider;
}
private void validateSliderObject(Slider slider) {
//Do some basic validations to check
}
}
}
Better explained here
EDIT
How to use
Slider.with(this).duration(3000).build();

Android: Getting the count of items with a specific code in a Room database

I am essentially trying to create some kind of a search feature. I am using a Room database and every element has a specific 3-digit code submitted by the user. However, when I try to get the number of elements with a specific 3-digit code and display it in a Toast message in Main Activity, I always get 0 as a result.
Each entity of my table is an object of a Word class I have created as shown here:
#Entity(tableName = "word_table")
public class Word {
#PrimaryKey(autoGenerate = true)
#NonNull
private int uid;
#ColumnInfo(name = "word_code")
private int wordCode;
#ColumnInfo(name = "word")
private String word;
public Word(int uid, int wordCode, String word){
this.uid = uid;
this.wordCode = wordCode;
this.word = word;
}
public int getUid(){
return uid;
}
public int getWordCode(){
return wordCode;
}
public String getWord(){
return word;
}
}
My DAO class looks like this:
#Dao
public interface WordDao {
#Insert
void insert(Word word);
#Query("SELECT COUNT(*) FROM word_table WHERE word = :selectedCode")
LiveData<Integer> getWordWithCode(int selectedCode);
}
My class that extends the RoomDatabase looks like this:
#Database(entities = {Word.class}, version = 1, exportSchema = false)
public abstract class WordRoomDatabase extends RoomDatabase {
public abstract WordDao wordDao();
private static WordRoomDatabase INSTANCE;
public static WordRoomDatabase getDatabase(final Context context){
if (INSTANCE == null){
synchronized (WordRoomDatabase.class){
if (INSTANCE==null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), WordRoomDatabase.class, "word_database")
.fallbackToDestructiveMigration()
.addCallback(sDatabasePopulateCallback)
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sDatabasePopulateCallback = new RoomDatabase.Callback(){
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
new PopulateDatabaseAsync(INSTANCE).execute();
}
};
private static class PopulateDatabaseAsync extends AsyncTask<Void, Void, Void> {
private WordDao mWordDao;
PopulateDatabaseAsync(WordRoomDatabase db){
mWordDao = db.wordDao();
}
int[] discCodes = {232, 432, 523,233,242,554,221};
String[] discNames = {"First Word", "Second Word", "Third Word", "Fourth Word", "Fifth Word", "Sixth word", "Seventh Word"};
#Override
protected Void doInBackground(Void... voids) {
for (int i = 0;i < discCodes.length; i++){
Word newWord = new Word(0, discCodes[i], discNames[i]);
mWordDao.insert(newWord);
}
return null;
}
}
}
I am using the discCodes and discNames arrays to populate the list as a sample.
This is what my Repository looks like:
public class WordRepository {
private WordDao mWordDao;
private LiveData<Integer> mCount;
int thiscount;
WordRepository(Application application){
WordRoomDatabase db = WordRoomDatabase.getDatabase(application);
mWordDao = db.wordDao();
}
public void insert(Word word){
new insertWordAsync(mWordDao).execute(word);
}
private static class insertWordAsync extends AsyncTask<Word, Void, Void>{
private WordDao mDao;
insertWordAsync(WordDao dao){
mDao = dao;
}
#Override
protected Void doInBackground(Word... words) {
mDao.insert(words[0]);
return null;
}
}
public LiveData<Integer> getCount(int givenCode){
return mWordDao.getWordWithCode(givenCode);
}
}
This is the ViewModel class:
public class WordViewModel extends AndroidViewModel {
private WordRepository mRepo;
public WordViewModel(#NonNull Application application) {
super(application);
mRepo = new WordRepository(application);
}
public void insert(Word word){
mRepo.insert(word);
}
public LiveData<Integer> getCount(int givenCode){
return mRepo.getCount(givenCode);
}
}
And finally the MainActivity class:
public class MainActivity extends AppCompatActivity {
private WordViewModel mWordViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWordViewModel = ViewModelProviders.of(this).get(WordViewModel.class);
mWordViewModel.getCount(242).observe(this, new Observer<Integer>() {
#Override
public void onChanged(Integer integer) {
String toShow = Integer.toString(integer);
Toast.makeText(getApplicationContext(), toShow, Toast.LENGTH_SHORT).show();
}
});
}
}
Now in this particular example I am using the code 242 as the base of my search. I first tried using a return type of int instead of LiveData, meaning my DAO Query would like like this:
#Query("SELECT COUNT(*) FROM word_table WHERE word = :selectedCode")
int getWordWithCode(int selectedCode);
After some search I figured using LiveData and an Observer is preferable.
However when I run the app, instead of getting 1 in the Toast message, I get 0.
I am new to android development so I apologize for the messy code and for pasting all this code. I have been learning about Room with the Google Codelabs tutorials, so feel free to suggest me any learning resources if having a better understanding of Room will solve my problem.
Thanks in advance!
You are actually searching word instead of wordCode
Try this code in WordDao
#Query("SELECT COUNT(*) FROM word_table WHERE word_code = :selectedCode")
LiveData<Integer> getWordWithCode

save arrayList<Class> as a string inside Room

I am using Room library from jetpack and i want to save my arrayList inside Room database.
I am using typeConverter to convert arrayList into String, but still getting error.
Error Message : Cannot figure out how to save this field into database. You can consider adding a type converter for it.
this is my typeConverter.
public class TypeConverterUtils {
#TypeConverter
public static String fromArray(ArrayList<CropData> arrayList) {
return GsonUtils.toGson(arrayList);
}
}
this is my Database class.
#TypeConverters({TypeConverterUtils.class})
public abstract class CheruvuDatabase extends RoomDatabase {
private static final String DATABASE_NAME = "Cheruvu.db";
public abstract OtpDAO otpDAO();
public abstract FarmerInfoDAO farmerInfoDAO();
// For Singleton instantiation
private static final Object LOCK = new Object();
private static volatile CheruvuDatabase sInstance;
public static CheruvuDatabase getInstance(Context context) {
if (sInstance == null) {
synchronized (LOCK) {
if (sInstance == null) {
context.getApplicationContext().deleteDatabase(CheruvuDatabase.DATABASE_NAME);
sInstance = Room.databaseBuilder(context.getApplicationContext(), CheruvuDatabase.class, CheruvuDatabase.DATABASE_NAME)
.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.build();
}
}
}
return sInstance;
}
}
I want to store this ArrayList.
private ArrayList cropData = new ArrayList<>();
this is my CropData class.
public class CropData {
private String cropName;
private Crop crop;
private Float cropAcres;
private Float cropYield;
private Float cropPrice;
public String getCropName() {
return cropName;
}
public void setCropName(String cropName) {
this.cropName = cropName;
}
public Crop getCrop() {
return crop;
}
public void setCrop(Crop crop) {
this.crop = crop;
}
public Float getCropAcres() {
return cropAcres;
}
public void setCropAcres(Float cropAcres) {
this.cropAcres = cropAcres;
}
public Float getCropYield() {
return cropYield;
}
public void setCropYield(Float cropYield) {
this.cropYield = cropYield;
}
public Float getCropPrice() {
return cropPrice;
}
public void setCropPrice(Float cropPrice) {
this.cropPrice = cropPrice;
}
}
Have you added #Embedded on the ArrayList variable? because you will be needed to Embed the Class, that you want to convert.
for example,
ArrayList<CropData> cropData;
and CropData.class is different. so just add
#Embedded
ArrayList<CropData> cropData;
and your problem will be solved.

Java enum in class: make fields inaccessible & methods accessible

I have a User class with an enum in it:
public class User
{
private int index;
private enum Counter
{
INSTANCE;
private int objects;
protected int getObjects()
{
return objects;
}
protected void setObjects()
{
this.objects++;
}
}
public User(){
this.index = User.Counter.INSTANCE.getObjects();
User.Counter.INSTANCE.setObjects();
}
}
In this class I am still able to do
this.index = User.Counter.INSTANCE.objects; //in public User()
How can I make it so that this line becomes invalid?

How to build chain of responsibility using constructor for initializing next chains?

How to build a chain of responsibility using constructor for initializing chains.
Here is my Runner.class where i'm building my chain using setNext method.
public class Runner {
private static final String ENTER_PATH = "Enter path: ";
private static final String FILTER_BY_NAME = "Filter by name? (0/1)";
private static final String ENTER_NAME_PARAMETER = "Enter name parameter please: ";
private static final String FILTER_BY_EXTENSION = "Filter by extension? (0/1)";
private static final String ENTER_EXTENSION_PARAMETER = "Enter extension please (without '.'): ";
private static final String FILTER_BY_SIZE = "Filter by size? (0/1)";
private static final String ENTER_SIZE_TO = "Enter upper limit searching files in kb";
private static final String ENTER_SIZE_FROM = "Enter lower limit searching files in kb";
private static final String TRUE="1";
private Scanner scanner;
private List<File> fileList;
public Runner() {
this.scanner = new Scanner(System.in);
this.fileList = new ArrayList<>();
}
private String getDirName(){
System.out.println(ENTER_PATH);
return scanner.nextLine();
}
private Handler getChainOfResponsibility(){
GeneralHandler generalHandler = new GeneralHandler();
Handler lastHandler = generalHandler;
System.out.println(FILTER_BY_NAME);
if (scanner.nextLine().equals(TRUE)) {
System.out.println(ENTER_NAME_PARAMETER);
String name = scanner.nextLine();
Handler nameHandler = new NameHandler(name);
lastHandler.setHandler(nameHandler);
lastHandler = nameHandler;
}
System.out.println(FILTER_BY_EXTENSION);
if (scanner.nextLine().equals(TRUE)) {
System.out.println(ENTER_EXTENSION_PARAMETER);
Handler extensionHandler = new ExtensionHandler(scanner.nextLine());
lastHandler.setHandler(extensionHandler);
lastHandler = extensionHandler;
}
System.out.println(FILTER_BY_SIZE);
if (scanner.nextLine().equals(TRUE)) {
System.out.println(ENTER_SIZE_FROM);
double fromSize = scanner.nextDouble();
System.out.println(ENTER_SIZE_TO);
double toSize = scanner.nextDouble();
Handler sizeHandler = new SizeHandler(fromSize, toSize);
lastHandler.setHandler(sizeHandler);
}
return generalHandler;
}
public void run() throws InterruptedException, IOException {
findAllFiles(getDirName(), getChainOfResponsibility());
showListOfFilteredFiles();
}
Here is my Handler abstract class
public abstract class Handler {
private Handler handler;
public void setHandler(Handler handler) {
this.handler = handler;
}
protected abstract boolean handleFilter(File file);
public boolean doFilter(File file){
if(handleFilter(file)){
if(Objects.nonNull(handler)){
return handler.doFilter(file);
}
return true;
}
return false;
}
}
And also i have it's implementation. How to make, that it will be init through constructor! Help pls!
Preamble
Your implementation is wrong; the general way of implementing the Chain of Responsibility pattern is for each link in the chain to forward the request to the next link if it cannot handle the request itself. This is traditionally done by delegating to the abstract super class if the current class cannot handle the request. So in short, to comply with tradition, I would rewrite your Handler class as follows:
public abstract class Handler {
private Handler next;
public void setHandler(Handler next) {
this.next = next;
}
public boolean doFilter(File file) {
return next.doFilter(file);
}
}
I have not read the contract of either your Handler nor NameHandler classes, but I'll just make a few assumptions in order to provide an example of how the NameHandler might look like after refactoring its parent:
public class NameHandler extends Handler {
private final String name;
public NameHandler(String name){
this.name = name;
}
#Override
public boolean doFilter(File file){
final boolean result;
if(file.getName().equals(name)){
result = true;
}else{
result = super.doFilter(file);
}
return result;
}
}
Answer
Use constructors to configure the next link in the chain as opposed to "setters" like your setHandler method:
public abstract class Handler {
private final Handler next;
public Handler(Handler next){
this.next = next;
}
public boolean doFilter(File file){
return next.doFilter(file);
}
}
Now your subclasses are required to deal with the non-default constructor:
public class NameHandler extends Handler {
private final String name;
public NameHandler(String name, Handler next){
super(next);
this.name = name;
}
#Override
public boolean doFilter(File file){
final boolean result;
if(file.getName().equals(name)){
result = true;
}else{
result = super.doFilter(file);
}
return result;
}
}

Categories