How to properly use Executer In Room Android

Viewed 544

So I am relatively new to programming, and I have been working on this task app, where I want to save the data such as task name and more, given by the user. I am trying to accomplish this using Room. Now, initially, when I tried to do it, the app would crash since I was doing everything on the main thread probably. So, after a little research, I came to AsyncTask, but that is outdated. Now finally I have come across the Executer. I created a class for it, but I am a little unsure as to how I can implement it in my app. This is what I did :

Entity Class :

@Entity (tableName = "subtasks")
public class SubtaskDetails {
    @PrimaryKey(autoGenerate = true)
    private int id;
    @ColumnInfo(name = "subtaskName")
    private String subtasksName;
    @ColumnInfo(name = "priority")
    private boolean priHigh;
    private boolean priMed;
    private boolean priLow;
    @ColumnInfo(name = "time")
    private boolean timeMore;
    private boolean timeMed;
    private boolean timeLess;

    public SubtaskDetails(String subtasksName, boolean priHigh, boolean priMed, boolean priLow, boolean timeMore, boolean timeMed, boolean timeLess){

        this.subtasksName = subtasksName;
        this.priHigh = priHigh;
        this.priMed = priMed;
        this.priLow = priLow;
        this.timeMore = timeMore;
        this.timeMed = timeMed;
        this.timeLess = timeLess;


    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getSubtasksName() {
        return subtasksName;
    }

    public void setSubtasksName(String subtasksName) {
        this.subtasksName = subtasksName;
    }

    public boolean isPriHigh() {
        return priHigh;
    }

    public void setPriHigh(boolean priHigh) {
        this.priHigh = priHigh;
    }

    public boolean isPriMed() {
        return priMed;
    }

    public void setPriMed(boolean priMed) {
        this.priMed = priMed;
    }

    public boolean isPriLow() {
        return priLow;
    }

    public void setPriLow(boolean priLow) {
        this.priLow = priLow;
    }

    public boolean isTimeMore() {
        return timeMore;
    }

    public void setTimeMore(boolean timeMore) {
        this.timeMore = timeMore;
    }

    public boolean isTimeMed() {
        return timeMed;
    }

    public void setTimeMed(boolean timeMed) {
        this.timeMed = timeMed;
    }

    public boolean isTimeLess() {
        return timeLess;
    }

    public void setTimeLess(boolean timeLess) {
        this.timeLess = timeLess;
    }
}

Dao Class:

@Dao
public interface UserDao {

    @Query("Select * from subtasks")
    List<SubtaskDetails> getSubtaskDetailsList();
    @Insert
    void insertSubtaskDetails(SubtaskDetails subtaskDetails);
    @Update
    void updateSubtaskDetails(SubtaskDetails subtaskDetails);
    @Delete
    void deleteSubtaskDetails(SubtaskDetails subtaskDetails);

}

App Database Class :

@Database(entities = SubtaskDetails.class, exportSchema = false, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    private static final String DB_NAME = "subtaskdetails_db";
    private static AppDatabase instance;

    public static synchronized AppDatabase getInstance(Context context){
        if (instance == null){
            instance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DB_NAME).fallbackToDestructiveMigration().build();
        }
        return instance;
    }

    public abstract UserDao subtaskdetailsdao();

    }

Executer Class :

public class AppExecutors {

    // For Singleton instantiation
    private static final Object LOCK = new Object();
    private static AppExecutors sInstance;
    private final Executor diskIO;
    private final Executor mainThread;
    private final Executor networkIO;

    private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
        this.diskIO = diskIO;
        this.networkIO = networkIO;
        this.mainThread = mainThread;
    }

    public static AppExecutors getInstance() {
        if (sInstance == null) {
            synchronized (LOCK) {
                sInstance = new AppExecutors(Executors.newSingleThreadExecutor(),
                        Executors.newFixedThreadPool(3),
                        new MainThreadExecutor());
            }
        }
        return sInstance;
    }

    public Executor diskIO() {
        return diskIO;
    }

    public Executor mainThread() {
        return mainThread;
    }

    public Executor networkIO() {
        return networkIO;
    }

    private static class MainThreadExecutor implements Executor {
        private Handler mainThreadHandler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {
            mainThreadHandler.post(command);
        }
    }
}

Where I try to implement it : (I have written a comment where I do it)

public class TaskInfo extends AppCompatActivity {

    //Declaring variables
    EditText etWorkingHours, etWorkingMinutes, etTaskName, etWorkingMins, etWorkinghrs, etSubtaskName;
    Button btnNewSubtask;
    Button btnSaveTaskName;
    Button btnProceed;
    ImageView ivLeft, ivRight;
    TextView tvBreakTime;
    TextView tvTaskName;
    int breaktime = 10;
    final int ENTER_SUBTASK = 20;
    final int EDIT_SUBTASK = 40;
    ListView lvSubtasks;
    ArrayList<subtask> subtaskList = new ArrayList<>();
    ScrollView scrollView;







    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_task_info);



        //Connecting XML to JAVA
        etWorkingHours = findViewById(R.id.etWorkingHours);
        etWorkingMinutes = findViewById(R.id.etWorkingMinutes);
        etTaskName = findViewById(R.id.etTaskName);
        btnNewSubtask = findViewById(R.id.btnNewSubtask);
        ivLeft = findViewById(R.id.ivLeft);
        ivRight = findViewById(R.id.ivRight);
        tvBreakTime = findViewById(R.id.tvBreakTime);
        etWorkinghrs = findViewById(R.id.etWorkingHrs);
        etWorkingMins = findViewById(R.id.etWorkingMins);
        lvSubtasks = findViewById(R.id.lvSubtasks);
        scrollView = findViewById(R.id.scrollView);
        btnSaveTaskName = findViewById(R.id.btnSaveTask);
        tvTaskName = findViewById(R.id.tvTaskName);
        btnProceed = findViewById(R.id.btnProceed);



        tvTaskName.setVisibility(View.INVISIBLE);

        if (tvTaskName.getText().equals(""))
        {
            tvTaskName.setClickable(false);
        }
        else
        {
            tvTaskName.setClickable(true);
        }


// Code for the left right arrows along with break duration
        ivRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (breaktime >= 10 && breaktime < 60)
                {breaktime += 5;
                    String time = breaktime + "";
                    tvBreakTime.setText(time);}

                else
                {
                    String time = breaktime + "";
                    tvBreakTime.setText(time);
                }
            }
        });

        ivLeft.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (breaktime > 10 && breaktime <= 60)
                {
                    breaktime -= 5;
                    String time = breaktime + "";
                    tvBreakTime.setText(time);}

                else
                {
                    String time = breaktime + "";
                    tvBreakTime.setText(time);
                }
            }
        });


        btnNewSubtask.setEnabled(false);
        btnSaveTaskName.setEnabled(false);

        //save button enabler when task name is written

        etTaskName.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }



            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

                btnSaveTaskName.setEnabled(!TextUtils.isEmpty(s.toString().trim()));
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });




        btnSaveTaskName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tvTaskName.setVisibility(View.VISIBLE);
                tvTaskName.setText(etTaskName.getText().toString().toUpperCase().trim());
                etTaskName.setVisibility(View.GONE);
                btnSaveTaskName.setVisibility(View.GONE);
                btnNewSubtask.setEnabled(true);
            }
        });


        tvTaskName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String tasksname = tvTaskName.getText().toString().trim();
                tvTaskName.setText("");
                etTaskName.setVisibility(View.VISIBLE);
                etTaskName.setText(tasksname);
                btnSaveTaskName.setVisibility(View.VISIBLE);
            }
        });



        btnNewSubtask.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent i2 = new Intent(TaskInfo.this, SubtaskActivity.class);
                startActivityForResult(i2, ENTER_SUBTASK);
                overridePendingTransition(R.anim.slide_in_up, R.anim.slide_out_up);

            }
        });


        btnProceed.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                if (etWorkingHours.getText().toString().isEmpty())
                {
                    etWorkingHours.setText("0");
                }
                if (etWorkingMinutes.getText().toString().isEmpty())
                {
                    etWorkingMinutes.setText("0");
                }
                if (etWorkinghrs.getText().toString().isEmpty())
                {
                    etWorkinghrs.setText("0");
                }
                if (etWorkingMins.getText().toString().isEmpty())
                {
                    etWorkingMins.setText("0");
                }

                int working_hours = Integer.parseInt(etWorkinghrs.getText().toString().trim());
                int working_minutes = Integer.parseInt(etWorkingMins.getText().toString().trim());
                int without_break_hours = Integer.parseInt(etWorkingHours.getText().toString().trim());
                int without_break_minutes = Integer.parseInt(etWorkingMinutes.getText().toString().trim());




                if (etWorkingHours.getText().toString().isEmpty() || etWorkingMinutes.getText().toString().isEmpty() || etWorkinghrs.getText().toString().isEmpty() || etWorkingMins.getText().toString().isEmpty())
                {
                    Toast.makeText(TaskInfo.this, "Field cannot be empty, please try again.", Toast.LENGTH_SHORT).show();

                }
                else
                {
                    if (working_hours != 0)
                    {
                        if (working_hours > without_break_hours)
                        {
                            int breaktime = Integer.parseInt(tvBreakTime.getText().toString());
                            Intent intent = new Intent(TaskInfo.this, TaskSummary.class);
                            intent.putExtra("working_hours", working_hours);
                            intent.putExtra("working_minutes", working_minutes);
                            intent.putExtra("without_break_hours", without_break_hours);
                            intent.putExtra("without_break_minutes", without_break_minutes);
                            intent.putExtra("break_duration", breaktime);
                            startActivity(intent);
                        }

                        if (working_hours == without_break_hours){

                            if (working_minutes >= without_break_minutes){
                                int breaktime = Integer.parseInt(tvBreakTime.getText().toString());
                                Intent intent = new Intent(TaskInfo.this, TaskSummary.class);
                                intent.putExtra("working_hours", working_hours);
                                intent.putExtra("working_minutes", working_minutes);
                                intent.putExtra("without_break_hours", without_break_hours);
                                intent.putExtra("without_break_minutes", without_break_minutes);
                                intent.putExtra("break_duration", breaktime);
                                startActivity(intent);
                            }

                            if (working_minutes < without_break_minutes){

                                Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();

                            }



                        }

                        if (working_hours < without_break_hours){
                            Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();
                        }

                    }

                    if (working_hours == 0){

                        if (without_break_hours == 0)
                        {

                            if (working_minutes >= without_break_minutes){
                                int breaktime = Integer.parseInt(tvBreakTime.getText().toString());
                                Intent intent = new Intent(TaskInfo.this, TaskSummary.class);
                                intent.putExtra("working_hours", working_hours);
                                intent.putExtra("working_minutes", working_minutes);
                                intent.putExtra("without_break_hours", without_break_hours);
                                intent.putExtra("without_break_minutes", without_break_minutes);
                                intent.putExtra("break_duration", breaktime);
                                startActivity(intent);
                            }

                            if (working_minutes < without_break_minutes){

                                Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();

                            }

                        }

                        if (without_break_hours != 0)
                        {
                            Toast.makeText(TaskInfo.this, "Invalid Time Entered", Toast.LENGTH_SHORT).show();
                        }
                    }
                }





            }
        });


        //Applying the max min thing for which the class InputFilterMinMax is defined
        etWorkingHours.setFilters(new InputFilter[]{new InputFilterMinMax("0", "24")});
        etWorkingMinutes.setFilters(new InputFilter[]{new InputFilterMinMax("0", "59")});

        etWorkinghrs.setFilters(new InputFilter[]{new InputFilterMinMax("0", "24")});
        etWorkingMins.setFilters(new InputFilter[]{new InputFilterMinMax("0", "59")});


    }







// This is where I try to implement the executer : 


    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == ENTER_SUBTASK)
        {
            if (resultCode == RESULT_OK)
            {

                SubtaskAdapter adapter = new SubtaskAdapter(this, subtaskList);
                assert data != null;
                String subtaskName = data.getStringExtra("subtaskName");
                boolean priHigh = data.getBooleanExtra("priHigh", false);
                boolean priMed = data.getBooleanExtra("priMed", false);
                boolean priLow = data.getBooleanExtra("priLow", false);
                boolean timeMore = data.getBooleanExtra("timeMore", false);
                boolean timeMed = data.getBooleanExtra("timeMed", false);
                boolean timeLess = data.getBooleanExtra("timeLess", false);
                AppDatabase appDb = AppDatabase.getInstance(this);
                AppExecutors.getInstance().diskIO().execute(new Runnable() {
                    @Override
                    public void run() {
                        SubtaskDetails subtaskDetails = new SubtaskDetails(subtaskName,priHigh, priMed, priLow, timeMore, timeMed, timeLess);
                        appDb.subtaskdetailsdao().insertSubtaskDetails(subtaskDetails);


                    }
                });

                lvSubtasks.setAdapter(adapter);
                subtask subtask = new subtask(subtaskName, priHigh, priMed, priLow, timeMore, timeMed, timeLess);
                subtaskList.add(subtask);
                adapter.addANewSubTask(subtask);



            }








        }


    }






















    // Menu (action bar) code
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {

        switch (item.getItemId())
        {
            case (R.id.settings):
                startActivity(new Intent(this, SettingsActivity.class));
                break;
        }
        return super.onOptionsItemSelected(item);
    }


    //Class to make max and min value on the edit text of hours and minutes, so that they cant enter anything more than 24 hours, and 59 minutes
    static class InputFilterMinMax implements InputFilter {

        private int min, max;

        public InputFilterMinMax(int min, int max) {
            this.min = min;
            this.max = max;
        }

        public InputFilterMinMax(String min, String max) {
            this.min = Integer.parseInt(min);
            this.max = Integer.parseInt(max);
        }

        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            try {
                int input = Integer.parseInt(dest.toString() + source.toString());
                if (isInRange(min, max, input))
                    return null;
            } catch (NumberFormatException nfe) { }
            return "";
        }

        private boolean isInRange(int a, int b, int c) {
            return b > a ? c >= a && c <= b : c >= b && c <= a;
        }
    }






}

EDIT :

I implemented the code, but I am facing a few issues in the viewmodel class. For eg, the parameter in repository.insertSubtaskDetails(userDao); is userDao, but it actually it requires of type subtaskDetails.. some errors in the todo part as well. this is the code:

package com.example.taskmasterv3;

import android.app.Application;

import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;

import java.util.List;

public class ViewModel extends AndroidViewModel {
    private Repository repository;
    private List<SubtaskDetails> subtaskDetails;


    public ViewModel(@NonNull Application application) {
        super(application);
        repository = new Repository(application);
        subtaskDetails = repository.getSubtaskDetails();
    }

    public void insert(UserDao userDao) {
        repository.insertSubtaskDetails(userDao);
    }

    public void delete(Todo todo) {
        repository.deleteSubtaskDetails(userDao);
    }
}
1 Answers

First make a Repository class and make an instance of your DAO

public class Repository {
private UserDAO userDAO;
private List<SubtaskDetails> subtaskDetails;
private Executor executor = Executors.newSingleThreadExecutor();


public Repository(Application application){
    AppDatabase appDatabase = AppDatabase.getInstance(application);
    userDAO = appDatabase.userDAO();
    subtaskDetails = userDAO.getSubtaskDetailsList();
}

Then wrap it around your executor

    public void insertSubtaskDetails(SubtaskDetails subtaskDetails){
    executor.execute(new Runnable() {
        @Override
        public void run() {
            userDAO.insertSubtaskDetails(subtaskDetails);

        }
    });
}// For inserting

  public void deleteSubtaskDetails(SubtaskDetails subtaskDetails){
    executor.execute(new Runnable() {
        @Override
        public void run() {
            userDAO.deleteSubtaskDetails(subtaskDetails);

        }
    });
}// for deleting 

Basically just wrap your DAO queries around the executor.

Related