0

I've setup my activity to have a listview-> Listview-> listview-> table layout -> etc. When navigating the application apps to work great. But it's only a matter of time till the program randomly crashes.

03-06 21:12:29.350: W/dalvikvm(7132): threadid=3: thread exiting with uncaught exception (group=0x4001b188)
03-06 21:12:29.350: E/AndroidRuntime(7132): Uncaught handler: thread main exiting due to uncaught exception
03-06 21:12:29.370: E/AndroidRuntime(7132): java.lang.NullPointerException
03-06 21:12:29.370: E/AndroidRuntime(7132):     at wanted.pro.madlibs.title.onListItemClick(title.java:55)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.app.ListActivity$2.onItemClick(ListActivity.java:312)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.widget.AdapterView.performItemClick(AdapterView.java:284)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.widget.ListView.performItemClick(ListView.java:3285)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.widget.AbsListView$PerformClick.run(AbsListView.java:1640)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.os.Handler.handleCallback(Handler.java:587)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.os.Handler.dispatchMessage(Handler.java:92)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.os.Looper.loop(Looper.java:123)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at android.app.ActivityThread.main(ActivityThread.java:4363)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at java.lang.reflect.Method.invokeNative(Native Method)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at java.lang.reflect.Method.invoke(Method.java:521)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
03-06 21:12:29.370: E/AndroidRuntime(7132):     at dalvik.system.NativeStart.main(Native Method)
03-06 21:12:29.380: I/dalvikvm(7132): threadid=7: reacting to signal 3
03-06 21:12:29.380: E/dalvikvm(7132): Unable to open stack trace file '/data/anr/traces.txt': Permission denied

From the logcat it looks like the problem is in my onlistitemclick. Though I don't get why it will work for a while and then not. Below is the code I'm using for one of the listviews.

public class title extends ListActivity {
    private PopupWindow pw;
    public static int titleClick;
    private dbadapter mydbhelper;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.category_list);
        mydbhelper = new dbadapter(this);
        mydbhelper.open();
        fillData();
    }
    private void fillData() {

        Cursor t = mydbhelper.getTitles();
            startManagingCursor(t);

     // Create an array to specify the fields we want to display in the list (TITLE,DATE,NUMBER)
        String[] from = new String[] {dbadapter.KEY_TITLEDESC};

        // an array of the views that we want to bind those fields to (in this case text1,text2,text3)
        int[] to = new int[] {R.id.text1};

        // Now create a simple cursor adapter and set it to display
        SimpleCursorAdapter adapter = 
            new SimpleCursorAdapter(this, R.layout.cate_row, t, from, to);
        setListAdapter(adapter);
        }
@Override
protected void onListItemClick(ListView list, View v, int position, long id)
{
    super.onListItemClick(list, v, position, id);
    titleClick = (int) list.getPositionForView(v);
    final Intent intent = new Intent(this, inputpage.class);
    final MediaPlayer titleClickSound = MediaPlayer.create(this, R.raw.button50); 
    titleClickSound.start();
    startActivityForResult(intent, position);
    }
@Override
protected void onResume() {
    if (mydbhelper != null) {
        mydbhelper.open();};
    super.onResume();
}

@Override
protected void onPause() {
    mydbhelper.close();
    super.onPause();
}
//Menu Items
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.layout.menu, menu);
    return true;
}

public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
         case R.id.help:
           showHelp();
            return true;
       }
    return false;
}

    private void showHelp() {
        LayoutInflater inflater = (LayoutInflater)
                   this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                 pw = new PopupWindow(
                   inflater.inflate(R.layout.help, null, false), 
                   LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 
                   true);
                 pw.showAtLocation(this.findViewById(R.id.text1), Gravity.CENTER, 0, 0); 
    }
    public void onClickHelp(View helper){pw.dismiss();

    }
}   

Trying to cause the crash again this time it gave me a different error

03-06 21:52:40.250: E/Database(15818): Leak found
03-06 21:52:40.250: E/Database(15818): java.lang.IllegalStateException: /data/data/wanted.pro.madlibs/databases/madlib SQLiteDatabase created and never closed
03-06 21:52:40.250: E/Database(15818):  at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1695)
03-06 21:52:40.250: E/Database(15818):  at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:739)
03-06 21:52:40.250: E/Database(15818):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:761)
03-06 21:52:40.250: E/Database(15818):  at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:754)
03-06 21:52:40.250: E/Database(15818):  at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:473)
03-06 21:52:40.250: E/Database(15818):  at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193)
03-06 21:52:40.250: E/Database(15818):  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
03-06 21:52:40.250: E/Database(15818):  at wanted.pro.madlibs.dbadapter.open(dbadapter.java:176)
03-06 21:52:40.250: E/Database(15818):  at wanted.pro.madlibs.title.onCreate(title.java:29)
03-06 21:52:40.250: E/Database(15818):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
03-06 21:52:40.250: E/Database(15818):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
03-06 21:52:40.250: E/Database(15818):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
03-06 21:52:40.250: E/Database(15818):  at android.app.ActivityThread.access$2200(ActivityThread.java:119)
03-06 21:52:40.250: E/Database(15818):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
03-06 21:52:40.250: E/Database(15818):  at android.os.Handler.dispatchMessage(Handler.java:99)
03-06 21:52:40.250: E/Database(15818):  at android.os.Looper.loop(Looper.java:123)
03-06 21:52:40.250: E/Database(15818):  at android.app.ActivityThread.main(ActivityThread.java:4363)
03-06 21:52:40.250: E/Database(15818):  at java.lang.reflect.Method.invokeNative(Native Method)
03-06 21:52:40.250: E/Database(15818):  at java.lang.reflect.Method.invoke(Method.java:521)
03-06 21:52:40.250: E/Database(15818):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
03-06 21:52:40.250: E/Database(15818):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
03-06 21:52:40.250: E/Database(15818):  at dalvik.system.NativeStart.main(Native Method)

I've been trying to stop this leak. Thought I had it but guess not. Wondering if the leak could be causing the problem since the int in onclick is used in cursors at bottom of dbhelperclass

public class dbadapter extends SQLiteOpenHelper {

     //The Android's default system path of your application database.
   public static final String DB_PATH = "/data/data/wanted.pro.madlibs/databases/";
   public static final String DB_NAME = "madlib";
   public static final int DB_VERSION = 39;


   //database variables
   public static final String  KEY_ID = "_id";
   public static final String  KEY_CATEGORYDESC = "categorydesc";
   public static final String KEY_TITLE = "titlekey";
   public static final String KEY_TITLEDESC = "titledesc";
   public static final String KEY_TITLESTORY = "titlestory";
   public static final String KEY_SOURCEDESC = "sourcedesc";
   public static final String KEY_SOURCE = "sourcekey";
   public static final String KEY_CATEGORY = "categorykey";
   public static final String KEY_USERWORD = "userword";
   public static final String KEY_EDITWORD = "editword";
   public static final String KEY_QUICK = "quick";

   //table variables
   public static final String CATEGORY_TABLE = "category";
   public static final String SOURCE_TABLE = "source";
   public static final String TITLE_TABLE = "title";
   public static final String SOURCE_CATEGORY_TABLE = "source_category";
   public static final String SOURCE_TITLE_TABLE = "source_title";
   public static final String CATEGORY_TITLE_TABLE = "category_title";
   public static final String USER_WORD_TABLE = "userword";

   private dbadapter mydbhelper;
   public static SQLiteDatabase myDataBase; 

  /**
    * Constructor
    * Takes and keeps a reference of the passed context in order to access to the application assets and resources.
    * @param context
    */

       private final Context mCtx;
    public dbadapter(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
       this.mCtx = context;
   }    

 /**
    * Creates a empty database on the system and rewrites it with your own database.
    * */
   public void createDataBase() throws IOException{
    boolean dbExist = checkDataBase();
    if(dbExist){
        Log.v("DB Exists", "db exists");
        this.getWritableDatabase();
        //do nothing - database already exist
    }
    dbExist=checkDataBase();
    if(!dbExist){
        //By calling this method and empty database will be created into the default system path
              //of your application so we are gonna be able to overwrite that database with our database.
        this.getReadableDatabase();

        try {
            copyDataBase();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }


   }

   /**
    * Check if the database already exist to avoid re-copying the file each time you open the application.
    * @return true if it exists, false if it doesn't
    */
   private boolean checkDataBase(){

    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }catch(SQLiteException e){

        //database does't exist yet.

    }

    if(checkDB != null){

        checkDB.close();
    }

    return checkDB != null ? true : false;
   }

   /**
    * Copies your database from your local assets-folder to the just created empty database in the
    * system folder, from where it can be accessed and handled.
    * This is done by transferring bytestream.
    * */
   private void copyDataBase() throws IOException{

    //Open your local db as the input stream
    InputStream myInput = mCtx.getAssets().open(DB_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

    //Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    //transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer))>0){
        myOutput.write(buffer, 0, length);
    }

    //Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();


   }

   public void openDataBase() throws SQLException{

    //Open the database
       String myPath = DB_PATH + DB_NAME;
        this.getWritableDatabase();
       myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);

   }

   @Override
    public synchronized void close() {

        if(myDataBase != null)
            myDataBase.close();

        super.close();

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion > oldVersion)
        mCtx.deleteDatabase(DB_NAME);
        }

    public dbadapter open() throws SQLException {
        mydbhelper = new dbadapter (mCtx);
        myDataBase = mydbhelper.getWritableDatabase();
        return this;
    }


    // retrieves all the categories
      public Cursor getAllCategories() 
        {
            return myDataBase.query(CATEGORY_TABLE, new String[] {
                    KEY_ID, KEY_CATEGORY,
                    KEY_CATEGORYDESC,
                    }, 
                    null, null, null, null, KEY_CATEGORYDESC);

        }
    // retrieves all the titles
          public Cursor getTitles() 
            {
                return myDataBase.query(TITLE_TABLE, new String[] {
                        KEY_ID, 
                        KEY_TITLE,
                        KEY_TITLEDESC,
                        KEY_TITLESTORY, KEY_CATEGORY, KEY_SOURCE,
                        }, 
                        KEY_CATEGORY+ "=" + categories.categoryClick + " AND " + KEY_SOURCE+ "=" +source.sourceClick, null, null, null, KEY_TITLEDESC);

            }
        // retrieves all the descriptions for the edittext fields
          public  Cursor getUserWord() 
            {
                return myDataBase.query(USER_WORD_TABLE, new String[] {
                        KEY_ID, 
                        KEY_CATEGORY,
                        KEY_SOURCE, KEY_TITLE, KEY_USERWORD, KEY_QUICK 
                        }, 
                        KEY_CATEGORY+ "=" + categories.categoryClick + " AND " + KEY_SOURCE+ "=" 
                        +source.sourceClick + " AND " + KEY_TITLE+ "=" + title.titleClick, 
                        null, null, null, KEY_ID);

            }
            // Quick Start
          public Cursor getQuickStory() 
            {
                return myDataBase.query(TITLE_TABLE, new String[] {
                        KEY_ID, 
                        KEY_TITLE,
                        KEY_TITLEDESC,
                        KEY_TITLESTORY, KEY_CATEGORY, KEY_SOURCE,
                        }, 
                        KEY_ID+ "=" + main.RandomNum, null, null, null, null);

            }

          public  Cursor getQuickWord() 
            {
                return myDataBase.query(USER_WORD_TABLE, new String[] {
                        KEY_ID, 
                        KEY_CATEGORY,
                        KEY_SOURCE, KEY_TITLE, KEY_USERWORD, KEY_QUICK 
                        }, 
                        KEY_QUICK+ "=" + main.RandomNum, 
                        null, null, null, KEY_ID);

            }

          public Cursor getSource()
          {
             return myDataBase.query(SOURCE_TABLE, new String[]{
                    KEY_ID, KEY_SOURCEDESC, KEY_CATEGORY,},
                    KEY_CATEGORY+ "=" + categories.categoryClick, null, null, null, KEY_SOURCEDESC);
          } 

            // retrieves story to diplay in last activity
          public Cursor getStory() 
            {
                return myDataBase.query(TITLE_TABLE, new String[] {
                        KEY_ID, 
                        KEY_TITLE,
                        KEY_TITLEDESC,
                        KEY_TITLESTORY, KEY_CATEGORY, KEY_SOURCE,
                        }, 
                        KEY_CATEGORY+ "=" + categories.categoryClick + " AND " + KEY_SOURCE+ "=" +source.sourceClick + " AND " + KEY_TITLE+ "=" + title.titleClick, null, null, null, null);

            }


} 
maebe
  • 553
  • 1
  • 6
  • 18
  • Looking at the line `final Intent intent = new Intent(this, inputpage.class);`, what is `inputpage`? Where is that defined? – gobernador Mar 07 '12 at 02:25
  • According to the exception, the cause is: wanted.pro.madlibs.title.onListItemClick(title.java:55). Which line is that in the code you've shared? – Eric Levine Mar 07 '12 at 02:25
  • inputpage is a class and onlistitemclick is there – maebe Mar 07 '12 at 02:45
  • have you tried opening the database in `onCreate` and closing the database in `onDestroy`? maybe the reason you are getting an error is because at some point the `Cursor` is still active when the database isn't? – Alex Lockwood Mar 07 '12 at 05:43
  • 1
    check this link for some sample code on how you might go about allowing access to your database across multiple activities: http://stackoverflow.com/questions/6905524/is-singleton-good-enough-for-sqlite-db-sharing/9286006#9286006 – Alex Lockwood Mar 07 '12 at 05:44
  • Ty Alex, your link pointed me in the right direction for my issue with databasehelper. It doesn't crash for that reason anymore. – maebe Mar 10 '12 at 21:10

1 Answers1

0

I'm not sure if this is the cause of your exception or not, but the following looks like it can cause you some problems. You define:

public static int titleClick;

Then in your onListItemClick you call:

titleClick = (int) list.getPositionForView(v);

I assume that this public static variable is being accessed from other Activities in your application. Due to the way Android manages your Activity (see the flow chart here), this static variable may become null/undefined if your application's process has been killed and then restarted. It will also be null if that static variable is accessed before onListItemClick is called.

Also, you should be able to use the position parameter from onListItemClick instead of doing: (int) list.getPositionForView(v)

Eric Levine
  • 13,536
  • 5
  • 49
  • 49
  • My thought it was with that variable and something is happening after I write/access it a few times. I'll try the position parameter instead. What I'm doing with titleClick is using that to filter a cursor to pull item's from a database to show results based on item selected from the list. – maebe Mar 07 '12 at 02:46
  • Can you tell me which line is number 55 in title.java? That should provide another clue. – Eric Levine Mar 07 '12 at 02:53
  • I would suggest making things work without using static variables. Instead, you can pass information through your Intent object by using the putExtra and getExtras methods. – Eric Levine Mar 07 '12 at 02:55
  • I'm wondering if this might instead be an issue with my database. Add more information to my question... – maebe Mar 07 '12 at 02:57
  • Since you are getting a different exception, I would say that you have encountered a new problem. On first glance, I see a lot of unnecessary things going on inside your SQLiteOpenHelper. Having myDataBase as a static variable to share amongst your Activities is a bad idea. Each Activity should create a new instance of SQLiteOpenHelper. – Eric Levine Mar 07 '12 at 14:48
  • Elevine you are correct that it was two issues. I've resolved the dbhelper one but trying to resolve the issue with passing the position int to another activity. I've posted a new question on how to get the getextra/putextra to work with cursors. If you have the time plz take a look http://stackoverflow.com/questions/9650499/passing-value-from-extra-to-cursor – maebe Mar 10 '12 at 21:55
  • @maebe I'll take a look. If you have the time, please mark this answer as correct :) – Eric Levine Mar 10 '12 at 22:02