A little help with trying to time an async task - android

Situation: I would like to pull a network resource (a file), display it for 30 seconds, then load the next file. While displaying the initial file for 30 seconds, I'd like to preload the next file.
Question: Should I be using concurrent threads with a lock (like a linked blocking queue?) or a handler? Or something I'm missing?
Currently I have the onCreate call an asynctask that has a for loop which iterates through an array of paths for the files one at a time, which then calls the next asynctask (inside the for loop) which downloads the file from that path and then in the onPostExecute assigns the file to the UI view.
This works but I am unable to setup timing where the first file loads in the UI view then 30 seconds later the next file loads in the UI view and so on... Right now it loads the files fine but the 1st may take 40 seconds to display and the 2nd 25 seconds and the 3rd 60.
(FYI, the files are uniform size and only take 5~15 sec to load)
Here's a general example (non compile-able):
onCreate(){
new firstAsynchTask().execute(filePaths[]);
}
private class firstAsynchTask extends AsyncTask<String[], Void, Void> {
protected Void doInBackground(String[]... x) {
try {
for(int i = 0; x[0] != null && i < x.length; i++)
{
long startT = System.currentTimeMillis();
if(x[0][i].isFile())
{
SmbFile g = new SmbFile(x[0][i].getPath());
new secondAsynchTask().execute(g);
long TimeNow = (System.currentTimeMillis() - 30000);
if(startT > TimeNow)
{
try {
Thread.sleep(startT - TimeNow);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();}
}
}
if(i == x.length - 1)
{
i = 0;
}
}
return null;
} catch (IOException e) {
// TODO Auto-generated catch block
return null;
}
}
private class SecondAsyncTask extends AsyncTask<File, Integer, Drawable> {
protected File doInBackground(File... x) {
SomeType FileTemp = new File();
try {
long startT = System.currentTimeMillis();
FileTemp = (get streamed file);
long TimeNow = (System.currentTimeMillis() - 30000);
if(startT > TimeNow)
{
Thread.sleep(startT - TimeNow);
return FileTemp;
}
else
{
return FileTemp;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
protected void onPostExecute(File result) {
if(result != null)
{
FileView centerFile = (FileView) findViewById(R.id.FileView1);
centerFile.setFile(result);
}
}
}

It looks like a simple producer-consumer approach would be sufficient for what you need. I would have an array of URLs that point to your network resource with a synchronised access. A single AsyncTask would be enough to pop a single URL off the queue, download and display it. How you will re-invoke the task depends on you: you can display downloaded resource and at the same time run task, putting downloaded resource to some temporary placeholder (a Drawable member field for example). Have a timer that every 30 seconds just puts temporary resource to the display and runs download/cache task again.
Of course this is a very simple solutions without handling cases when your task haven't finished in 30 seconds time frame, etc.
Another approach would be to have a boolean object that you will set to true every 30 seconds. Your AsyncTask runs, downloads image and on onPostExecute checks if previously mentioned boolean is set to true, if yes - displays image, sets flag to false and finishes. If flag is false then it enters a loop that sleeps for, say, 200ms and checks condition again, etc.

Related

Android play sound without lag

I want to play a horn sound in the app without any lag. I am using Media player class but its giving lag while playing file again.
code to run:
thread to improve the lag:(mp_horn is the media player instance we made from sound file) Below thread gives us much better result then making mediaplayer.setloop(true)
#Override
public void run() {
try {
if (mp_horn != null && mp_horn.isPlaying()) {
final long durationTotal_horn = mp_horn
.getDuration();
long durationCurrent_horn = mp_horn
.getCurrentPosition();
if (durationCurrent_horn >= (.90) * durationTotal_horn) {
// mp_engineContiue.seekTo((int)
// durationCurrent_back);
Log.v("arrrrrr", durationCurrent_horn
+ "......."
+ durationTotal_horn);
// mp_engineContiue.pause();
mp_horn.seekTo((int) (durationTotal_horn * .0000001));
}
}
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Probably
if (mp_horn != null && mp_horn.isPlaying())
should be :
if (mp_horn != null && !mp_horn.isPlaying())
otherwise while the Horn is playing you are doing all these calculations all over again, which I am guessing is causing the lag

Android Execute method / function if minute and hour is 00.0

How can I improve the performance of the code below? I have created method that will execute some other Method if Minute and Second of hour is 0, but I am still using looping and that is lagging my phone up to 30% mem usage, is there any suggestion to do that ?
this is my code
try {
do {
if ((Calendar.getInstance().get(Calendar.MINUTE) == 0) && (Calendar.getInstance().get(Calendar.SECOND) == 0)){
UtilitiesService.InitLoggingService(getApplicationContext());
blnPerfect = true;
//return null;
break;
//stopSelf();
}
} while (!blnPerfect);
} catch (Exception e) {
e.printStackTrace();
}
You can calculate the time to 0,0 and Start a Single Shot thread
Executors.newSingleThreadScheduledExecutor().schedule(new Callable() {
public Void call() {
doSomething();
return null;
}
}, X, TimeUnit.SECONDS);
Why don't you simply calculate how long you have to wait until the time is at the ZEROth minute and ZEROth second ... but seeing how long you need to wait, converting to milliseconds, an sleeping for that long?
Also, you should do this "event" timing in an asynchronous task/thread.

thread start/stop does not work correct on android

I need some help with starting/stopping my monsters.
We generate like this:
for (int i = 0; i < 20; i++) {
boolean notFree = true;
int x = 0, y = 0;
// while not free change
// not determinstisch setting!
while (notFree) {
x = (int) (Math.random() * Config.XSIZE);
y = (int) (Math.random() * Config.YSIZE);
if (map.getMapPosition(x, y) == Config.EMPTYPOSITION) {
notFree = false;
}
}
switch ((int) Math.floor(Math.random() * 2)) {
case 0:
monsterVerktor.add(new Monster(context, x, y, this.map, 1,
this.charac));
break;
case 1:
monsterVerktor.add(new DeathReaper(context, x, y, this.map, 1,
this.charac));
break;
default:
break;
}
}
And I stop them like this: (Start is same just with Startmoving...)
public void stopAllMonsters() {
for (Monster monster : monsterVerktor) {
monster.getControl().stopMovingThread();
}
}
The thread.stopMovingThread works like this:
public void stopMovingThread() {
this.monster.setAlife(false);
running = false;
moveDone = true;
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
To the run():
public void startMovementThread() {
running = true;
thread = new Thread() {
#Override
public void run() {
while (running) {
Log.d(TAG, "run Thread");
// get a little randomness in the movement ;)
try {
// up to 0.5s sleeping till next moving
sleep(new Random().nextInt(Config.RANDOMSLEEP));
} catch (InterruptedException e1) {}
while (monster.isAlife()) {// check if alife
moveDone = false; // resett movement Done
noMove = false;
// Charakter in near if one is in near he
// will move to it.
if (!checkCharInAggroRange()) {
noMove = rndMove(); // if we have no move
}
while (!moveDone) {
timeBegin = System.currentTimeMillis();
// if hes not done with the move
if (monster.moveToX == monster.positionX
&& monster.moveToY == monster.positionY) {
if (noMove) {
try {// sleep because no movement with a bit
// randomness
sleep(Config.MONSTERMOVINGTIME
+ (new Random()
.nextInt(Config.RANDOMSLEEP)));
} catch (InterruptedException e) {
Log.d(TAG,
"An error occured during sleep because"
+ " of no Animatino");
}
}
// false after sleep
moveDone = false;
break; // already at the right position!
// movetoX is left of position
} else if (monster.moveToX > monster.positionX) {
monster.positionX++;
// movetoX is left of it
} else if (monster.moveToX < monster.positionX) {
monster.positionX--;
// movetoY is left of position
} else if (monster.moveToY > monster.positionY) {
monster.positionY++;
// movetoY is left of position
} else if (monster.moveToY < monster.positionY) {
monster.positionY--;
}
// sleep if hes moving to fast!
timeDiff = System.currentTimeMillis() - timeBegin;
sleepTimer = (int) (Config.MONSTERTIMING - timeDiff);
if (sleepTimer > 0) { // if >0 we are fast enough
// and can sleep a bit ;)
try {
sleep(sleepTimer);
} catch (InterruptedException e) {
Log.d(TAG, "Gameloop thread cant sleep");
}
}
}
}
try {
sleep(Config.RESPAWNTIMER);
} catch (InterruptedException e) {
Log.d(TAG, "Monsterthread cant sleep");
}
// respawn it after a sleep :)
respawn();
}
}
};
thread.start();
}
Android stops working if we want to stop them and start them like this, and I dont get it why. We also stop/start our render like this. (Well it's a runable and this isn't)
Monster isAlife and etc:
public class Monster extends Drawable {
private static final String TAG = Monster.class.getSimpleName();
private int fullLife; // full life
private int curLife; // current life
public Context context;
private Character charac;
// ..
// Basic monsterstuff
private boolean alife, moveDone;
private int level;
public Status status;
private MonsterControl control;
// ..
public Monster(Context context, int mapPosX, int mapPosY, Map map,
int level, Character cha) {
this.context = context;
this.map = map;
this.setCharac(cha);
this.mapPosition[0] = mapPosX;
this.mapPosition[1] = mapPosY;
this.status = Status.IDLE;
// example for full life calculation
this.fullLife = level * 100 + ((int) (Math.random() * 10 * level)); // Examples
this.curLife = this.fullLife;
this.map.setMapPosition(mapPosX, mapPosY, Config.MONSTERSTATE);
// set monster position
// ..
// load the sprite bitmap
// ...
// Change this later!
alife = true;
Log.d(TAG, "Monster created");
// Starting the Controler
control = new MonsterControl(this, this.charac);
control.startMovementThread();
Log.d(TAG, "Monster start moving");
// exemplarisch cut of the sprite
this.monsterPicAnimation();
}
}
here the getter/setter for aLife
public boolean isAlife() {
return alife;
}
public void setAlife(boolean alife) {
this.alife = alife;
}
First off, your comment of "Android stops working", Are you implying a crash? Got a LogCat trace?
Other than that is this analysis correct?
1.Create a monster.
running = true;
isAlife = true; //or whatever monster.isAlife() checks
2.Thread starts.
while (running) {
...
while (monster.isAlife()) {
...
}
}
3.You try to stop the thread by (1) setting running to false, and (2) joining on the thread?
Assuming that is all true. The monster thread still runs until something kicks it from the nested while(monster.isAlife()) loop. Once that ends, the while(running) will evaluate false and the thread should terminate, moving on to the next monster in your collection. Without this ever terminating you'll be waiting on each monster to die while locking your main thread with join().
Apart from the logic of your code which I haven't looked at in details, there is a lack of synchronization around shared variables. In particular, as it is, your code provides no guarantee that your thread (in startMovementThread) will ever be able to observe the changes made to your flags from the main thread.
A good first step would be to make those variables volatile:
private volatile boolean alife, moveDone;
Note however that there might be other issues (depending on your requirements). For example, when those statements are executed in startMovementThread:
if (monster.moveToX == monster.positionX ...)
monster.positionX++;
any changes made in that thread might not be visible from the main thread and vice versa. If that can be an issue, you need to synchronize access to those variables too (and making them volatile will not be enough because, for example, monster.positionX++ is not atomic).
I solved it myself with and "good" idea.
The problem was, that i let them sleep at some points. If they sleep it cant stop/join the thread and even dont watch if its "running". So i solved it with a small methode that looks like this:
private void breakableSleep(int i, int intervall){
int x = 0;
while(running && x <= i){
try {
this.thread.sleep(intervall);
} catch (InterruptedException e) {
Log.d(TAG, "Monsterthread cant sleep");
}
x++;
}
}
it can be stoped at every intervall. Sure it will cost some Battery but did not finde any other way to stop the Monsters in a "fast" way because some sleep for around 3seconds if they died (respawning)
I also rewrote the whole startMovementThread because it did not look well in my opinion.
Best Regards

TTS callback: dispatch completed to 1

I created a small TTS app implementing OnUtteranceCompleteListener and, while things seem to be working exactly as expected, I noticed the following on LogCat (one for each completed utterance):
03-01 20:47:06.436:
VERBOSE/TtsService(381): TTS callback:
dispatch completed to 1
Again, this seems to be benign but I don't understand what '1' means. All such lines for all utterances say "completed to 1", even for utterance IDs that are greater than 1.
What does '1' mean in this log?
BTW, this message is not generated by my code but rather by the TTS engine (Pico) itself.
Looking at the TTSService.java source code available at http://eyes-free.googlecode.com you can find the function dispatchUtteranceCompletedCallback():
private void dispatchUtteranceCompletedCallback(String utteranceId, String packageName) {
/* Legacy support for TTS */
final int oldN = mCallbacksOld.beginBroadcast();
for (int i = 0; i < oldN; i++) {
try {
mCallbacksOld.getBroadcastItem(i).markReached("");
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
try {
mCallbacksOld.finishBroadcast();
} catch (IllegalStateException e) {
// May get an illegal state exception here if there is only
// one app running and it is trying to quit on completion.
// This is the exact scenario triggered by MakeBagel
return;
}
/* End of legacy support for TTS */
ITtsCallbackBeta cb = mCallbacksMap.get(packageName);
if (cb == null) {
return;
}
Log.v(SERVICE_TAG, "TTS callback: dispatch started");
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
try {
cb.utteranceCompleted(utteranceId);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
mCallbacks.finishBroadcast();
Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
}
1 is the current value of N, which is initialized by the return value from mCallbacks.beginBroadcast().
beginBroadcast() is a method of the class RemoteCallbackList and its documentation states that it:
Returns the number of callbacks in the
broadcast, to be used with
getBroadcastItem(int) to determine the
range of indices you can supply
Does this help?

problem is in ASyncTask class in Android

basically i am reading image bytes from file i have a loop which has to read almost 20 images from file and in this loop i have making the object of my class which extends ASyncTask class and i am reading bytes and drawing on canvas in doItBackground() method and setting my image on onPostExecute() method. so basically Asynchronously 20 threads starts execution in background. now problem is it is not showing any image.
anybody have any idea how to handle multiple AsyncTask class? here is my code.
#Override
protected Void doInBackground(Void... params)
{
// Log.i("start background thread", "start background thread");
Set<Integer> keys;
keys = iTileListOffsets.keySet();
boolean found = false;
Object key[] = keys.toArray();
int k = 0;
for (int i=0; i < key.length && found==false ; i++)
{
k = (Integer) key[i];
MapTileHeader tileHeader = iTileListOffsets.get(k);
if (tileHeader.equalsWith(mapTile.getiMapTileHeader()) )
{
found = true;
}
}
if(found)
{
try
{
synchronized (MapMaker.getSingletonObject())
{
fc.position(0);
input.skipBytes(k);
int tSizeOfTile = input.readInt();
mapTile.loadTileWithFileHeader(input, tSizeOfTile, headerBytesArray);
}
mapMaker.getBufferedTilesDataList().add(mapTile);
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
byte imageTile[] = mapTile.getImageTilesBytes(); //bufferedTile.getImageTilesBytes();
if(mapTile.getImageTilesBytes() != null)
{
try
{
Bitmap tileBitmap = BitmapFactory.decodeByteArray(imageTile, 0, imageTile.length);
canvas.drawBitmap(tileBitmap, rect.left, rect.top, null);
tileBitmap = null;
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
// Log.i("ENDDDD background thread", "ENDDD background thread");
return null;
}
#Override
protected void onPostExecute(Void result)
{
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.i("start POSTECEXCUTE thread", "start POSTECEXCUTE thread");
MyRect mapRect = aBufferArea.GetScreenRectangle(buffer, aScrnArea);
Bitmap smallBitmap = Bitmap.createBitmap(bitmap, mapRect.left, mapRect.top, mapRect.width, mapRect.height);
image.setImageBitmap(smallBitmap);
Log.i("ENDDDDD POSTECEXCUTE thread", "ENDDDD POSTECEXCUTE thread");
}
thanks
I dont think you can update the UI directly from doInBackground, as the code in this method is run in a backgound thread and does not have direct access to the IU thread. You can update the UI either from onPostExecute or from onProgressUpdate. You can call the latter of these from doInBackground by calling publishProgress.
There is a simple example in the documentation for AsyncTask, and this one is a little more complex.
I'd like to suggest a slightly different way of thinking about the problem. Instead of having a thing in the background which both downloads and draws the bitmaps, you might try making the doInBackground method decode and return the Bitmap, then draw it onto the canvas in onPostExecute. This arrangement should prevent you from having contention on the canvas.
Looking at the code you've posted, the loaded bitmaps get drawn onto canvas. Then bitmap gets displayed in image. I can't see, in the code you posted, anywhere that the loaded bitmaps canvas gets sent to the screen.
It might be worth double-checking that the image you're drawing to has a large enough height and width.

Categories

Resources