Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
JawnV6
Jul 4, 2004

So hot ...
That sounds perfect, but I can't get it to work. It restarts the server and shows up under 'adb devices', but 'adb connect' complains about multiple devices and as soon as I unplug the USB, the tcp device drops off the list.

I've got a rough idea of where they're getting hung up and I think I can get it figured out from the firmware side. Thanks for the help!

Adbot
ADBOT LOVES YOU

Boz0r
Sep 7, 2006
The Rocketship in action.
I'm learning Android and I'm doing a thing with Services and Activities.

Activity A has an integer input field and a button. When the button is pressed, the activity starts a service that creates an alarm with time based on the input field. The alarm then triggers Activity B.

I've run into a snag where Activity B gets triggered after around 2 seconds no matter what's in the input field.

code:

class MainActivity {
		public void setAlarm(View view) {
		Log.w("Main", "setAlarm");		
		EditText editText = (EditText) findViewById(R.id.edit_message);
		long time = Long.parseLong(editText.getText().toString());
		
		Intent intent = new Intent(this, AlarmService.class);
		intent.setAction(Intent.ACTION_VIEW);
		intent.putExtra(CLOCK_TIME, time);
		
		startService(intent);
	}
}

class AlarmService {
	public void onStart(Intent intent, int startId) {
		Log.w("AlarmService", "onStart");
		timeReceiver.setAlarm(this, intent.getExtras());
	}
}

class TimeReceiver {
	public void setAlarm(Context context, Bundle bundle) {		
		final AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
		Intent intent = new Intent(context, TimeReceiver.class);
		final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
		
		final long time = (Long) bundle.get(MainActivity.CLOCK_TIME);
		alarmManager.set(AlarmManager.RTC_WAKEUP, time * 1000, pendingIntent);			
	}

	public void onReceive(Context context, Intent intent) {
		Intent intent2 = new Intent(context, Activity2.class);
		intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(intent2);	
	}
}
Can anyone spot any errors? I swear it was working yesterday :(

zeekner
Jul 14, 2007

That call to alarmManager.set needs a time including system.currentmilis. Right now you are telling it to start 2 seconds after new years 1970.

JawnV6
Jul 4, 2004

So hot ...
I rewrote my stupid thing to use OTG instead of AOA, got the demo ready.

I guess this is an Android internals question, but where does power drawn from the dc/dc converter in OTG show up in the Settings Battery monitor? From a test we did earlier this week it looks like it's shown under "Wifi" for whatever reason. I'm sucking half an amp out of this thing, it's a large amount of power and I can't imagine it isn't noticing.

NoDamage
Dec 2, 2000
So now that there's an ActionBar in the support library is there any reason to use ActionBarSherlock?

zeekner
Jul 14, 2007

NoDamage posted:

So now that there's an ActionBar in the support library is there any reason to use ActionBarSherlock?

Not really, I've converted several ABS projects to ABC and haven't run into any serious issues. It's a little more annoying to work with, like you have to use MenuItemCompat instead of the full-replacement MenuItem ABS has. Really though, both libraries require a few weird changes (Window flags have a duplicate replacement in ABS, *Compat helpers in ABC, ect). Once you get past that it's pretty easy.

Tunga
May 7, 2004

Grimey Drawer

JawnV6 posted:

I guess this is an Android internals question, but where does power drawn from the dc/dc converter in OTG show up in the Settings Battery monitor? From a test we did earlier this week it looks like it's shown under "Wifi" for whatever reason.
It would not surprise me at all if this shows up under some completely arbitrary category like that. I've never seen any direct indication of the power used by an OTG device.

Boz0r
Sep 7, 2006
The Rocketship in action.

Salvador Dalvik posted:

That call to alarmManager.set needs a time including system.currentmilis. Right now you are telling it to start 2 seconds after new years 1970.

Thanks, that did the trick.

Now I'm trying to extend the project to also update a ProgressBar in the main view, and I have some trouble with that too. I don't really know how I'm supposed to bring a reference to the ProgressBar with me through to the service and on to the BroadcastReceiver. I tried making it static, but then I get a nullpointerexception when I try to access it.

Same code as before, the main activity calls a service when a button is called, the service sets an alarm(two now) that's supposed to repeatedly update a ProgressBar until it's full.

code:
class ProgressReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {		
		int progress = MainActivity.progressBar.getProgress() + 10;			
		MainActivity.progressBar.setProgress(progress);
	}	
}
Any ideas?

zeekner
Jul 14, 2007

Boz0r posted:

Thanks, that did the trick.

Now I'm trying to extend the project to also update a ProgressBar in the main view, and I have some trouble with that too. I don't really know how I'm supposed to bring a reference to the ProgressBar with me through to the service and on to the BroadcastReceiver. I tried making it static, but then I get a nullpointerexception when I try to access it.

Same code as before, the main activity calls a service when a button is called, the service sets an alarm(two now) that's supposed to repeatedly update a ProgressBar until it's full.

code:
class ProgressReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {		
		int progress = MainActivity.progressBar.getProgress() + 10;			
		MainActivity.progressBar.setProgress(progress);
	}	
}
Any ideas?

So just to get it straight, are you sending an update broadcast from the service to the activity? If you are trying to keep the receiver outside the activity, you don't really need to.

If you put that ProgressReceiver as an inner class to your Activity or Fragment, you should be able to reference the progressbar directly. You might need to use a Runnable and activity.runOnUiThread(runnable) to make sure you only modify the progressbar on the UI thread or else it might throw an exception.

e: Also, you can use Intent.putExtra() to add a real progress percentage to that broadcast, so you don't have to send exactly 10 updates.

Boz0r
Sep 7, 2006
The Rocketship in action.
I'm supposed to do the countdown from the service, so I don't think I can have it as an internal class in the Activity.

EDIT: Can I carry a reference to MainActivity through to the service somehow?

EDIT: I've come a little further:

http://pastebin.kde.org/p3zvxowci

I think the only problem left is, that the onReceive doesn't trigger, and I can't see why.

Boz0r fucked around with this message at 15:42 on Nov 24, 2013

zeekner
Jul 14, 2007

Boz0r posted:

I'm supposed to do the countdown from the service, so I don't think I can have it as an internal class in the Activity.

EDIT: Can I carry a reference to MainActivity through to the service somehow?

EDIT: I've come a little further:

http://pastebin.kde.org/p3zvxowci

I think the only problem left is, that the onReceive doesn't trigger, and I can't see why.

At this line in your service:

code:
Intent progressIntent = new Intent(context, MainActivity.ProgressReceiver.class);
progressIntent.setAction(MainActivity.PROGRESS_ACTION);
Should be:
code:
Intent progressIntent = new Intent(MainActivity.PROGRESS_ACTION);
Since you registered the PROGRESS_ACTION event in your activity you can skip straight to that action. That action string should also include the application package before your action, to prevent any collisions (so "com.yourapp.handin2.progress_action"). Specifying the class is typically only done when you want to launch a new activity, in this case you should use the action string intent constructor with the fully formed ID that you registered in the activity.

When setting up a broadcastreceiver, you should never need direct contact between the receiver and sender.

zeekner fucked around with this message at 18:37 on Nov 24, 2013

Boz0r
Sep 7, 2006
The Rocketship in action.
I've made the changes you mentioned but it still doesn't work :(

This is the revised code: http://pastebin.kde.org/pbbprijzb

Do I need to change anything in the manifest file or something?

EDIT: If I just invoke sendBroadcast(progressIntent) instead of setting the alarm, it still doesn't work.

Boz0r fucked around with this message at 21:19 on Nov 24, 2013

zeekner
Jul 14, 2007

I'm not sure why that code isn't working, but I was just able to create a simple broadcast with this:

code:
public class MainActivity extends Activity {
    public static final String ACTION_BROADCAST = "com.salvadordalvik.broadcast.testbroadcast";
    private TestBroadcast broad = new TestBroadcast();

    private class TestBroadcast extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(MainActivity.this, "Broadcast received: "+intent.getLongExtra("time", 0), Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onResume() {
        super.onRestart();
        registerReceiver(broad, new IntentFilter(ACTION_BROADCAST));
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(broad);
    }
}
From a service (or anywhere else) I could call this:
code:
sendBroadcast(new Intent(MainActivity.ACTION_BROADCAST).putExtra("time", System.currentTimeMillis()));
The only real difference is that I register/unregister as part of the resume/pause lifecycle, which you should do so you don't leave any dead references.

Boz0r
Sep 7, 2006
The Rocketship in action.
I got it working. I don't know how, though. I tried going through the things you did and it worked. Even though I already did the same. Thanks.

Boz0r
Sep 7, 2006
The Rocketship in action.
I have an activity with two different views. If you're on a tablet, the view has two fragments, one of them is a list, and the other is a text field. When you click on an item on the list, it shows some text on the text field. If you're on a phone, the activity only contains the list, and starts a new activity with the text field when you select one.

I don't know how to do the second one. I've done the update of the other fragment, but I can't see how I can update a new Activity's Fragment's text field.

Here's how I've done the first one, it's in the list fragment:
code:
listView.setOnItemClickListener(new OnItemClickListener() {
				
				@Override
				public void onItemClick(
						AdapterView<?> parent, 
						View view, 
						int position,
						long id) {
					Log.w("listview", "onItemClick, twopane");
					
					int itemPosition = position;
					
					String itemValue = (String) listView.getItemAtPosition(position);
					
					Intent intent = new Intent(activity, ContentActivity.class);
									
					ContentFragment fragment = new ContentFragment();
					
					fragment.setText(values[position]);										
					
					FragmentManager fm = getFragmentManager();
					FragmentTransaction transaction = fm.beginTransaction();
					transaction.replace(R.id.content_fragment, fragment);
					transaction.commit();					
				}			
			});
Any ideas?

A COMPUTER GUY
Aug 23, 2007

I can't spare this man - he fights.
Why not pass the text as an extra to the new activity?

Tunga
May 7, 2004

Grimey Drawer
You might also consider using a ViewPager such that both Fragments are part of the same activity.

GenJoe
Sep 15, 2010


Rehabilitated?


That's just a bullshit word.
So I have an app that authenticates the user with a third party website using account information that the user supplies. Right now I am storing their username/passwords in plaintext on the app's internal file storage so they don't have to supply this information every time the app connects to the website. The files are supposed to be private to the application, but I would still like to encrypt the user information because of obvious reasons.

Hashing here isn't going to work, because the app has to post the unencrypted passwords to the website, so what is going to be the best way to encrypt and decrypt the data to and from storage? I don't have much experience with cryptography, doubly so with doing it in the context of an android app, so any help would be appreciated.

Sereri
Sep 30, 2008

awwwrigami

GenJoe posted:

So I have an app that authenticates the user with a third party website using account information that the user supplies. Right now I am storing their username/passwords in plaintext on the app's internal file storage so they don't have to supply this information every time the app connects to the website. The files are supposed to be private to the application, but I would still like to encrypt the user information because of obvious reasons.

Hashing here isn't going to work, because the app has to post the unencrypted passwords to the website, so what is going to be the best way to encrypt and decrypt the data to and from storage? I don't have much experience with cryptography, doubly so with doing it in the context of an android app, so any help would be appreciated.

Do you have to present the password with every request? Can't you just save cookies or something similar?

GenJoe
Sep 15, 2010


Rehabilitated?


That's just a bullshit word.

Sereri posted:

Do you have to present the password with every request? Can't you just save cookies or something similar?

No, cookies will keep the user logged in for the current session, so its more an issue of keeping the password stored for subsequent sessions. There are two problems with not storing any user information at all. First is that I don't want the app to prompt the user for a password every time they start the app up again (the entire app revolves around connecting to this website and retrieving data from it, so that would really mess with the user experience). The second is that the app will poll the website at scheduled intervals in the background, so the user will not always be there to supply their information to the app.

TheReverend
Jun 21, 2005

I feel like I'm losing my mind.

I had an application I was working on, and when you started it, onstart was called.

When you changed the orientation, onpause and then onresume were called.

All was right with the world.

Now all of a sudden, onstart is being called when the screen oritentation changes.

Any idea what is happening?

zeekner
Jul 14, 2007

TheReverend posted:

I feel like I'm losing my mind.

I had an application I was working on, and when you started it, onstart was called.

When you changed the orientation, onpause and then onresume were called.

All was right with the world.

Now all of a sudden, onstart is being called when the screen oritentation changes.

Any idea what is happening?

Are you handling the configuration change by specifying the manifest entry "configChanges=orientation|screenSize|keyboardHidden"?

Because without that you should be seeing a full application lifecycle on rotation, from onPause to onDestroy and onCreate back to onResume.

One thing that changed is that before 3.x, you only had to specify configChange=orientation|keyboardHidden for that hack to work, but now you have to include screenSize for it to have the same effect.

zeekner fucked around with this message at 23:21 on Dec 6, 2013

TheReverend
Jun 21, 2005

Salvador Dalvik posted:

One thing that changed is that before 3.x, you only had to specify configChange=orientation|keyboardHidden for that hack to work, but now you have to include screenSize for it to have the same effect.
Well that fixed it. I had orientation|keyboard before you told me to add in screensize.


That's really the default behavior though? I thought it was pause-resume for screen changes. That seems undesirable. Or is it desirable and I'm not doing stuff right?

Oh well thank you!

zeekner
Jul 14, 2007

TheReverend posted:

Well that fixed it. I had orientation|keyboard before you told me to add in screensize.


That's really the default behavior though? I thought it was pause-resume for screen changes. That seems undesirable. Or is it desirable and I'm not doing stuff right?

Oh well thank you!

It is a bit of a pain, but you should be using onSaveInstanceState so you can handle the other situations where your activity will be killed and need to be recreated.

It's covered in the docs here:
http://developer.android.com/guide/topics/resources/runtime-changes.html

That rotation hack is legitimately useful, but don't rely on it alone.

Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

TheReverend posted:

Well that fixed it. I had orientation|keyboard before you told me to add in screensize.


That's really the default behavior though? I thought it was pause-resume for screen changes. That seems undesirable. Or is it desirable and I'm not doing stuff right?

Oh well thank you!

It's desirable. Consider the case where you have separate layouts for portrait and for landscape. The safest way to handle this is to recreate the activity and inflate the new layout. If you know you can handle these config changes yourself, you can declare that you do, but you should still be able to recreate your state as appropriate (say the locale changes due to someone's notification's pending intent).

See http://developer.android.com/guide/topics/manifest/activity-element.html#config for more great possibilities to your code barfing.

Jarl
Nov 8, 2007

So what if I'm not for the ever offended?
Is there a way to get a method invocation from the OS, when a user uninstalls the app, so that relevant files created on the disk can be deleted (like an uninstaller in windows would)?

Sereri
Sep 30, 2008

awwwrigami

Jarl posted:

Is there a way to get a method invocation from the OS, when a user uninstalls the app, so that relevant files created on the disk can be deleted (like an uninstaller in windows would)?

Stack Overflow posted:

Sadly android at the moment does not give you a possibility to perform code at the moment your app is uninstalled.

All the settings that are set via the SharedPreferences are deleted together with everything in the Aplication Data an Cache folder.

The only thing that will persist is the data that is written to the SD-Card and any changes to phone settings that are made. I don't know what happens to data that is synchronized to the contacts through your app.

You could however place your files on the SD card with Context.getExternalFilesDir(). Files in this directory will be removed with the app.

Jarl
Nov 8, 2007

So what if I'm not for the ever offended?

Sereri posted:

You could however place your files on the SD card with Context.getExternalFilesDir(). Files in this directory will be removed with the app.

Thanks. Much better actually.

surc
Aug 17, 2004

I'm having issues with a MediaPlayer, and I'm hoping somebody in here could shed some light.
I've got a viewpager, and when you click on an image displayed in it, it plays an audio file associated with it. While setting it up to stop playing the audio if you go to the next page, I ran into some errors. Stackoverflow (unsurprisingly) has like 300 conflicting opinions on what the proper way to stop and start playback is for MediaPlayers, so I have less of an idea of what's needed then I did going in. Could somebody please help me figure out if there's just some specific configuration of .stop() .reset() .release() .prepare() and .start() I need?


From what I can tell, I basically want:

code:
mediaPlay.stop();
mediaPlay.reset();   //Unsure about if I should have this here or in the start code? People say different things.
mediaPlay.release();
when I stop it, and
code:
mediaPlay.reset(); //Unsure if I need this here or after I stop it?
mediaPlay.setDataSource(source);
mediaPlay.prepare();
mediaPlay.start();
when I start it. And maybe I have to do something about making mediaPlayer null and doing things if it's not null?


Attempting to use stackoverflow solutions ended with me getting null pointer exceptions or state errors, and the MediaPlayer state diagram (http://developer.android.com/reference/android/media/MediaPlayer.html#StateDiagram), while interesting and informative, didn't actually help me understand where and what I needed to call when stopping and starting.

genki
Nov 12, 2003

surc posted:

I'm having issues with a MediaPlayer, and I'm hoping somebody in here could shed some light.
I've got a viewpager, and when you click on an image displayed in it, it plays an audio file associated with it. While setting it up to stop playing the audio if you go to the next page, I ran into some errors. Stackoverflow (unsurprisingly) has like 300 conflicting opinions on what the proper way to stop and start playback is for MediaPlayers, so I have less of an idea of what's needed then I did going in. Could somebody please help me figure out if there's just some specific configuration of .stop() .reset() .release() .prepare() and .start() I need?


From what I can tell, I basically want:

code:
mediaPlay.stop();
mediaPlay.reset();   //Unsure about if I should have this here or in the start code? People say different things.
mediaPlay.release();
when I stop it, and
code:
mediaPlay.reset(); //Unsure if I need this here or after I stop it?
mediaPlay.setDataSource(source);
mediaPlay.prepare();
mediaPlay.start();
when I start it. And maybe I have to do something about making mediaPlayer null and doing things if it's not null?


Attempting to use stackoverflow solutions ended with me getting null pointer exceptions or state errors, and the MediaPlayer state diagram (http://developer.android.com/reference/android/media/MediaPlayer.html#StateDiagram), while interesting and informative, didn't actually help me understand where and what I needed to call when stopping and starting.
Uh, I guess I'm just curious what the first few points after the state diagram don't clear up for you? Highlighting what I consider most relevant.

quote:

When a MediaPlayer object is just created using new or after reset() is called, it is in the Idle state; and after release() is called, it is in the End state. Between these two states is the life cycle of the MediaPlayer object.
- There is a subtle but important difference between a newly constructed MediaPlayer object and the MediaPlayer object after reset() is called. It is a programming error to invoke methods such as getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare() or prepareAsync() in the Idle state for both cases. If any of these methods is called right after a MediaPlayer object is constructed, the user supplied callback method OnErrorListener.onError() won't be called by the internal player engine and the object state remains unchanged; but if these methods are called right after reset(), the user supplied callback method OnErrorListener.onError() will be invoked by the internal player engine and the object will be transfered to the Error state.
- It is also recommended that once a MediaPlayer object is no longer being used, call release() immediately so that resources used by the internal player engine associated with the MediaPlayer object can be released immediately. Resource may include singleton resources such as hardware acceleration components and failure to call release() may cause subsequent instances of MediaPlayer objects to fallback to software implementations or fail altogether. Once the MediaPlayer object is in the End state, it can no longer be used and there is no way to bring it back to any other state.
- Furthermore, the MediaPlayer objects created using new is in the Idle state, while those created with one of the overloaded convenient create methods are NOT in the Idle state. In fact, the objects are in the Prepared state if the creation using create method is successful.
Either you need to create a new mediaplayer for every new audio file, or you need to accept that your media player will not release resources used by the internal player engine blah blah. I don't believe that's the end of the world, so most likely the answer you're looking for is "keep the media player reference while you need it, only call stop() to stop it, then call reset()/setDataSource()/prepare()/start() when you want to play a new file".

surc
Aug 17, 2004

I don't know how I missed that when I was going through the documentation, guess I was taking a bit of a mental holiday. :doh:
Got it working now though, thanks!

Jarl
Nov 8, 2007

So what if I'm not for the ever offended?
If you have an activity which is popped (e.g. through back), and you want some part of the UI to remain the same the next time the user returns, although it should be reset when the app is actually restarted (i.e. a new task), then what is the best way to go about that?

onSaveInstanceState() is not the way since it is not a kill or device configuration change that is a problem (although this should also be supported, that is a different matter). Using PreferenceManager doesn't seem the right way to go about it, since when the app is restarted then the UI in the activity should go back to default.

surc
Aug 17, 2004

Jarl posted:

If you have an activity which is popped (e.g. through back), and you want some part of the UI to remain the same the next time the user returns, although it should be reset when the app is actually restarted (i.e. a new task), then what is the best way to go about that?

onSaveInstanceState() is not the way since it is not a kill or device configuration change that is a problem (although this should also be supported, that is a different matter). Using PreferenceManager doesn't seem the right way to go about it, since when the app is restarted then the UI in the activity should go back to default.

There might be a better way to do this, but I would probably use onPause() to save the data and use an onCreate() in an Application class, which will be called only when the whole application is created, to set it to the default.

IAmKale
Jun 7, 2007

やらないか

Fun Shoe
I'm having a problem upgrading my app's database. For background, my app's a J-E dictionary that relies on a prepopulated database for its entries, sample sentences, etc... Right now I'm trying to figure out a way to upgrade the database itself with a new one I compiled from updated sources.

I have 95% of the upgrade process figured out, but I'm running into a problem where backed up, user-generated information isn't being committed to the new database file. Rather, it looks as though the Content Provider is writing everything to a journal, which is bad because even though the user's content appears to survive the upgrade, force-closing the app blows away the journal file and basically leaves the user with a brand new installation.

Here's a high-level breakdown of how I'm handling the database upgrade:

1. Grab three cursors' worth of the user's information from the old database
2. Delete the old database
3. Instantiate a copy of the new database from the Expansion file
4. INSERT or UPDATE the user's information into the new database

Here's some actual code used in the SQLiteOpenHelper's OnUpgrade():

Java code:
// Back up tags, tags_vocab, and last_viewed from r_ele
Cursor cursorTags = db.rawQuery("SELECT...;", null);
Cursor cursorTagsVocab = db.rawQuery("SELECT...;", null);
Cursor cursorLastViewed = db.rawQuery("SELECT...;", null);

// Delete the old database
gContext.deleteDatabase(DATABASE_NAME);

// Install the new database (this just expands the new database from the Main Expansion file, I know it works)
copyDatabaseFromOBB();

db = getWritableDatabase();
db.beginTransaction();

try
{
	// Restore user-generated tags
	while(cursorTags.moveToNext())
	{
		// Retrieve the label from the cursor
		String label = cursorTags.getString(cursorTags.getColumnIndex("label"));

		createNewTag(label);
	}

	// Restore user's tagged words
	while(cursorTagsVocab.moveToNext())
	{
		String seq = cursorTagsVocab.getString(cursorTagsVocab.getColumnIndex("seq"));
		String label = cursorTagsVocab.getString(cursorTagsVocab.getColumnIndex("label"));

		// Convert the Sequence Number into an FKey based since the FKey may have changed between databases
		Cursor cRFK = db.rawQuery("SELECT...;", null);
		cRFK.moveToFirst();

		// Get a Label's new ID since it may have changed when we restored the user's labels
		Cursor cTagID = db.rawQuery("SELECT...;", null);
		cTagID.moveToFirst();

		Integer iRFK = cRFK.getInt(cRFK.getColumnIndex("id"));
		Integer iTagID = cTagID.getInt(cTagID.getColumnIndex("id"));

		setTagOnWord(iRFK, iTagID);
	}

	// Restore entry timestamps that let us populate History
	while(cursorLastViewed.moveToNext())
	{
		String seq = cursorLastViewed.getString(cursorLastViewed.getColumnIndex("seq"));
		String dateTime = cursorLastViewed.getString(cursorLastViewed.getColumnIndex("date"));

		// Convert the Sequence Number into an FKey based since the FKey may have changed between databases
		Cursor cRFK = db.rawQuery("SELECT...;", null);
		cRFK.moveToFirst();
		Integer iRFK = cRFK.getInt(cRFK.getColumnIndex("id"));

		updateLastViewed(iRFK, dateTime);
	}

	db.setTransactionSuccessful();
}
finally
{
	// Commit the changes to the database?
	db.endTransaction();
}

// We're done with the cursors, release their resources
cursorTags.close();
cursorTagsVocab.close();
cursorLastViewed.close();
Everything appears to work fine, and db.setTransactionSuccessful() and db.endTransaction() are both called as though all of the user's information has been committed to the database without issue.

The weird part is that the createNewTag(), setTagOnWord(), and updateLastViewed() functions are the exact same ones I use elsewhere in the app to commit information to the database. I've verified that any time these functions are called in the course of using the app, the information is committed to the database file itself (I rooted my dev device so I can pull the database straight from the protected directory). It's only during the above upgrade process that the changes are only committed to the db-journal file.

What can I do to make this work?

IAmKale fucked around with this message at 19:43 on Dec 17, 2013

Cruseydr
May 18, 2010

I am not an atomic playboy.
Is the database actually deleted before you close the cursors? Maybe deleting it at the end would work correctly?

IAmKale
Jun 7, 2007

やらないか

Fun Shoe

Cruseydr posted:

Is the database actually deleted before you close the cursors? Maybe deleting it at the end would work correctly?
gContext.deleteDatabase(DATABASE_NAME) is supposed to handle that. I'm not sure that I can delete it at the end since the new database needs to use the same name as the old one.

That brings up another question I had: when I query the database, does the cursor that is returned contain the data itself, or references to the location of that data in the database?

Cruseydr
May 18, 2010

I am not an atomic playboy.

Karthe posted:

That brings up another question I had: when I query the database, does the cursor that is returned contain the data itself, or references to the location of that data in the database?

That's kind of what I was meaning, maybe it can't be fully deleted until the cursors close. Could you change it so that you make a new database, insert the old data, close the cursors, delete the old database, then rename the new database?

IAmKale
Jun 7, 2007

やらないか

Fun Shoe

Cruseydr posted:

That's kind of what I was meaning, maybe it can't be fully deleted until the cursors close. Could you change it so that you make a new database, insert the old data, close the cursors, delete the old database, then rename the new database?
You appear to be correct. I shifted things around so that the new database is created and populated under a temp name before deleting the old database and renaming the new database to the old database's name, and the user-generated information stuck around even after a force close of the app. Thanks for your help :)

Claeaus
Mar 29, 2010
I'm trying to use the onSaveInstanceState to save a "camera position" for a small 2D app and retrieve them with onRestoreInstanceState.

Stuff are being done in a SurfaceView that implements SurfaceHolder.Callback that starts a thread that does the drawing in the surfaceCreated function. In the onPause function I do setRunning(false).

The values get saved and read correctly. But the camera doesn't jump to the saved position until I touch the screen. I've tried resuming the thread that does the drawing in the onResume function and running the surfaceCreated function but nothing puts the camera in the correct position before touching the screen. Does anyone know how to solve this?

EDIT: Nevermind, I was just missing a function call :downs:. That's what you get for coding non-stop all day.

Claeaus fucked around with this message at 23:46 on Dec 22, 2013

Adbot
ADBOT LOVES YOU

IAmKale
Jun 7, 2007

やらないか

Fun Shoe
What's a good way to hardcode a "no ads" mode into my app so that ads are disabled on any device from which I personally run the app? I'm using Admob for ads and allow users to purchase a "no ads" upgrade via IAP. Unfortunately I'm unable to purchase the upgrade because I can't buy things from myself. This makes it impossible for me to run my app without ads unless I run the app in DEBUG mode (since I coded in an exception for that for development purposes), but I want to run the Play Store version on my phone so I can get the end-user experience (I develop on a separate device).

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply