1
我有一個類顯示屬於自定義對象的一些數據值,這些對象是通過主類中的一個intent傳遞的。當我改變方向時,一切都會改變,因爲它只是回到了課堂的意圖。Android:更改定位對象後刪除的自定義對象
但是,用戶可以編輯對象並返回到類,並且更改可見。在編輯對象後更改方向時,它將恢復爲原始意圖。
我已經嘗試創建一個onSaveInstanceState以及一個onRestoreInstanceState以防止第一個intent的調用,但它不能正常工作。
這裏是我遇到問題的類的代碼:
import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.Arrays;
import java.util.List;
public class RecipeTextView extends AppCompatActivity {
private TextView mRecipeName;
private TextView mServings;
private TextView mCookTime;
private TextView mPrepTime;
private TextView mDirections;
private TextView mIngredients;
private Button mEditButton;
private int REQUEST_CODE = 1;
Recipe selectedRecipe = new Recipe();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//selectedRecipe = savedInstanceState.getParcelable("savedRecipes");
selectedRecipe = getIntent().getExtras().getParcelable("view_recipe_key");
loadActivity(selectedRecipe);
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putParcelable("savedRecipes", selectedRecipe);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Recipe restoreRecipe = savedInstanceState.getParcelable("savedRecipes");
loadActivity(restoreRecipe);
}
protected void loadActivity(final Recipe selectedRecipe){
setContentView(R.layout.activity_recipe_text_view);
mRecipeName = (TextView) findViewById(R.id.recipe_name_text_view);
mRecipeName.setText(selectedRecipe.getRecipeName());
mServings = (TextView) findViewById(R.id.serving_text_view);
if(selectedRecipe.getServings() != null && selectedRecipe.getServings() != "") {
mServings.setText(selectedRecipe.getServings());
}
mPrepTime = (TextView) findViewById(R.id.prep_time_text_view);
if(selectedRecipe.getPrepTime() != null && selectedRecipe.getPrepTime() != "") {
mPrepTime.setText("Prep time: " + selectedRecipe.getPrepTime() + " minutes");
}
mCookTime = (TextView) findViewById(R.id.cook_time_text_view);
if(selectedRecipe.getCookTime() != null && selectedRecipe.getCookTime() != "") {
mCookTime.setText("Cook time: " + selectedRecipe.getCookTime() + " minutes");
}
//Below code builds a string concatenating a bullet to each line followed by a new line
//Each line is an index of the directions arraylist
List<String> ingredientsList = selectedRecipe.getIngredients();
int ingredientsSize = ingredientsList.size();
String ingredientsConcat = "";
for(int i = 0; i < ingredientsSize; i++){
ingredientsConcat += "\u2022 " + ingredientsList.get(i) + "\n";
}
mIngredients = (TextView) findViewById(R.id.ingredients_text_view);
if(ingredientsConcat.equals("\u2022 " + "\n") == false) {
mIngredients.setText(ingredientsConcat);
}
//This code does almost the same as above for the directions, except it appends a number
//to each line instead of a bullet.
List<String> directionsList = selectedRecipe.getDirections();
int directionsSize = directionsList.size();
String directionsConcat = "";
for(int i = 0; i < directionsSize; i++){
directionsConcat += (i + 1) + ". " + directionsList.get(i) + "\n";
}
mDirections = (TextView) findViewById(R.id.directions_text_view);
if(directionsConcat.equals("1. \n") == false) {
mDirections.setText(directionsConcat);
}
mEditButton = (Button) findViewById(R.id.edit_recipe_button);
mEditButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(RecipeTextView.this, EditRecipe.class);
i.putExtra("passed_recipe_key", selectedRecipe);
startActivityForResult(i, REQUEST_CODE);
}
});
}
@Override
//This is called when the user is finished EDITING the recipe chosen.
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE){
if(resultCode == Activity.RESULT_OK) {
Recipe editedRecipe = (Recipe) data.getExtras().getParcelable("recipe_key");
//Since the user is returned to this class and not RecipeList, we want to make sure that the appropriate
//list inside the list of recipes. This is only necessary here since creating a new recipe returns the user to the recipe list.
RecipeList classObject = new RecipeList();
classObject.updateList(editedRecipe);
this.loadActivity(editedRecipe);
}
}
}
}
以下是編輯類的代碼:
import android.app.Activity;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.Selection;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
//This class is used to edit a recipe. Editing includes both creating a new recipe and editing an existing one
//The edit and create button are in RecipeTextView (Edit) and RecipeList (Create)
//TODO: Change passes to Parcelable
public class EditRecipe extends AppCompatActivity {
private final String TAG = "myApp";
private EditText mRecipeName;
private EditText mServings;
private EditText mPrepTime;
private EditText mIngredients;
private EditText mDirections;
private Button mSaveButton;
private EditText mCookTime;
private int REQUEST_CODE = 1;
//These are declared here so that I can use them within each edit text listener, and then set them to the values
//of the recipe object when the save button is pushed.
private String recipeName;
private String prepTime;
private String cookTime;
private String servings;
//For directions and ingredients, we will seperate these into a list of strings by \n (new line).
private String directions;
private String ingredients;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate() called");
setContentView(R.layout.activity_edit_recipe);
final Recipe passedRecipe = (Recipe) getIntent().getExtras().getParcelable("passed_recipe_key");
mRecipeName = (EditText) findViewById(R.id.recipe_name_text_edit);
mPrepTime = (EditText) findViewById(R.id.prep_time_edit_text);
mCookTime = (EditText) findViewById(R.id.cook_time_edit_text);
mServings = (EditText) findViewById(R.id.serving_edit_text);
mIngredients = (EditText) findViewById(R.id.ingredients_edit_text);
mDirections = (EditText) findViewById(R.id.directions_edit_text);
mSaveButton = (Button) findViewById(R.id.save_edit_recipe_button);
//The following if statements will only be triggered if this class is accessed from editing an
//already existing recipe. Otherwise a new recipe is created.
if(passedRecipe.getRecipeName() != null){
mRecipeName.setText(passedRecipe.getRecipeName(), TextView.BufferType.EDITABLE);
recipeName = passedRecipe.getRecipeName();
}
if(passedRecipe.getPrepTime() != null){
mPrepTime.setText(passedRecipe.getPrepTime(), TextView.BufferType.EDITABLE);
prepTime = passedRecipe.getPrepTime();
}
if(passedRecipe.getCookTime() != null){
mCookTime.setText(passedRecipe.getCookTime(), TextView.BufferType.EDITABLE);
cookTime = passedRecipe.getCookTime();
}
if(passedRecipe.getServings() != null){
mServings.setText(passedRecipe.getServings(), TextView.BufferType.EDITABLE);
servings = passedRecipe.getServings();
}
//For the array list values, we check if the array list is empty
//If it isn't empty, we save each value of the array list into a string concatenated with a new line
//We then set that string as the new line
if(passedRecipe.getIngredients() != null){
String passedIngredientString = "";
for(int i = 0; i < passedRecipe.getIngredients().size(); i++){
passedIngredientString += passedRecipe.getIngredients().get(i) + "\n";
}
mIngredients.setText(passedIngredientString, TextView.BufferType.EDITABLE);
ingredients = passedIngredientString;
}
if(passedRecipe.getDirections() != null){
String passedDirectionString = "";
for(int i = 0; i < passedRecipe.getDirections().size(); i++){
passedDirectionString += passedRecipe.getDirections().get(i) + "\n";
}
mDirections.setText(passedDirectionString, TextView.BufferType.EDITABLE);
directions = passedDirectionString;
}
//In the following Listeners I use .trim at the end to get rid of white space users tend to leave
//For the integer values I first store the data in a string then parse it to an int.
mRecipeName.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) {
recipeName = mRecipeName.getText().toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
}
});
mPrepTime.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) {
prepTime = mPrepTime.getText().toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
}
});
mServings.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) {
servings = mServings.getText().toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
}
});
mCookTime.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) {
cookTime = mCookTime.getText().toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
}
});
mDirections.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) {
//For now we will save this in a string, then seperate each line into an array list.
directions = mDirections.getText().toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
}
});
mIngredients.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) {
//For now we will save this in a string, then seperate each line into an array list.
ingredients = mIngredients.getText().toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
}
});
//TODO
mSaveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//If statement to make sure the recipe name exists. Every other value can be empty
//if the user wishes
if (TextUtils.isEmpty(recipeName)){
mRecipeName.setError("Recipe name can not be empty.");
return;
}
if (recipeName != null) {
passedRecipe.setRecipeName(recipeName);
}
if(cookTime != null) {
passedRecipe.setCookTime(cookTime);
}
if(prepTime != null) {
passedRecipe.setPrepTime(prepTime);
}
if (servings != null) {
passedRecipe.setServingSize(servings);
}
List<String> directionsList = new ArrayList<String>();
List<String> ingredientsList = new ArrayList<String>();
//Check if the edit text strings are null. if they are, add an empty string to each list
//If they aren't null, check if they are multi lined.
//If multi lined, save into a list split by new line. Otherwise, it is just one string. Add it to the list
if (directions != null){
if(directions.contains("\n")) {
directionsList = Arrays.asList(directions.split("\n"));
}
else{
directionsList = Arrays.asList(directions);
}
}
else{
directionsList.add("");
}
if (ingredients != null){
if(ingredients.contains("\n")) {
ingredientsList = Arrays.asList(ingredients.split("\n"));
}
else{
ingredientsList = Arrays.asList(ingredients);
}
}
else{
ingredientsList.add("");
}
passedRecipe.setDirections(directionsList);
passedRecipe.setIngredients(ingredientsList);
Intent returnIntent = new Intent(EditRecipe.this, RecipeList.class);
returnIntent.putExtra("recipe_key", passedRecipe);
setResult(Activity.RESULT_OK, returnIntent);
finish();
}
});
}
}
和公正的情況下,它相關的代碼主類:
import android.app.Activity;
import android.content.Intent;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import java.util.ArrayList;
public class RecipeList extends AppCompatActivity{
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private int REQUEST_CODE=1;
ArrayList<Recipe> recipes = new ArrayList<>();
//TODO: Create a new taskbar
//TODO: Test the new onSaveInstanceState
//TODO: Create a navigaton bar.
//BUG: When pressing backbutton on textView after editing the data is deleted and it goes back to the list.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null){
recipes = savedInstanceState.getParcelableArrayList("savedRecipes");
}
setContentView(R.layout.activity_recipe_list);
mRecyclerView = (RecyclerView) findViewById(R.id.list_recycler_view);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MyAdapter(recipes);
mRecyclerView.setAdapter(mAdapter);
//This button creates a new empty Recipe object and passes it to the EditRecipe class
//The Recipe object is passed as a parcelable
Button mCreateRecipeButton = (Button) findViewById(R.id.create_new_recipe_button);
mCreateRecipeButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
//Create a new empty recipe to be passed to the EditRecipe class
Recipe passedRecipe = new Recipe();
Intent i = new Intent(RecipeList.this, EditRecipe.class);
i.putExtra("passed_recipe_key", (Parcelable) passedRecipe);
startActivityForResult(i, REQUEST_CODE);
}
});
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState){
savedInstanceState.putParcelableArrayList("savedRecipes", recipes);
}
//protected void onRestoreInstanceState(Bundle)
@Override
protected void onResume(){
super.onResume();
}
//This code is called after creating a new recipe. This is only for creating, and not editing.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE){
if(resultCode == Activity.RESULT_OK) {
Recipe editedRecipe = data.getExtras().getParcelable("recipe_key");
recipes.add(editedRecipe);
mAdapter.notifyDataSetChanged();
}
}
}
//This will be called from RecipeTextView after a user edits a recipe they chose. When a new reicpe is
//created, the user returns here. When a recipe is edited, the user returns to that text view. But
//The recipe still needs to be updated within this list (Yay consistency!)(Holy cow Google has spell check in comments...the future is now.)(Hire me I'm comical and write overly long comments.)
protected void updateList(Recipe editedRecipe){
for(Recipe recipe : recipes){
if(recipe.getID().equals(editedRecipe.getID())){
int index = recipes.indexOf(recipe);
recipes.set(index, editedRecipe);
mAdapter.notifyDataSetChanged();
break;
}
}
}
}
和配方類:
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
/**
* Created by Jacob on 9/14/2016.
*/
//Implements serilizable so that it can be passed in a bundle as a serializable object
public class Recipe implements Parcelable {
//These are all of the qualities a recipe contains, we will create an arraylist of this in the activity
private String mRecipeName;
private UUID mID;
private String mServings;
private String mPrepTime;
private String mCookTime;
private List<String> mIngredients;
private List<String> mDirections;
public Recipe(){
mID = UUID.randomUUID();
}
public String getRecipeName() {
return mRecipeName;
}
public UUID getID() {
return mID;
}
public String getServings() {
return mServings;
}
public String getPrepTime() {
return mPrepTime;
}
public void setRecipeName(String recipeName) {
mRecipeName = recipeName;
}
public void setServingSize(String servings) {
mServings = servings;
}
public void setPrepTime(String prepTime) {
mPrepTime = prepTime;
}
public List<String> getIngredients() {
return mIngredients;
}
public List<String> getDirections() {
return mDirections;
}
public String getCookTime() {
return mCookTime;
}
public void setCookTime(String cookTime) {
mCookTime = cookTime;
}
public void setIngredients(List<String> ingredients) {
mIngredients = ingredients;
}
public void setDirections(List<String> directions) {
mDirections = directions;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.mRecipeName);
dest.writeSerializable(this.mID);
dest.writeString(this.mServings);
dest.writeString(this.mPrepTime);
dest.writeString(this.mCookTime);
dest.writeStringList(this.mIngredients);
dest.writeStringList(this.mDirections);
}
protected Recipe(Parcel in) {
this.mRecipeName = in.readString();
this.mID = (UUID) in.readSerializable();
this.mServings = in.readString();
this.mPrepTime = in.readString();
this.mCookTime = in.readString();
this.mIngredients = in.createStringArrayList();
this.mDirections = in.createStringArrayList();
}
public static final Parcelable.Creator<Recipe> CREATOR = new Parcelable.Creator<Recipe>() {
@Override
public Recipe createFromParcel(Parcel source) {
return new Recipe(source);
}
@Override
public Recipe[] newArray(int size) {
return new Recipe[size];
}
};
}
食譜類是否實現了Parcelable類,並且可以發佈食譜類代碼? –
是的。我添加了食譜類的代碼。 – knokout1
我看到你有三個活動,請你可以解釋每個活動的目的:RecipeTextView,EditRecipe,RecipeList。 – fernandospr