22

I'm having a hard time correctly implementing a 'favorites' feature for my app. Moving through a list of objects, the user should be able to check/uncheck something as a favorite. Once the activity moves into the onPause(); state, it should save the list of favorites (rather, the complete list of boolean markers that signal whether something is a favorite or not... true for favorite, false for not a favorite.) Obviously, upon moving into the onResume(); state, the list should be loaded so they can view the favorites that they've previously marked.

My issue, I think, truly comes from the fact that the list is randomized upon initialization. I'm sure my algorithm is off, but I've tried various ways to the point where I can hardly bare to look at it anymore.

Main Activity Java

public class MainActivity extends ActionBarActivity {


Global global_main;


@Override
protected void onCreate(Bundle savedInstanceState) {

    global_main = Global.getInstance("all");

}



@Override
protected void onResume(){
    super.onResume();


    SharedPreferences settings = getSharedPreferences(FILE_FAVORITES, 0);

    for(int index = 0; index < TOTAL_QUESTIONS; index++){

        boolean favFromFile = settings.getBoolean(("savedFavorite_" + String.valueOf(index)), false);
        global_main.setFav(index, favFromFile);

    }

}



@Override
protected void onPause(){
    super.onPause();

    SharedPreferences settings = getSharedPreferences(FILE_FAVORITES, 0);
    SharedPreferences.Editor editor = settings.edit();

    for(int index = 0; index < TOTAL_QUESTIONS; index++){
        editor.putBoolean(("savedFavorite_" + String.valueOf(index)), global_main.getFav(index));

        // Commit the edits!
        editor.commit();
    }

}

Practice Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent intent = getIntent();
    selectedSection = intent.getStringExtra(chooseSection.chosenSection);

    global = Global.getInstance(selectedSection);

}

Global Class

public class Global {


private static Global global = null;

//Current total of questions which the user has chosen
//EX: if Multiplication was chosen and has 10 questions in the array
//Then this equals 10
int CURRENT_TOTAL;

//This is the position that the first question of the user's choice starts with
//EX: If user chooses Multiplication, and the multiplication questions start at questions[19];
//Then this equals 19
int CURRENT_START;

//This is the position that the last question of the user's choice ends with
//EX: If user chooses Multiplication, and the multiplication questions end at questions[24];
//Then this equals 24
int CURRENT_END;


//Basic question structure
class questionStruct
{

    String q;
    String a;
    int position; //original position in the array;
    boolean favorite;

}

//Array of question structures
questionStruct[] questions = new questionStruct[TOTAL_QUESTIONS];


//userChoice is the choice of question type that the user has selected.
//EX: Multiplication, Division, Addition, Subtraction, or All/Default
public static Global getInstance(String userChoice) {
    if(global == null)
    {
        global = new Global();
        global.initialize();
    }

    global.getChoice(userChoice);
    global.setQuestionsDefault();
    global.randomize();
    return global;

}


public void initialize() {
    for (int i = 0; i < TOTAL_QUESTIONS; i++) {
        questions[i] = new questionStruct();
    }

    questions[0].q = "Question 1 Text";
    questions[0].a = "Answer";
    questions[0].position = 0;
    questions[1].q = "Question 2 Text";
    questions[1].a = "Answer";
    questions[1].position = 1;
    questions[2].q = "Question 3 Text";
    questions[2].a = "Answer";
    questions[2].position = 2;
    ....ETC.
    ....ETC.
    ....ETC.
}


public void setQuestionsDefault(){

    questionStruct temp = new questionStruct();

    for(int index = 0; index < TOTAL_QUESTIONS; index++){

        int count = questions[index].position;

        temp = questions[count];
        questions[count] = questions[index];
        questions[index] = temp;

        temp = null;
    }
}


//Randomize the questions only within the range of the category
//which the user has chosen
public void randomize(){


    for(int index = CURRENT_END; index >= CURRENT_START; index --)
    {
        //Generate random number to switch with random block
        Random rand = new Random();
        int currentQ = rand.nextInt((CURRENT_END - CURRENT_START) + 1) + CURRENT_START;


        //Switch two Question blocks
        questionStruct temp = questions[currentQ];
        questions[currentQ] = questions[index];
        questions[index] = temp;


    }
}



public void setFav(int q, boolean b){
    questions[q].favorite = b;
}


public boolean getFav(int q){
    return questions[q].favorite;
}

That MIGHT be everything pertinent to my issues. I apologize if I left anything out or if something doesn't make sense. Feel free to ask questions. I'm still currently in the middle of altering everything to get it to work, so I might have copied over something that doesn't quite add up.

EDIT: I'll also add the code for the "favorite" button click to turn a favorite into a non-favorite and vise versa. Even though it's critical to having this work, it's not something I was worried about functioning properly because it's so simple. But, if someone feels they'd like to see it, and in turn help me out, then here it is.

This is also in the Practice Questions Java file:

public void setFavoriteButton(){
    if(global.getFav(tempQQ)){
        FAVORITE.setBackgroundColor(Color.YELLOW);
    }
    else{
        FAVORITE.setBackgroundColor(getResources().getColor(R.color.primary));
    }
}


@Override
public void onClick(View v){

    switch(v.getId()){

        case R.id.favorite:
            updateFavorite();
            break;
    }
}


public void updateFavorite(){

    if(global.getFav(tempQQ)){
        global.setFav(tempQQ, false);
    }
    else{
        global.setFav(tempQQ, true);
    }

    setFavoriteButton();
}

EDIT: I might should add that I believe the issue is algorithmic. If I didn't have the "randomize" feature in conjunction with the favorites, I'd be fine I think. But I think both are important for my app to be very useful. So that's where my focus is at, trying to implement a favorites feature at the same time while keeping the randomization each time the Global is called.

Carrie Kendall
  • 11,124
  • 5
  • 61
  • 81
lilgodwin
  • 1,098
  • 3
  • 13
  • 26
  • 3
    if you randomize the list of question, you can't base the favorite selection on the index in the list. You need an identifier for your questions. – njzk2 Apr 23 '15 at 14:19
  • that's a good advice, you could also consider putting everything in the database, so you could do some sorting etc – Chaosit Apr 23 '15 at 14:23
  • I've taken a hiatus for a few weeks, and so my response may not reflect the best understanding at this point, but here goes. I believe that what I intended to do (not sure if I did it correctly though at this point) is to load the list of checked favorites upon opening the app. If the list exists, apply the list to the questions in order. If it doesn't exist, then fill the markers with "false" to indicate that none of them are favorites yet. Anytime a question is marked as a favorite, the marker should be set to true. And anytime the app/activity goes into `onPause()` the markers are saved – lilgodwin Apr 23 '15 at 14:24
  • @Chaosit can you explain? I suppose something I didn't mention is that "saving" in general completely escapes me. I've tried picking up a few implementations here and there and try to get it to work. Upon testing, It proved to work. I was able to get a default value upon the first time opening the app, then upon closing the app, save a certain value, then that value appears the next time the app is open. Beyond that, I don't think I know how to "save" and "load" properly. I was just happy to get that to work. – lilgodwin Apr 23 '15 at 14:26
  • are you using check box in list items of list view? – Amrut Bidri Apr 23 '15 at 14:30
  • 1
    Basically what I am suggesting is just an addition to @njzk2 answer. I would create a local SQLite database with your questions, having columns ID, QUESTION, FAVORITE in table of questions. – Chaosit Apr 23 '15 at 14:31
  • @Chaosit oh ok. I've seen people mention SQL but i'm not familiar with it even in the slightest. I suppose I can attempt to figure it out, but it won't require me learning another language will it? Sorry if that's a stupid question but I really have no idea what it is at this point. – lilgodwin Apr 23 '15 at 14:32
  • @ScionofIkshvaku No? If you mean for the favorite feature, it's just a button. If the button is clicked, it checks to see if the favorites value for that question is true or false. If then turns it into the opposite value. – lilgodwin Apr 23 '15 at 14:34
  • @lilgodwin then you definitely need a fixed identifier for each question, no matter how much you randomize your questions – Amrut Bidri Apr 23 '15 at 14:38
  • @lilgodwin well it will require learning basics of SQLite, but anyway your case won't require writing any kind of complex queries and there is a library called [ORMLite](http://ormlite.com/sqlite_java_android_orm.shtml) which makes working with database really easy – Chaosit Apr 23 '15 at 14:38
  • @ScionofIkshvaku thanks for the advice, I'll definitely try to look into that, but like I said, I'm a bit rusty due to leaving it for a few weeks. So, I'm not really sure how to do what you're suggesting. – lilgodwin Apr 23 '15 at 14:53

2 Answers2

15

I really suggest you to use a more Object-oriented approach to handle your model.

You can create the model class Quiz, that will probably looks like this:

class Quiz{

    private boolean favorite;
    private String question;
    private String answer;

    public Quiz(String question, String answer){
        this.question = question;
        this.answer = answer;
    }

    public boolean isFavorite() {
        return favorite;
    }

    public void setFavorite(boolean favorite) {
        this.favorite = favorite;
    }

    //... 
}

In this way, you can create a list of Quiz and do shuffle, ordering, check for favorite and so on:

    //Create the list of questions
    ArrayList<Quiz> myQuiz = new ArrayList<Quiz>();
    myQuiz.add(new Quiz("Question?", "Ansewer!"));
    //...

    //Shuffle all!
    Collections.shuffle(myQuiz);

    //Iterate and check for favorites
    for(Quiz q : myQuiz){
       if(q.isFavorite()){
          //this is favorite!
       }
    }

Regarding the persistence of the data, you can consider an SQLite approach, or simply serialize your list and save it in your SharedPreference.

Community
  • 1
  • 1
bonnyz
  • 13,458
  • 5
  • 46
  • 70
2

As I believe you are storing your favorites state in your questionStruct class, you don't need to restore your favorites state in your onResume(), you can keep it in onCreate().

As @bonnyz has answered, you can use Collections.shuffle(myQuiz); to shuffle your items in onResume() and refresh your Adapter with notifyDataSetChanged().

Dhruv
  • 1,129
  • 2
  • 13
  • 32