Sunday, March 1, 2015

105 MySuperHero Android ArrayList and SharedPreferences


.
105 MySuperHero Android ArrayList and SharedPreferences
In the previous tutorial, we use String Array as the data source for the ListView.
String Array is static ie the initial size cannot be changed.
In this tutorial, we are going to rewrite the codes without String Array and our codes depend entirely on the ArrayList data type. It is a dynamic data structure therefore it can be used when there is no upper bound on the number of elements. It is much easier to add, replace or remove items during runtime.
We are going implement data storage using SharedPreferences so that changes are permanent and users get the last saved list instead of the default list. In this regard, ArrayList is a perfect choice since we do not know how many data items are stored in SharedPreferences when the apps is started.

0) Starting Up

1) Edit SuperHeroesActivity.java

Omit the use of String Array codes.
Use ArrayList method to add, edit or replace item in list.
Create loadData() method to get data from SharedPreferences
Create saveData() method to save data to SharedPreferences
(Most codes have been explained by the comments preceding them)
File: SuperHeroesActivity.java
package com.example.mysuperhero;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class SuperHeroesActivity extends Activity {
 Button btnAddSuperHero;
 ListView lvwSuperHeroes;
 List < String > lstSuperHeroes = new ArrayList < String > (); //init lstSuperHeroes
 ArrayAdapter adpSuperHeroes;
/* String Array declaration has been omitted */
 static final int ADD_ITEM = 1; // The request code to add item
 static final int EDIT_ITEM = 2; // The request code to edit item
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_super_heroes);
  setLvwSuperHeroes();
  setBtnAddSuperHero();
 }
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_super_heroes, menu);
  return true;
 }
 private void setLvwSuperHeroes() {
  //bind object
  lvwSuperHeroes = (ListView) findViewById(R.id.lvw_superheroes);
  /* String Array codes have been omitted */
  //load data from SharedPreferences to lstSuperHeroes if exists
  loadData();
  //define adpSuperHeroes having data source from lstSuperHeroes
  adpSuperHeroes = new ArrayAdapter < String > (this, android.R.layout.simple_list_item_1, lstSuperHeroes);
  //Plug adpSuperHeroes to lvwSuperHeroes
  lvwSuperHeroes.setAdapter(adpSuperHeroes);
  //set onclick listener for listview
  lvwSuperHeroes.setOnItemClickListener(new AdapterView.OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView < ? > parent, View view, int position, long id) {
    Intent intent = new Intent(SuperHeroesActivity.this, SuperHeroActivity.class);
    intent.putExtra("POSITION", position);
    intent.putExtra("NAME", lvwSuperHeroes.getItemAtPosition(position).toString());
    startActivityForResult(intent, EDIT_ITEM);
   }
  });
  //set onItemLongClickListener
  lvwSuperHeroes.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
   public boolean onItemLongClick(AdapterView < ? > arg0, View v,
    int index, long arg3) {
    deleteSuperHero(index);
    //save changes (DELETE_ITEM) to SharedPreferences    
    saveData();
    return true;
   }
  });
 }
 private void setBtnAddSuperHero() {
  btnAddSuperHero = (Button) findViewById(R.id.btn_add_superhero);
  btnAddSuperHero.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View view) {
    Intent intent = new Intent(SuperHeroesActivity.this, SuperHeroActivity.class);
    startActivityForResult(intent, ADD_ITEM);
   }
  });
 }
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  String strNewName = "";
  int intPosition = -1;
  if (resultCode == RESULT_OK) {
   if (requestCode == ADD_ITEM) {
    try {
     strNewName = data.getStringExtra("NAME");
    } catch (Exception e) {}
    addSuperHero(strNewName);
   }
   if (requestCode == EDIT_ITEM) {
    try {
     intPosition = data.getIntExtra("POSITION", -1);
     strNewName = data.getStringExtra("NAME");
    } catch (Exception e) {}
    editSuperHero(intPosition, strNewName);
   }
   //save changes (ADD_ITEM or EDIT_ITEM) to SharedPreferences
   saveData();
  } else if (resultCode == RESULT_CANCELED) {
   //Toast.makeText(getApplicationContext(), "No Changes", //Toast.LENGTH_SHORT).show();
  }
 }
 private void editSuperHero(int position, String text) {
  //check that we have a valid position value
  if (position < 0) {
   return;
  }
  /* String Array codes have been omitted */
  //replace item in lstSuperHeroes
  lstSuperHeroes.set(position, text);
  //notify apps that adapter has changed
  adpSuperHeroes.notifyDataSetChanged();
  //scroll to the bottom
  lvwSuperHeroes.smoothScrollToPosition(adpSuperHeroes.getCount() - 1);
 }
 private void addSuperHero(String strNewName) {
  /* String Array codes have been omitted */
  //add new item to lstSuperHeroes
  lstSuperHeroes.add(strNewName);
  //notify apps that adapter has changed
  adpSuperHeroes.notifyDataSetChanged();
  //scroll to the bottom
  lvwSuperHeroes.smoothScrollToPosition(adpSuperHeroes.getCount() - 1);
 }
 private void deleteSuperHero(int position) {
  //delete item in lstSuperHeroes
  lstSuperHeroes.remove(position);
  //notify apps that adapter has changed        
  adpSuperHeroes.notifyDataSetChanged();
 }
 private void loadData() {
  //get data from SharedPreferences Resource identified by appsdata
  SharedPreferences spAppsData = getSharedPreferences("appsdata", MODE_PRIVATE);
  //get comma-separated values from data item identified by superheroes (key)
  String csvSuperHeroes = spAppsData.getString("superheroes", "");
  if (!csvSuperHeroes.equals("")) {
   //convert comma-separated value to string array using split method
   //create new list array having values from string array
   lstSuperHeroes = new ArrayList < String > (Arrays.asList(csvSuperHeroes.split(",")));
  }
 }
 private void saveData() {
  //set data SharedPreferences Resource identified by appsdata
  SharedPreferences spAppsData = getSharedPreferences("appsdata", MODE_PRIVATE);
  //set edit mode
  SharedPreferences.Editor e = spAppsData.edit();
  //prepare comma-separated values from lstSuperHeroes
  String csvSuperHeroes = TextUtils.join(",", lstSuperHeroes);
  //put values into data item identified by superheroes (key)
  e.putString("superheroes", csvSuperHeroes);
  //make permanent
  e.commit();
 }
}
Start the apps.
You should get an empty list
Add Thor, Hulk and X-men.
Delete Hulk.
Close the app.
Start the apps again and check that the correct data items persist.

DOWNLOAD

REFERENCES


.

104 MySuperHero Android Form Processing


.
104 MySuperHero Android Form Processing
We are going to provide a form for users to enter their super hero names.
The form will be provided in a separate activity, SuperHeroActivity (without s).
We will use StartActivityForResult to call the SuperHeroActivity. When the user finishes entering the data and submit them, SuperHeroActivity will return back to SuperHeroesActivity together with data for ListView to update.

0) Starting Up

Continue from the previous tutorial or download startup files.

1) Add a new activity

Type a name SuperHeroActivity. (without s)

2) startActivityForResult and onActivityResult

There will be a lot of code changes.
Refer code outlines below.
When the button is clicked, onClickListener will call startActivityForResult forSuperHeroActivity with no Intent Extra. RequestCode is 1 (ADD_ITEM).
When the list is clicked, onItemClickListener will call startActivityForResult forSuperHeroActivity with Intent Extra. RequestCode is 2 (EDIT_ITEM).
When SuperHeroActivity receives BackPressed event, the apps goes back to SuperHeroesActivity. The OnActivityResult method will evaluate the ResultCode andRequestCode .
 Since we use setResult to return RESULT_CANCELED, you will get No Parameter Changes message.
File: SuperHeroesActivity.java
File: SuperHeroesActivity.java
package com.example.mysuperhero;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class SuperHeroesActivity extends Activity {
 Button btnAddSuperHero;
 ListView lvwSuperHeroes;
 String[] strSuperHeroes;
 ArrayAdapter adpSuperHeroes;
 static final int ADD_ITEM = 1; // The request code to add item
 static final int EDIT_ITEM = 2; // The request code to edit item
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_super_heroes);
  setLvwSuperHeroes();
  setBtnAddSuperHero();
 }
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_super_heroes, menu);
  return true;
 }
 private void setLvwSuperHeroes() {
  //bind object
  lvwSuperHeroes = (ListView) findViewById(R.id.lvw_superheroes);
  //Add new values to array
  strSuperHeroes = new String[] {
   "Superman",
   "Spiderman",
   "Batman",
   "Ironman",
   "Ultraman",
   "Pacman",
   "Roboman"
  };
  //Create ArrayList from strSuperHeroes
  List < String > values = new ArrayList < String > (Arrays.asList(strSuperHeroes));
  //Create Adapter to load ArrayList
  adpSuperHeroes = new ArrayAdapter < String > (this, android.R.layout.simple_list_item_1, values);
  //Plug adpSuperHeroes to lvwSUperHeroes
  lvwSuperHeroes.setAdapter(adpSuperHeroes);
  //set onclick listener for listview
  lvwSuperHeroes.setOnItemClickListener(new AdapterView.OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView < ? > parent, View view, int position, long id) {
    Intent intent = new Intent(SuperHeroesActivity.this, SuperHeroActivity.class);
    intent.putExtra("POSITION", position);
    intent.putExtra("NAME", lvwSuperHeroes.getItemAtPosition(position).toString());
    startActivityForResult(intent, EDIT_ITEM);
   }
  });
  //set onItemLongClickListener
  lvwSuperHeroes.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
   public boolean onItemLongClick(AdapterView < ? > arg0, View v,
    int index, long arg3) {
    deleteSuperHero(index);
    return true;
   }
  });
 }
 private void setBtnAddSuperHero() {
  btnAddSuperHero = (Button) findViewById(R.id.btn_add_superhero);
  btnAddSuperHero.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View view) {
    Intent intent = new Intent(SuperHeroesActivity.this, SuperHeroActivity.class);
    startActivityForResult(intent, ADD_ITEM);
   }
  });
 }
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (resultCode==RESULT_OK){
         if(requestCode==ADD_ITEM){
                  addSuperHero();
          }
          if(requestCode==EDIT_ITEM){
                  editSuperHero(0,"test"); //dummy values only
          }          
 }else if (resultCode==RESULT_CANCELED){
          Toast.makeText(getApplicationContext(), "No Changes",Toast.LENGTH_SHORT).show();
 }
 }
 private void editSuperHero(int position, String text) {
  //recreate new superheroes string array
  String[] strNewSuperHeroes = new String[adpSuperHeroes.getCount()];
  for (int i = 0; i < adpSuperHeroes.getCount(); i++) {
   if (i != position) {
    strNewSuperHeroes[i] = (String) adpSuperHeroes.getItem(i);
   } else {
    strNewSuperHeroes[i] = (String) adpSuperHeroes.getItem(i);
    strNewSuperHeroes[i] += " Edited";
   }
  }
  //clear adapter
  adpSuperHeroes.clear();
  //reassign new superheroes string array to adapter
  adpSuperHeroes.addAll(strNewSuperHeroes);
  //notify apps that adapter has changed
  adpSuperHeroes.notifyDataSetChanged();
  //scroll to the bottom
  lvwSuperHeroes.smoothScrollToPosition(adpSuperHeroes.getCount() - 1);
 }
 private void addSuperHero() {
  adpSuperHeroes.add("New Hero");
  adpSuperHeroes.notifyDataSetChanged();
  //scroll to the bottom
  lvwSuperHeroes.smoothScrollToPosition(adpSuperHeroes.getCount() - 1);
 }
 private void deleteSuperHero(int position) {
  adpSuperHeroes.remove(adpSuperHeroes.getItem(position));
  adpSuperHeroes.notifyDataSetChanged();
 }
}
File: SuperHeroActivity.java
package com.example.mysuperhero;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Toast;
public class SuperHeroActivity extends Activity {
        int intPosition=-1; //init intPosition to -1 ie no position value
        String strItemName=""; //init strItemName to ""
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_super_hero);
                getParam();
        }
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                // Inflate the menu; this adds items to the action bar if it is present.
                getMenuInflater().inflate(R.menu.activity_super_hero, menu);
                return true;
        }
        private void getParam(){
                 final Bundle bundle = getIntent().getExtras();
                if(bundle != null) {
                    intPosition = bundle.getInt("POSITION");
                    strItemName = bundle.getString("NAME");
                    Toast.makeText(getApplicationContext(),
                                    "POSITION: "+intPosition
                                    +"\nNAME: " + strItemName,
                                    Toast.LENGTH_SHORT).show();
                }else{
                        Toast.makeText(getApplicationContext(),
                                        "No Parameter",
                                        Toast.LENGTH_SHORT).show();
               
                }
        }
        @Override
        public void onBackPressed() {
            super.onBackPressed();
            setResult(Activity.RESULT_CANCELED); //no changes
            finish();
        }
}
Start.
Click Add Super Hero button.
SuperHeroActivity  is started.
No Parameter is toasted.
Press Back Button.
SuperHeroesActivity is started.
No Changes is toasted.
Start.
Click Ironman.
SuperHeroActivity  is started.
Ironman item POSITION and NAME is toasted.
Press Back Button.
SuperHeroesActivity is started.
No Changes is toasted.

3) Form Layout

File: res/layout/activity_super_hero.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SuperHeroActivity" >
   <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/superhero"
       android:layout_gravity="center_horizontal"
       />
    <EditText
        android:id="@+id/etx_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Name" />
    <Button
        android:id="@+id/btn_save"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save" />
</LinearLayout>

4) Form Processing

File: SuperHeroActivity.java
package com.example.mysuperhero;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class SuperHeroActivity extends Activity {
 int intPosition = -1; //init intPosition to -1 ie no position value
 String strItemName = ""; //init strItemName to ""
 EditText etxName;
 Button btnSave;
 String strNewName = "";
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_super_hero);
  setForm();
  getParam();
 }
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_super_hero, menu);
  return true;
 }
 private void getParam() {
  final Bundle bundle = getIntent().getExtras();
  if (bundle != null) {
   intPosition = bundle.getInt("POSITION");
   strItemName = bundle.getString("NAME");
   etxName.setText(strItemName);
  } else {
   //Toast.makeText(getApplicationContext(),
    //"No Parameter",
    //Toast.LENGTH_SHORT).show();
  }
 }
 private void setForm() {
  etxName = (EditText) findViewById(R.id.etx_name);
  btnSave = (Button) findViewById(R.id.btn_save);
  btnSave.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View view) {
    if (isValidFormData()) {
     saveNewData();
    }
   }
   private void saveNewData() {
    Intent intent = new Intent();
    intent.putExtra("POSITION", intPosition);
    intent.putExtra("NAME", strNewName);
    setResult(Activity.RESULT_OK, intent); //2=Edit Buddy                                
    finish();
   }
   private boolean isValidFormData() {
    boolean isName = false;
    //get field values
    strNewName = etxName.getText().toString();
    //check field values validity
    if (isEmptyString(strNewName)) {
     etxName.setError("Name must not be empty");
    } else {
     isName = true;
    }
    return (isName);
   }
   // validating empty string
   public boolean isEmptyString(String text) {
    return (text == null || text.trim().equals("null") || text.trim()
     .length() <= 0);
   }
  });
 }
 @Override
 public void onBackPressed() {
  super.onBackPressed();
  setResult(Activity.RESULT_CANCELED);
  finish();
 }
}

5) OnActivityResult

File: SuperHeroesActivity.java
package com.example.mysuperhero;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class SuperHeroesActivity extends Activity {
 Button btnAddSuperHero;
 ListView lvwSuperHeroes;
 String[] strSuperHeroes;
 ArrayAdapter adpSuperHeroes;
 static final int ADD_ITEM = 1; // The request code to add item
 static final int EDIT_ITEM = 2; // The request code to edit item
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_super_heroes);
  setLvwSuperHeroes();
  setBtnAddSuperHero();
 }
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_super_heroes, menu);
  return true;
 }
 private void setLvwSuperHeroes() {
  //bind object
  lvwSuperHeroes = (ListView) findViewById(R.id.lvw_superheroes);
  //Add new values to array
  strSuperHeroes = new String[] {
   "Superman",
   "Spiderman",
   "Batman",
   "Ironman",
   "Ultraman",
   "Pacman",
   "Roboman"
  };
  //Create ArrayList from strSuperHeroes
  List < String > values = new ArrayList < String > (Arrays.asList(strSuperHeroes));
  //Create Adapter to load ArrayList
  adpSuperHeroes = new ArrayAdapter < String > (this, android.R.layout.simple_list_item_1, values);
  //Plug adpSuperHeroes to lvwSUperHeroes
  lvwSuperHeroes.setAdapter(adpSuperHeroes);
  //set onclick listener for listview
  lvwSuperHeroes.setOnItemClickListener(new AdapterView.OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView < ? > parent, View view, int position, long id) {
    Intent intent = new Intent(SuperHeroesActivity.this, SuperHeroActivity.class);
    intent.putExtra("POSITION", position);
    intent.putExtra("NAME", lvwSuperHeroes.getItemAtPosition(position).toString());
    startActivityForResult(intent, EDIT_ITEM);
   }
  });
  //set onItemLongClickListener
  lvwSuperHeroes.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
   public boolean onItemLongClick(AdapterView < ? > arg0, View v,
    int index, long arg3) {
    deleteSuperHero(index);
    return true;
   }
  });
 }
 private void setBtnAddSuperHero() {
  btnAddSuperHero = (Button) findViewById(R.id.btn_add_superhero);
  btnAddSuperHero.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View view) {
    Intent intent = new Intent(SuperHeroesActivity.this, SuperHeroActivity.class);
    startActivityForResult(intent, ADD_ITEM);
   }
  });
 }
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  String strNewName = "";
  int intPosition = -1;
  if (resultCode == RESULT_OK) {
   if (requestCode == ADD_ITEM) {
    try {
     strNewName = data.getStringExtra("NAME");
    } catch (Exception e) {}
    addSuperHero(strNewName);
   }
   if (requestCode == EDIT_ITEM) {
    try {
     intPosition = data.getIntExtra("POSITION", -1);
     strNewName = data.getStringExtra("NAME");
    } catch (Exception e) {}
    editSuperHero(intPosition, strNewName);
   }
  } else if (resultCode == RESULT_CANCELED) {
   Toast.makeText(getApplicationContext(), "No Changes", Toast.LENGTH_SHORT).show();
  }
 }
 private void editSuperHero(int position, String text) {
  //recreate new superheroes string array
  if (position<0){return;} //check that we have a valid position value
  String[] strNewSuperHeroes = new String[adpSuperHeroes.getCount()];
  for (int i = 0; i < adpSuperHeroes.getCount(); i++) {
   if (i != position) {
    strNewSuperHeroes[i] = (String) adpSuperHeroes.getItem(i);
   } else {
    strNewSuperHeroes[i] = text;
   }
  }
  //clear adapter
  adpSuperHeroes.clear();
  //reassign new superheroes string array to adapter
  adpSuperHeroes.addAll(strNewSuperHeroes);
  //notify apps that adapter has changed
  adpSuperHeroes.notifyDataSetChanged();
  //scroll to the bottom
  lvwSuperHeroes.smoothScrollToPosition(adpSuperHeroes.getCount() - 1);
 }
 private void addSuperHero(String strNewName) {
  adpSuperHeroes.add(strNewName);
  adpSuperHeroes.notifyDataSetChanged();
  //scroll to the bottom
  lvwSuperHeroes.smoothScrollToPosition(adpSuperHeroes.getCount() - 1);
 }
 private void deleteSuperHero(int position) {
  adpSuperHeroes.remove(adpSuperHeroes.getItem(position));
  adpSuperHeroes.notifyDataSetChanged();
 }
}
OUTCOME.
Start.
Click Add Super Hero.
Enter Antman.
Click Save.
Antman is added to the list.
Start.
Click Add Super Hero.
Click Save.
You get error.
Start.
Click Batman.
Replace Batman with Robin.
Click Save.
Robin replaces Batman in the list.
Click either Add Super Hero or any name.
Press Back Button

DOWNLOAD


.