I have a few downloads that are submitted as tasks to a ThreadPoolExecutor. Now, I am creating this ThreadPoolExecutor in a global class that extends Application. I am storing all the submitted tasks in a HashMap with ids.
I have a ListView in a Fragment. This ListView item contains pause and resume buttons. When I click on the list item itself, the download FutureTask is submitted to the global pool executor. Now, when I click on the pause button of the ListView item, I want that particular thread to pause/wait.
I have the onClick method of the pause button in my list view's custom adapter. So, when I click the button, in my adapter class, I get all the threads that are currently running, put them in an array and then get the thread with the name I want from the array. I can see in my log that the thread I want to get is running with the name I set. So once I get that thread, I do wait() on it.
In the onclick of my resume button, I notify that particular thread and set the flag to pause as false so that the thread resumes. But, the download inside that thread actually keeps running even after clicking pause. I do not know where I am going wrong.
My GlobalState Class:
public class GlobalState extends Application{
HashMap<String, Future<?>> futureMapMain = new HashMap<String, Future<?>>();
ThreadPoolExecutor mainExec = new ThreadPoolExecutor(2, 2, 2000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new YourThreadFactory());
public void submitTaskMain(String name, Thread task){
Future<?> longRunningTaskFuture = mainExec.submit(task);
futureMapMain.put(name, longRunningTaskFuture);
}
public HashMap<String, Future<?>> getFutureMap(){
return futureMapMain;
}
public ThreadPoolExecutor getMainExeutor(){
return mainExec;
}
public class YourThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
return new Thread(r, gettName());
}
}
}
My Download Method that is written inside my fragment class. gets executed on list item click:
public void abDownloadTask(){
Thread dThread = new Thread(new Runnable() {
final Handler pdfHandler = new Handler();
#Override
public void run() {
for(something){
/* DOES SOME DOWNLOAD USING url.getcontent() with different urls in a loop and stores files to sd card. */
}
}
}
dThread.setName(threadname);
Log.d("Tel Frag", "Thread name set as: "+dThread.getName());
mainGs.settName(threadname);
mainGs.submitTaskMain(threadname, dThread);
}
onclick of my pause button inside custom list adapter:
pause.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
needToPause = true;
Runnable runnable = new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
Log.d("CLA", "Threads running size: "+threadArray.length);
Thread neededThread = null;
for ( Thread thread : threadArray ){
Log.d("CustomListAdapter", "Thread name in array: "+thread.getName());
if (thread.getName( ).equals(threadname)){
neededThread = thread;
}
}
if(neededThread!=null){
while(needToPause){
synchronized (neededThread) {
try {
neededThread.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
};
new Thread(runnable).start();
notifyDataSetChanged();
}
});
onclick of my resume button written inside custom list adapter class:
resume.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
needToPause = false;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for ( Thread thread : threadArray ){
if ( thread.getName( ).equals(threadname) ){
thread.notify();
}
}
notifyDataSetChanged();
}
});
I have been trying to figure it out for 2 days now but no luck. I went through a lot of examples and stackoverflow questions. I am just trying to get a thread by its name and then pause and resume it. Any help would be appreciated. Thank you!
You can't reliably use wait() and notify() on Thread objects. This is clearly stated in the Javadoc. You already have Future objects, you shouldn't be using other mechanisms anyway.
Related
I need to delete a value from SharedPreferences after 5 minutes or when the user finished to do something . So when I add that value I start this:
Activity A
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
}, Utils.TIME_BEFORE_DELETE);
and in the case users finished all I do this:
Activity B
mySharedPrefernces.removeValue(mContext, Utils.MY_VALUE);
But how can I stop the Handle into second activity?? Or is there another way to do it??
you can you boolean variable if you want to cancel this.
create public static boolean to check if the task is cancelled or not.
public static boolean isCanceled = false;
Use this in run() method
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (!isCanceled)
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
}, Utils.TIME_BEFORE_DELETE);
if you want to cancel then set:
isCanceled = true;
Runnable run = new Runnable() {
#Override
public void run() {
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
};
Handler handler = new Handler();
handler.postDelayed(run, Utils.TIME_BEFORE_DELETE);
//to dismiss pending runnable
handler.removeCallbacks(run);
A better way to do: Example code
publc static final Handler handler = new Handler();
public static final Runnable runnable = new Runnable() {
public void run() {
try {
Log.d("Runnable","Handler is working");
if(i == 5){ // just remove call backs
handler.removeCallbacks(this);
Log.d("Runnable","ok");
} else { // post again
i++;
handler.postDelayed(this, 5000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
//now somewhere in a method
b1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, 5000);
}
});
You can use handler.removeCallbacksAndMessages(null);. More information link
In this case you can use service with sticky flags. So you start service with intent "start_handler" and start handler also. When you need cancel handler you send the intent to stop handler and service. Or when time is passed and handler calls your code you should also stop service.
Using service with sticky flag provides possibility restoring handler. Also you need add some logic saving time when handler was run for correct restoring handler.
For that you can't use direct Runnable inside handler, you need to take one instance of it then you can do this like below,
Runnable myRunnable = new Runnable(){};
Then assign this in handler
handler.postDelayed(myRunnable);
And on no need use below line
handler.removeCallbacks(myRunnable);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//add your code hare
finish();
}
}, 10000);
by using this way you can stop your runnable in a fix time
Hi im trying to do an app that searchs bluetooth devices that are near every 5-10 seconds, so I tried to do an endless loop but the app is getting stuck when I press the button that starts the loop:
int stopInt=2;
serachB.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
do {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
listAdapter.clear();
getPairedDevices();
startDiscovery();
}
}, 4000);
} while (stopInt>1);
}
private final Handler mMyhandler = new Handler();
private final Runnable checkBluetoothRunnable = new Runnable() {
public void run() {
//Do your work here
mMyHandler.postDelayed(this, 5000);
}
};
serachB.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v){
mMyhandler.post(checkBluetoothRunnable);
}
}
}
Change it this way:
serachB.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
while(true){
listAdapter.clear();
getPairedDevices();
startDiscovery();
Thread.sleep(4000);
}
}
});
}}
You are continually creating new instances of Handler in your while loop which is going to eat up memory. I wouldn't be surprised if you were getting an OutOfMemoryError which is causing the termination. Try creating a single instance outside of your loop.
The Runnable passed to Handler runs on the UIThread since it was created on that thread. This should be avoided for lengthy operations and instead delegated to another thread.
When you create a new Handler, it is bound to the thread / message
queue of the thread that is creating it
Also, rather than using the Handler class you could potentially swap it out to use ScheduledThreadPoolExecutor which will give you a pool of threads which can then periodically execute your device discovery code.
Firstly create a ScheduledExecutorService:
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
Create an instance of your Runnable:
MyRunnable deviceDiscovery = new MyRunnable();
Then in your onClick method you kick off with scheduleAtFixedRate:
ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(deviceDiscovery, 0, 1, TimeUnit.MINUTES);
Then when you want to stop it running you need to call cancel on the ScheduledFuture:
future.cancel(true); // Set to true to say it can interrupt if already running
Right now I have one thread which populates the view of my activity. But I want another thread to add some textviews and imageviews in the same activity. I am using SurfaceView inside which I created this thread and I don't know how to add another thread so that it can contribute to the view of the current activity.
Help me out..
MyView view;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
view = new MyView(this);
setContentView(view);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
view.pause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
view.resume();
}
public class MyView extends SurfaceView implements Runnable {
Thread threadstill = null;
boolean isitok = false;
SurfaceHolder holder;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = getHolder();
}
#Override
public void run() {
// TODO Auto-generated method stub
while (isitok == true) {
if (!holder.getSurface().isValid()) {
continue;
}
canvas = holder.lockCanvas();
canvas.drawARGB(255, 255, 255, 255);
canvas.drawBitmap(<bitmapimage>, x, y, null);
holder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
isitok = false;
while (true) {
try {
threadstill.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
threadstill = null;
}
public void resume() {
isitok = true;
threadstill = new Thread(this);
threadstill.start();
}
}
You cannot directly manipulate the user interface from another thread.
The main thread is responsible for all UI changes.
However, if you want to perform some expensive work in the background (e.g. loading pictures) you can send the results to the UI thread.
Hava a look at the official documentation: https://developer.android.com/training/multiple-threads/communicate-ui.html
Or at a similiar question: How can I manipulate main thread UI elements from another thread in Android?
I don't exactly know what is your issue but regarding to I don't know how to add another thread so that it can contribute to the view of the current activity. you can create a new thread easily with a nested class...simply call:
Thread myNewThread = new Thread(new Runnable() {
public void run() {
//do code here
}
}).start();
But be Aware you can only change views from the UIThread so i would recommend you the AsyncTask:
public void myAsyncTask exstends Asynctask<Void,Void,Void> {
....
}
AsyncTask Comes with several methods the most important is the doInBackground where you can do the heavy things like Network Connections or other stuff which would freeze the UI or is simply not allowed on the UIThread(Network stuff).
After doInBackground is finished onPostExecute is called which runs on the UiThread and where you can process changes on your views.
To get more Information look at this link:
http://developer.android.com/reference/android/os/AsyncTask.html
Hope it helps and it is what you asked for. ;)
Do it with AsyncTask class. In doInBackground method download image, and in onPostExecute method apply image to ImageView.
I did it here already https://github.com/bajicdusko/AndroidJsonProvider/tree/master/app/src/main/java/com/bajicdusko/ajp/tools.
You can use my class or make your own .
I have an activity named BuildingActivity that extends ListActivity.
In the onCreate() method, i'm running 7 database queries in a background thread. In that background thread, I am building an ArrayList<String> object from the data returned from the queries.
Now, I want to return that ArrayList<String> object back to my BuildingActivity thread.
Here's part of the code that Im working on:
public class BuildingActivity extends ListActivity {
private ProgressBar mProgressBar;
public ArrayList<String> buildings;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_building);
new Thread(new Runnable() {
#Override
public void run() {
ArrayList<String> list;
DataSource dbSource = new DataSource(getApplicationContext());
dbSource.open();
list = dbSource.getBuildingsList();
dbSource.close();
//*** NOW HOW DO I PASS list BACK TO onCreate()?
//*** I WANT TO MAKE buildings = list.
}
}).start();
if(!buildings.isEmpty()) {
// do Something.
// If i do buildings = list in the background thread,
// This will always be executed because the background thread can take
// some time to return the data. How do i make sure this part of
// code is executed only after the data has been returned?
}
}
}
My objective after this is to create a list from this returned list of buildings. And on clicking a building, another activity shall open. How do I get about this problem?
Thanks!
How do i make sure this part of code is executed only after the data
has been returned?
Instead of using Thread for doing task in background use AsyncTask which provide doInBackground for performing operation in background and onPostExecute methods run on UI Thread after completing background task
here use this
public void myMethod(){
Thread background = new Thread(new Runnable(){
#Override
public void run(){
Looper.prepare();
//Do your data rerieval work here
Runnable r=new Runnable() {
#Override
public void run() {
//return your list from here
}
};
handler.post(r);
Looper.loop();
}
});
background.start();
}
Can someone explain to me 2 things about the thread code that I finally made almost working the way it should. I want to do a periodic task in the background every x seconds and be able to stop and start it at will. I coded that based on the examples I found, but I'm not sure if I made it in the right way. For the purpose of debugging, the task is displaying a time with custom showTime().
public class LoopExampleActivity extends Activity {
TextView Napis, Napis2;
Button button1,button_start,button_stop;
Handler handler = new Handler();
Boolean tread1_running = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Napis = (TextView) findViewById(R.id.textView1);
Napis2 = (TextView) findViewById(R.id.textView2);
button1 = (Button) findViewById(R.id.button1);
button_stop = (Button) findViewById(R.id.button_stop);
button_start = (Button) findViewById(R.id.button_start);
button_stop.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
tread1_running = false;
}
});
button_start.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
tread1_running = true;
}
});
thread.start();
}// endof onCreate
final Runnable r = new Runnable()
{
public void run()
{
handler.postDelayed(this, 1000);
showTime(Napis2);
}
};
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(tread1_running) {
sleep(1000);
handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
Now the questions are:
1)Will my thread quit forever if I stop it with the stop button?
2)Why can't I start it again with the start_button? If I add the tread.start() in a button, will it crash?
3) I tried a second version when I let the thread run and put a condition into the handler. The only way I can get it to work is to loop conditionaly in the handler by adding an
if (thread1_running) {
handler.postDelayed(this, 2000);
showTime(Napis2);
}
And changing the condition in a thread start to while (true) but then I have an open thread that is running all the time and I start and stop it in a handler, and it posts more and more handlers.
So, finally I get to the point it looks like that:
final Runnable r = new Runnable()
{
public void run()
{
if (thread1_running) handler.postDelayed(this, 1000);
showTime(Napis2);
}
};
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
if (thread1_running) handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Is the proper way to do that is to start and stop a whole thread? Or that is the best way?
The best way to achieve something like that would be, in my humble opinion, to postDelayed(Runnable, long).
You could do something like this. Class definition:
private Handler mMessageHandler = new Handler();
private Runnable mUpdaterRunnable = new Runnable() {
public void run() {
doStuff();
showTime(Napis2);
mMessageHandler.postDelayed(mUpdaterRunnable, 1000);
}
};
And control true run/stop like this:
To start:
mMessageHandler.postDelayed(mUpdaterRunnable, 1000);
And to stop:
mMessageHandler.removeCallbacks(mUpdaterRunnable);
It's much much simpler, in my humble opinion.
Threads a described by a state machine in java.
When a thread get outs of its run method, it enters in the stopped state and can't be restarted.
You should always stop a thread by getting it out of its run method as you do, it s the proper way to do it.
If you want to "restart the thread", start a new instance of your thread class.
You should better encapsulate your thread and its running field. It should be inside your thread class and the class should offer a public method to swich the boolean. No one cares about your datastructure, hide them. :)
You should consider using runOnUIThread for your runnable, its much easier to use than handlers.