Shivansh Potdar
Shivansh Potdar

Reputation: 1267

Use arrayList values updated in thread outside it

Basically, I'm taking some links from a website in a thread and adding it to an ArrayList. But when I check the size of the ArrayList it returns 0. Is there anyway to make the new values in it reflect outdie the thread.

Here is the code:

lsiter.setOnItemClickListener(new AdapterView.OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            final ArrayList<String>LinkAr = new ArrayList<String>();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Document doc = null;
                    try {
                        doc = Jsoup.connect(message).get();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    //Title
                    Element TitleSpan = doc.select("span.detail-info-right-title-font").first();
                    String TitleString = TitleSpan.text();

                    //Chaps Names
                    Elements Chaps = doc.getElementsByClass("title3");

                    for(Element item: Chaps){
                        LinkAr.add(item.text());
                    }
                }
            }).start();
            
                int pos = parent.getPositionForView(view);
                String ClickedVal = (String) parent.getItemAtPosition(position);
                Toast.makeText(ChapterPage.this, LinkAr.size() + "@ " + ClickedVal, Toast.LENGTH_SHORT).show();
        }
    });

Upvotes: 1

Views: 405

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 338336

Caveat: I do not know Android. I'm speaking of Java generally here.

Caveat: As others commented, it may or may not make sense for your app to do your particular workload on a background thread. I will ignore that issue, and focus on answering how to produce data on a background thread. It is up to the reader to decide if doing so is appropriate within their particular app.


In Java, we no longer need manage threads manually. The Executors framework (Oracle tutorial) was built into Java 5 to free app developers from the tricky work of juggling threads.

ExecutorService as global variable

Establish your executor service, backed by a thread pool. Keep a reference to that executor service somewhere in your app. This executor service will be used repeatedly.

To configure an ExecutorService object, use factory methods found in the Executors class.

ExecutorService executorService = Executors.newCachedThreadPool() ;

Code in your onItemClick code

In your onItemClick method, define the work to be done as a Callable. A Callable returns a value. In your case, you want to return a List or Set of URLs. There is no need for the background thread to access a list in your onItemClick code. Just let the background thread generate a new list or set, and return that list/set back to the calling code. Cleaner separation.

Apparently you are using String objects to represent your URLs. But we have a class for that: URL. Let's produce a list of URL objects, specified as List < URL >. We expect our Callable object to eventually produce and return a List < URL >. If something goes wrong with our task, we expect the Callable to return an empty list rather than throw an exception (if that is appropriate to your business logic).

Callable < List < URL > > urlFetch =
        ( ) -> {
            List < URL > urls = List.of(); // Default to empty list.
            //  … do the work to fetch your URLs and build a list.
            return urls;
        };

Submit that task to the executor service. The executor service then assigns that task to a thread in its backing pool. Wo do not care about how that thread assignment is done; perhaps a new thread is started, or perhaps an existing idle thread is re-used, not our problem.

Upon submitting our task to the executor service, we get back a Future object. This Future is our handle back to our task. We can ask the Future about the status of that work being done.

Future < List < URL > > futureUrls = executorService.submit( urlFetch );
// … do other work while you wait. 

Later, whenever you want, you can check the status of our task. The Future may report that the task is done or is cancelled. Otherwise, we can assume the task is incomplete, and still be worked on.

If the Future reports as complete, we can retrieve its results. Here that would be a List< URL > object.

// … check to see if the URL fetch work has been done yet.
if ( futureUrls.isDone() )
{
    List < URL > urls = futureUrls.get();
    // … Use your list of URLs. 
} else if ( futureUrls.isCancelled() )
{
    // … deal with cancellation. 
} // else neither done nor cancelled, so still being worked. Check back again later.

That syntax above is incomplete. We must trap for certain exceptions. Let's add the try-catch.

// … check to see if the URL fetch work has been done yet.
if ( futureUrls.isDone() )
{
    try
    {
        List < URL > urls = futureUrls.get();
        // …Use your URL collection…
    }
    catch ( InterruptedException e )
    {
        e.printStackTrace();
    }
    catch ( ExecutionException e )
    {
        e.printStackTrace();
    }
} else if ( futureUrls.isCancelled() )
{
    // … deal with cancellation.
} // else neither done nor cancelled, so still being worked. Check back again later.

Waiting for task to complete

If you want the calling thread to wait indefinitely until the task finishes, call Future::get. But avoid doing this in the main user-interface thread, as your app becomes unresponsive to the user, appearing to have frozen/crashed.

If you want the calling thread to wait briefly for the task to finish, call Future::get while passing the amount of time to wait. When the wait time expires with our task still not done, the calling thread moves on to other work. Again, do not wait for long in the UI thread, as the UI freezes for that amount of time.

Do not mess with the UI

Important: Never access the user-interface from a background thread. Bad things may or may not happen.

Cleanup

Lastly, be sure to gracefully shutdown your executor service before your app ends. Otherwise its backing pool of threads may continue indefinitely.

Upvotes: 2

Related Questions