0

I am trying to show the Progress Bar component (circular, not horizontal) during a GET api request in Android Studio. I am running the API request on a different thread and I am setting the progress bar to visible before the thread starts and setting its visibility to gone after the thread is over using the runOnUiThread() method. My code works correctly without the progress bar, I just want a better user experience by showing them that the search is loading. I have already looked at a lot of other solutions, but so far, none have worked (maybe I haven't done it correctly).

The progress bar doesn't show up at all normally, but if I don't set it's visibility to gone, the progress bar shows up after the thread completes. Here is my current code for searching for ingredients:

private List<FoodHint> searchIngredient(String ingredient) {

        Gson gson = new Gson();
        AtomicReference<FoodSearchResults> searchResults = new AtomicReference<>();
    
        runOnUiThread(new Runnable() {
    
            @Override
            public void run() {
    
                progressBar.setVisibility(View.VISIBLE);
    
            }
        });
    
        Runnable runnable = new Runnable() {
    
            @Override
            public void run() {
    
                try {
    
                    StringBuilder result = new StringBuilder();
                    URL url = new URL("www.exampleurl.com");
    
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.connect();
    
                    int responseCode = connection.getResponseCode();
    
                    if (responseCode == 200) {
    
                        Scanner scanner = new Scanner(url.openStream());
    
                        while (scanner.hasNext()) {
    
                            result.append(scanner.nextLine());
    
                        }
    
                        scanner.close();
    
                    } else {
    
                        Log.d("debug-error", "Response Code: " + responseCode);
    
                    }
    
                    searchResults.set(gson.fromJson(result.toString(), FoodSearchResults.class));
    
                } catch (MalformedURLException e) {
    
                    e.printStackTrace();
    
                } catch (IOException e) {
    
                    e.printStackTrace();
    
                }
            }
        };
    
        Thread thread = new Thread(runnable);
        thread.start();
    
        try {
    
            thread.join();
    
        } catch (InterruptedException e) {
    
            e.printStackTrace();
    
        }
    
        runOnUiThread(new Runnable() {
    
            @Override
            public void run() {
    
                progressBar.setVisibility(View.GONE);
    
            }
        });
    
        return searchResults.get().getHints();
    
    }
CladCobra
  • 11
  • 4
  • Review what [join](https://docs.oracle.com/javase/tutorial/essential/concurrency/join.html) does and check [this SO question](https://stackoverflow.com/questions/3142915/how-do-you-create-an-asynchronous-http-request-in-java). – dominicoder May 02 '23 at 03:58
  • 2
    If you call that function from main thread then you are blocking the main (UI) thread in this line -> `thread.join();`, hence the UI will freeze until the thread returns. Blocking the main thread is not correct. Get rid of it. Instead, you can post your progressBar's view within the Runnable block when the request is finished. Code like following -> `if(progressBar != null) prrogressBar.post(()-> progressBar.setVisibility(View:GONE));` – Kozmotronik May 02 '23 at 07:09

1 Answers1

0

By using Dispatchers.IO, we have specified that the task should be performed on a thread pool for I/O operations. Likewise, by using Dispatchers.Main, we have specified that the task should be performed on the main thread for UI operations. With this modification to the code, we can ensure that network operations are not performed on the UI thread. For further advanced options, you can use sealed classes or utilize RxJava.

private suspend fun searchIngredient(ingredient: String): List<FoodHint> = withContext(Dispatchers.IO){
    val gson = Gson()
    val searchResults = AtomicReference<FoodSearchResults>()
    var results: List<FoodHint> = emptyList()
    
    withContext(Dispatchers.Main) {
        progressBar.visibility = View.VISIBLE
    }
    
    try {
        val result = StringBuilder()
        val url = URL("www.exampleurl.com")
    
        val connection = url.openConnection() as HttpURLConnection
        connection.requestMethod = "GET"
        connection.connect()
    
        val responseCode = connection.responseCode
    
        if (responseCode == 200) {
            val scanner = Scanner(url.openStream())
            while (scanner.hasNext()) {
                result.append(scanner.nextLine())
            }
            scanner.close()
        } else {
            Log.d("debug-error", "Response Code: $responseCode")
        }
    
        searchResults.set(gson.fromJson(result.toString(), FoodSearchResults::class.java))
        results = searchResults.get().getHints()
    
    } catch (e: MalformedURLException) {
        e.printStackTrace()
    } catch (e: IOException) {
        e.printStackTrace()
    }
    
    withContext(Dispatchers.Main) {
        progressBar.visibility = View.GONE
    }
    
    results

}
maru
  • 31
  • 4