Not able to execute loop based on thread.sleep - android

I'm trying to display a series of images from a specific folder in sdcard - in the form of slideshow. filelist[] contains names of all files present in that directory.
I'm filtering out the images here. Next, thread.sleep(1000) does not seem to have any effect. Only the last image in the directory is displayed after a time of 1000ms. Where am I going wrong? Any other way I could accomplish this?
Maybe I've gone completely wrong. I'm a newbie so plz help.
public class List_imgActivity extends Activity {
/** Called when the activity is first created. */
Bitmap[] bitmapArray = new Bitmap[1000];
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button pf=(Button) findViewById(R.id.pick_button);
pf.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
Intent intent = new Intent("org.openintents.action.PICK_DIRECTORY");
intent.setData(Uri.parse("file:///sdcard"));
intent.putExtra("org.openintents.extra.TITLE", "Please select a folder");
intent.putExtra("org.openintents.extra.BUTTON_TEXT", "Use this folder");
startActivityForResult(intent, 1);
}
});
}
protected void onActivityResult(int requestCode, int recievecode, Intent intent)
{
if (requestCode == 1 )
{
Uri uri = intent.getData();
try {
File f=new File(new URI(uri.toString()));
final String nx=f.toString();
if(f.isDirectory()) {
File filelist[] = f.listFiles();
for(int i=0;i<filelist.length;i++)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String filename = filelist[i].getName();
int pos = filename.lastIndexOf(".");
String ext = filename.substring(pos);
if(ext.equals(".jpg"))
{
TextView tv1= (TextView) findViewById(R.id.textView1);
tv1.setText(filelist[i].toString());
ImageView iv1=(ImageView) findViewById(R.id.imageView1);
bitmapArray[i] = BitmapFactory.decodeFile(filelist[i].toString());
iv1.setImageBitmap(bitmapArray[i]);
}
}
}
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

In Android behaviour like this will make the UI-Thread sleep. This will freeze the whole UI of the phone your App will look crashed to the user and the System will automatically kill your application after a while.
There is a mechanism to change things in specific time intervalls. You should use this handlers for doing this. Handlers
A handler has a postDelayed and sendMessageDelayed methods that allow you to either build a Runnable that will be executed after a certain time or send a message that must be handled by the implementation of your handler.
The initialization of the handler would look something like this:
showNextImageHandler = new Handler() {
#Override
public void handleMessage(android.os.Message msg) {
showNextImage();
}
};
showNextImageHandler.sendMessageDelayed(showNextImageHandler.obtainMessage(), 1000);
This code creates a new handler that calls the function showNextImage every time it receives a message. I would store the Handler in an instance variable of your activity to send further messages later on. After the handler is created a first empty message is send in a way that will delay the posting of the message 1000 milliseconds. After a second the showNextImage function will be called. In this function you can change the view and if a next image exists you can post another delayed message to trigger another call to the function later on.

U Must synchronise the current object before applying Thread.sleep() method

Related

File Modification check on Android

I have written a loop that checks the file modification date on two files.
This is successful as far as the Toast text is concerned.
However I cannot seem to work out the syntax to actually compare the dates, comparing Date1 > Date2 is actually rejected by android studio.
Lots of advice on how to get the most recent modification date is on Stack Overflow, just not the answer as to how to craft the necessary if statement.
Any help would be most appreciated. (yes I have read documentation! Usage examples poor on this subject)
Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Email sync loop (maybe change for watcher method)
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(10000);
mHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "Loop", Toast.LENGTH_SHORT).show();
File file = new File(String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/Database1.db")));
if (file.exists()) {
Date lastModified = new Date(file.lastModified());
String modified = lastModified.toString();
Toast.makeText(MainActivity.this, modified, Toast.LENGTH_LONG).show();
}
File file2 = new File(String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/Database2.db")));
if (file2.exists()) {
Date lastModified2 = new Date(file2.lastModified());
String modified2 = lastModified2.toString();
Toast.makeText(MainActivity.this, modified2, Toast.LENGTH_LONG).show();
}
}
});
} catch (Exception e) {
// TODO: handle exception
}
}
}
}).start();
}
You don't need the separate thread, the loop and the sleep() call, you can simply schedule the check on the Handler instance using postDelayed() method. It will be executed on the main thread which is perfectly fine for you and won't block the app. As a final step in your Runnable instance you can schedule it again, so it will run in a loop.
If you want to stop it then call removeCallbacksAndMessages(null) on the handler.
I am not sure what do you want to achieve with this, but maybe instead of doing a polling loop you can use FileObserver class for monitoring file changes, here is an example how to use it.
For comparing two dates you can always compare their millisecond values.
For e.g. date1.getTime() > date2.getTime()
getTime() method returns the time in milliseconds and it is a long value that can be easily compared.

Android Multiple download pause resume in listview with progress update

I am trying to download multiple files in listview with progressbar. What I achieved is, I can start a particular download, pause/resume it using AsyncTask and progress bar is updated(for single file), this part works well
My problem is I am not able to download multiple files simultaneously and when I leave the listview to another screen although my download is going on in the background but progress is not updated, progress bar shows 0 progress as if it is not downloading but its been downloading in the background.
Finally I found the answer which was much simpler than I thought, here it is as follows
Create a service having Asynctask for downloading and hashtable of values(url, Asynctask)
Pass the value(url, Asynctask) when a list item is clicked and check whether that hashtable contain the value already if yes cancel that Asynctask task if no add it to hashtable and start Asynctask
now for updating progress in my adapter I ran a thread which iterate over hashtable and passes the value using BroadcastListener.
And in activity intercept the broadcast and depending on the ListItem visible update the progress
PS: If anybody needs some code I can provide basic code of the description explained above
public class DownloadingService extends Service {
public static String PROGRESS_UPDATE_ACTION = DownloadingService.class.getName() + ".progress";
private static final long INTERVAL_BROADCAST = 800;
private long mLastUpdate = 0;
private Hashtable<String, DownloadFile> downloadTable;
private LocalBroadcastManager broadcastManager;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MessageEntity entityRecieved = (MessageEntity) intent.getSerializableExtra("ENTITY");
queueDownload(entityRecieved);
return super.onStartCommand(intent, flags, startId);
}
private void queueDownload(MessageEntity entityRecieved){
if (downloadTable.containsKey(entityRecieved.getPacketID())) {
DownloadFile downloadFile = downloadTable.get(entityRecieved.getPacketID());
if (downloadFile.isCancelled()) {
downloadFile = new DownloadFile(entityRecieved);
downloadTable.put(entityRecieved.getPacketID(), downloadFile);
startDownloadFileTask(downloadFile);
} else {
downloadFile.cancel(true);
downloadTable.remove(entityRecieved.getPacketID());
}
} else {
DownloadFile downloadFile = new DownloadFile(entityRecieved);
downloadTable.put(entityRecieved.getPacketID(), downloadFile);
startDownloadFileTask(downloadFile);
}
}
#Override
public void onCreate() {
super.onCreate();
downloadTable = new Hashtable<String, DownloadFile>();
broadcastManager = LocalBroadcastManager.getInstance(this);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
void startDownloadFileTask(DownloadFile asyncTask) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
asyncTask.execute();
}
private void publishCurrentProgressOneShot(boolean forced) {
if (forced || System.currentTimeMillis() - mLastUpdate > INTERVAL_BROADCAST) {
mLastUpdate = System.currentTimeMillis();
int[] progresses = new int[downloadTable.size()];
String[] packetIds = new String[downloadTable.size()];
int index = 0;
Enumeration<String> enumKey = downloadTable.keys();
while (enumKey.hasMoreElements()) {
String key = enumKey.nextElement();
int val = downloadTable.get(key).progress;
progresses[index] = val;
packetIds[index++] = key;
}
Intent i = new Intent();
i.setAction(PROGRESS_UPDATE_ACTION);
i.putExtra("packetIds", packetIds);
i.putExtra("progress", progresses);
mBroadcastManager.sendBroadcast(i);
}
class DownloadFile extends AsyncTask<Void, Integer, Void> {
private MessageEntity entity;
private File file;
private int progress;
public DownloadFile(MessageEntity entity) {
this.entity = entity;
}
#Override
protected Void doInBackground(Void... arg0) {
String filename = entity.getMediaURL().substring(entity.getMediaURL().lastIndexOf('/') + 1);
file = new File(FileUtil.getAppStorageDir().getPath(), filename);
downloadFile(entity.getMediaURL(), file);
return null;
}
public String downloadFile(String download_file_path, File file) {
int downloadedSize = 0;
int totalSize = 0;
try {
// download the file here
while ((bufferLength = inputStream.read(buffer)) > 0 && !isCancelled()) {
progress = percentage;
publishCurrentProgressOneShot(true);
}
} catch (final Exception e) {
return null;
}
return file.getPath();
}
}
On big problem with AsynchTask is when you finish its activity, AsynchTask looses it's track with your UI. After that when you return back to that activity the progressBar is not updating even if the download progress still running in background. In fact that AsynchTask is not belong to the new Activity you lunched so the new instance of progress bar in new Activity will not updating.
To fix this problem I suggest you:
1- Run a thread with a timerTask in onResume() which updates ur progressbar with values updating from the AsyncTask running background. Something like this:
private void updateProgressBar(){
Runnable runnable = new updateProgress();
background = new Thread(runnable);
background.start();
}
public class updateProgress implements Runnable {
public void run() {
while(Thread.currentThread()==background)
try {
Thread.sleep(1000);
Message msg = new Message();
progress = getProgressPercentage();
handler.sendMessage(msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
}
}
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
progress.setProgress(msg.what);
}
};
and when your activity is not visible you must destroy the thread:
private void destroyRunningThreads()
{
if(background!=null)
{
background.interrupt();
background=null;
}
}
2- Define a global static boolean variable. Set it true in onPreExecute and in onPostExecute set it to false. It shows that you are downloading or not, so you can check if the variable is equal to true, show the previous progressbar dialog.(you can do something like this with an integer value-or array of integers- in order to show the update percentage for each download progress).
3- The last way I personally used is to show the download progress in Notification Bar and in my list view I just show that it is downloading right now or not.(using 2nd method with a boolean values). In this way even if you finish the activity the notification bar is still updated with download progress.
when you leave your activity, the activity that asynctask shows the progressbar is killed and thus the progressBar dose not show anymore when you come back on new activity because the asynctask dose not aware of your new activity.
General solution that will work in any cases for example when your user closes your app and again opens it and wants to know the progressBar is separating your presentation completely. that means you can create sharedPreferences or database table and put your state of your file in to it while your asynctask is downloading. for example every 500 milisecond update the sharedPreferences or database table with how much downloaded from total file size. then when user come back to your new activity you read from DB or sharedPreferences to show progressBar and update it every for example 1000 milisecond. In this way your user will know the progressBar even if he closes the app and opens it again. I know it takes a bit more work but it surely makes your users be happy.
in order to read and update at fixed rate you can use scheduleAtFixedRate

How to play video when there is no action perform on screen for 5 mins in Android?

I want when my app exit, after exit if there is no action perform on screen for 5 minutes a video will play every time, this video id define in my app.
Any help would be appreciated. Thankx in advance.
I have the following class but it is not worked fine, how can make the same code as Services ?
public class IdlePhoneState extends Activity {
Handler hl_timeout = new Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.main);
try{
hl_timeout.postDelayed(DoOnTimeOut, 120000); // 2 min
}catch(Exception e)
{
e.printStackTrace();
}
}
// Toast
Thread DoOnTimeOut = new Thread() {
public void run() {
try{
Toast.makeText(getApplicationContext(), "System is idle", Toast.LENGTH_LONG).show();
}catch(Exception e)
{
e.printStackTrace();
}
}
};
#Override
public void onUserInteraction()
{
super.onUserInteraction();
//Remove any previous callback
try{
hl_timeout.removeCallbacks(DoOnTimeOut);
hl_timeout.postDelayed(DoOnTimeOut, 120000);
System.out.println("ggggggggggggggggggggg");
Intent intr= new Intent(getApplicationContext(), VideoPlayerActivity.class);
startActivity(intr);
}catch(Exception e)
{
e.printStackTrace();
}
}
}
Do like below.
you should set an id on the outer-most element of your layout:
android:id="#+id/entire_view"
In java file find it like below.
View view = getViewById(R.id.entire_view);
Write touchlistener code for that root layout.
view.setOnTouchListener( ...
in the touch save the touched time to shared prefereces are something like that. Then compare the saved time with current time. if the difference exceeds five mins then play the video.
For time duration checking try to use Alarm Manager else use CountDownTimer.

If I finish an activity and call it again, it's attribute values still remain inside thread (RunOnUiThread)

In this case, I have 2 activities. I'm on Activity 1 and go to Activity 2. The application works as intended.
The problem starts when I go back to Activity 1, and start Activity 2 again.
See code below:
public class ScreenWActivity extends SerialComActivity {
private static final String tag = "ScreenWActivity";
private TextView mReception, m_tvDate, mtvPesoPercent, mtvState;
public String mCommand = null;
public int mActualProcess, mNextProcess;
private Commands mLastCommand;
public SettingsGlobal mSettings;
public int mAttempts = 0;
public long mStartTime, mTimeout;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_W);
this.mSettings = new SettingsGlobal(this); // get global settings
this.mtvState = (TextView) findViewById(R.id.tv_state); // label to update the current state
startSerialConnection(); // open serial port and start connection. inherited from SerialComActivity (the upper class)
this.mTimeout = 10; // timeout for commands response in seconds
this.mNextProcess = 1; // the next step in the process, its updated in the stepN() methods
this.mActualProcess = 1; // current step in the processo
this.mLastCommand = Commands.OPEN_DOOR; // the last command I've sent, to know what to expect in return
this.executeWorkflow(mNextProcess); // starts the workflow
}
private void step1(){
this.mtvState.setText("Closing door."); // update status
this.writeSerial(Commands.OPEN_DOOR.command("080").getBytes()); // sends the command to the outputstream, the external device reads the command, execute it and respond back
this.mNextProcess = 2; // the next step in the process is 2
this.mActualProcess = 1; // just tracking
this.mLastCommand = Commands.OPEN_DOOR;
startCounting(); // starts the timout, I've sent the command, now I wait for an answer
}
private void step2(){
this.mtvState.setText("Testando peso das balanças 1.");
this.writeSerial(Commands.GET_W.command().getBytes()); // get weight from weighing-machine
mLastCommand = Commands.GET_W; // the last command i sent i requested the weight - now I know what to expect
mNextProcess = 3; // next step in the sequence in case everything goes according to plan
this.mActualProcess = 2; // tracking
startCounting(); // starting timeout to get an answer
}
private void step3(){...}
private void step4(){...}
private void step5(){...}
private void step6(){...}
#Override
protected void writeSerial(byte[] buffer){...}
public void startCounting(){
mStartTime = System.currentTimeMillis();
timerHandler.postDelayed(timerRunnable, 0);
}
public void stopCounting(){
timerHandler.removeCallbacks(timerRunnable);
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
stopCounting();
timerRunnable = null;
if(this.mSerialPort != null)
this.mSerialPort.close();
this.mSerialPort = null;
if(AppConfig.DEBUG) Log.i(tag, "finishing!");
finish();
super.onDestroy();
}
public void executeWorkflow(int step) {
switch(step){
case 1:
step1();
break;
case 2:
step2();
break;
case 3:
step3();
break;
case 4:
step4();
break;
case 5:
step5();
break;
case 6:
step6();
break;
}
}
protected boolean validateReturn(String resposta) {
/// we check the command we've sent and the response we're given. if it matches, then we return true, else false
}
// overrided from SerialComActivity, called when the external equipment sends a message to us
// ITS CALLED WHEN THERE IS INPUT FROM THE EXTERNAL EQUIPMENT
#Override
protected void onDataReceived(final byte[] buffer, final int size) {
runOnUiThread(new Runnable() {
public void run() {
stopCounting(); // we remove the callbacks from the timeout thread
if( validateReturn(new String(buffer, 0, size).trim()) ){ // we check if the response is good
executeWorkflow(mNextProcess); // if its good, we move to the next step
}else{
mtvState.setText("invalid return"); // if not we message the user
executeWorkflow(mActualProcess); // we try again
}
}
});
}
// RESPONSIBLE FOR THE TIMEOUT
// the code below was created intending to implement a timeout timer for waiting a response from the external device
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
long millis = System.currentTimeMillis() - mStartTime;
long seconds = (millis / 1000);
timerHandler.postDelayed(this, 500);
if(mTimeout - seconds == 0 ){
mAttempts += 1;
if(mAttempts == 3){ // we make 3 attempts to get a response, if it is the third, we quit trying and give error
mAttempts = 0;
mtvState.setText("Could not communicate.");
stopCounting(); // we end the timer
}else{
executeWorkflow(mActualProcess); // if we can still try, we send the command again
}
}
}
};
}
Inside the method onDataReceived(), which is called everytime I get a response from the external equipment, I use the attribute mLastCommand (which indicates the last command I've sent), so this way I know how to validate the response I get.
When I go back to Activity 2, in the class scope the values of the attributes are the same as the ones I've defined in the onCreate() method. In the LogCat I saw that the attributes values are correctly defined as stated in OnCreate.
BUT, when the method onDataReceived (it's inside a Thread in the SerialComActivity class) is called (which is called when I get data from outside) the value of this same attribute mLastCommand is the same as the first time I started the activity, regardless of the value I define for it. As if the the runnable inside RunOnUiThread is still holding the old values from the first time I entered the activity, and outside of it the class has the values I have defined.
It's like having two different attributes with the same name in the ScreenWActivity.
I tried nulling the attributes inside the onDestroy() method, but to no avail.
Below is the code for the SerialComActivity class:
public abstract class SerialComActivity extends Activity{
SerialPort mSerialPort = null;
protected OutputStream mOutputStream;
protected InputStream mInputStream;
protected ReadThread mReadThread;
private class ReadThread extends Thread {
#Override
public void run() {
super.run();
while(!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[64];
if (mInputStream == null) return;
size = mInputStream.read(buffer);
if (size > 0) {
onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
protected void startSerialConnection(){
try {
mSerialPort = new SerialPort(new File("/dev/ttyS2"), 38400, 0);
} catch (SecurityException e) {
// TODO Auto-generated catch block
if(AppConfig.DEBUG)
Log.e("SERIAL", "portopen ERR: " + e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
if(AppConfig.DEBUG)
Log.e("SERIAL", "portopen ERR: " + e.getMessage());
}
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
/* Create a receiving thread */
mReadThread = new ReadThread();
mReadThread.start();
}
protected abstract void onDataReceived(final byte[] buffer, final int size);
protected abstract void writeSerial(byte[] buffer);
#Override
protected void onDestroy() {
if (mReadThread != null){
mReadThread.interrupt();
if(AppConfig.DEBUG) Log.i("ThreadSerial", "interrupting");
}
if(mSerialPort != null)
mSerialPort.close();
mSerialPort = null;
finish();
super.onDestroy();
}
}
I'm still in the process of learning Java and Android programming, so please forgive me if I'm doing something wrong. I looked up around, and the thing that you can't use variables other than "final" inside the RunOnUiThred came up. But I think it's not the issue, since it works the first time I start the activity.
Try doing your clean up in onPause() instead of onDestroy(), onDestroy() may not be called immediately which means there may be a read conflict on SerialPort. Also if you are already in onDestroy(), calling finish() doesn't really do anything.
Lastly, for a finite resource like SerialPort connection, it's better to put it in a Service.
I'm a newbie in Java, but I think I found out what was happening. The thing is that I asked the wrong question.
The problem is in the mInputStream.read(). As I've come to know, it's a blocking operation. I'm creating a thread that stays blocked in that read() method. After I finish the Activity, (go back to the first one), the thread keeps running. I know that because when a send some information through the serial interface, that thread responds.
So what I did, and it's working for me, altough many people stated that this method is not recommended is use mInputStream.available():
try {
if (mInputStream == null){ Log.i(tag,"returning"); return null ;}
Log.i(tag,"reading");
mEmptyStream = true;
while(mEmptyStream && !mFinish){
Log.i(tag,"input while");
/// checking if there is info, so we don't block the thread
if(mInputStream.available() > 0){
Log.i(tag,"input avail : " + InputStream.available());
//stream not empty
mEmptyStream = false;
size = mInputStream.read(buffer); //
}
}
if (size > 0) {
Log.i(tag,"size > 0 = " + new String(buffer, 0, size));
return new String(buffer,0,size);
}else{
Log.i(tag,"size <= 0");
}
}
Basically I loop using available(). When I finish the activity, in the onPause() method I set the field mFinish to true, this way the thread finds it's way out of execution and can end properly. It's the way I found and it's working so far. I improved the code significantly after the original post, like not running non UI jobs in the RunOnUiThread :)
But I tested it and it's working.

Android Rotation with IntentService

I have an application that uses IntentService to run a background task where I pull data from a website, parse the data out, and create calendar events based on the results. Everything seems to be working create, except I'm running into an issue with rotation.
Using the code below, when I rotate the screen, the ProgressDialog box stays visible, but is never updated with new text when the process is updated, and never goes away once the call is completed. I'm using an IntentService instead of an ASyncTask because the user can also schedule the IntentService to run at other times without having to interface with the app. Any help is appreciated, thanks!
public void onCreate(Bundle savedInstanceState) {
Object retained = getLastNonConfigurationInstance();
if (retained instanceof CalendarHandler) {
// CH is a class level variable defined at the top which references my IntentService, aptly named CalendarHandler
ch = (CalendarHandler) retained;
ch.setActivity(this);
} else {
ch = null;
}
activity = this;
btnLogin.setOnClickListener(OnClickListener(View view) {
ch = new CalendarHandler();
ch.setActivity(MyTlc.this);
// Do other stuff, like run the intent service
}
}
public Handler handler = new Handler() {
public void handleMessage(Message message) {
// We read the information from the message and do something with it
// based on what the result code is
String result = message.getData().getString("status");
if (result.equals("ERROR")) {
activity.removeDialog(PROGRESS_DIALOG);
results.setText(message.getData().getString("error"));
} else if (result.equals("DONE")) {
activity.removeDialog(PROGRESS_DIALOG);
int count = message.getData().getInt("count", 0);
activity.results.setText("Added " + count + " shifts to the calendar");
} else {
activity.pDialog.setMessage(result);
}
super.handleMessage(message);
}
};
From what I understand, this should work, and like I said the ProgressDialog box does stay properly, I just can't seem to pass information to the dialog box after rotating.

Categories

Resources