简体   繁体   中英

get method of Jsoup.connect() block the UI

I've created an application android divided in two part: T

  • The Managers, that make the call on the site, using Jsoup.connect() , associated with the AsyncTask , and all the override method.

  • The Activities, that use the manager for call the method and format the answer.

My problem is when I try to take the call in one Activity. The UI will be blocked until the answer of the call.

Reading the other questions in StackOverflow, I've understood that the problem is when I try to call Jsoup.connect(values[0]).get(); in doInBackground() method, but I've tried to follow some guide, but no one works.

The code

Activity

public class CreazioneLibrettoActivity extends AppCompatActivity {

    private EditText editMatricola;
    private Spinner elencoPercorsi;
    private ListView elencoInsegnamenti;
    private String matricola;
    private PercorsiAdapter percorsiAdapter;
    private InsegnamentiAdapter insegnamentiAdapter;
    private ArrayList<Insegnamento> elencoEsami;
    private FloatingActionButton bottonPiano;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_creazione_libretto);

        bottonPiano = findViewById(R.id.bottonPiano);
        editMatricola = findViewById(R.id.matricola);
        elencoPercorsi = findViewById(R.id.elencoPercorsi);
        elencoInsegnamenti = findViewById(R.id.elencoInsegnamenti);


        editMatricola.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

                if(charSequence.length() == 5) {

                    InputMethodManager imm = (InputMethodManager)getSystemService(getApplicationContext().INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(editMatricola.getWindowToken(), 0);
                    Esse3RecoveryManager esse3 = new Esse3RecoveryManager(getApplicationContext());
                    matricola = charSequence.toString();

                    String result = esse3.selectCdL(matricola);

                    if(result != null) {
                        if(result.equals("nullo")){
                            Toast.makeText(getApplicationContext(),"Nessuna connessione a internet",Toast.LENGTH_LONG).show();
                        }
                        else
                        {
                            TreeMap<String, String> percorsi = esse3.getPercorsi(result);
                            if(percorsi == null) {
                                System.out.println(percorsi);
                                Toast.makeText(getApplicationContext(),"Nessuna connessione a internet",Toast.LENGTH_LONG).show();
                            } else {
                                percorsiAdapter = new PercorsiAdapter(getApplicationContext(), R.layout.spinner_percorsi, percorsi);
                                elencoPercorsi.setAdapter(percorsiAdapter);
                                elencoPercorsi.setVisibility(View.VISIBLE);
                            }
                        }
                    } else {
                        Toast.makeText(getApplicationContext(),"Matricola non trovata",Toast.LENGTH_SHORT).show();
                    }
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

        elencoPercorsi.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {

                String url = view.getTag().toString();

                if(!url.equals("firstTag")) {
                    Esse3RecoveryManager esse3 = new Esse3RecoveryManager(getApplicationContext());
                    elencoEsami = esse3.getCdS(url, matricola);
                    if (elencoEsami == null) {
                        Toast.makeText(getApplicationContext(), "Nessuna connessione a internet", Toast.LENGTH_LONG).show();
                    } else {
                        insegnamentiAdapter = new InsegnamentiAdapter(getApplicationContext(), R.layout.insegnamenti_listview, elencoEsami);
                        elencoInsegnamenti.setAdapter(insegnamentiAdapter);
                        elencoInsegnamenti.setVisibility(View.VISIBLE);
                        bottonPiano.setVisibility(View.VISIBLE);
                    }
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {

            }
        });

        bottonPiano.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(getApplicationContext(), PianoActivity.class);
                i.putExtra("matricola", matricola);
                i.putExtra("elencoEsami", elencoEsami);
                startActivity(i);
            }
        });

    }


}

AsyncTask

public class Esse3RecoveryManager{

    private Context context;
    private static Document docInitial = null;
    private static final String URL_SELECT_CDL = "https://esse3web.unisa.it/Guide/ListaFacoltaCorsi.do";

    public Esse3RecoveryManager(Context context) {
        this.context = context;
    }

    /**
     * Metodo utilizzato per il recupero dell'url del sito web del corso di laurea scelto dall'utente.
     * @param matricola, la matricola del corso di laurea scelto dall'utente.
     * @return l'url del corso di laurea.
     */
    public String selectCdL(String matricola) {
        if(!networkConnectivity() || !isInternetWorking(URL_SELECT_CDL)) {
            return "nullo";
        }

        if(docInitial == null) {
            try {
                NetworkTask nt = new NetworkTask();
                docInitial = nt.execute(URL_SELECT_CDL).get();
            } catch (Exception e) {
                e.getMessage();
            }
        }
        Document doc = docInitial;
        Element a;
        if(doc.select("a:contains("+ matricola + ")").size() > 0)
        {

            a = doc.select("a:contains("+ matricola + ")").get(0);
            return "https://esse3web.unisa.it/" + a.attr("href");
        }
        return null;
    }

    /**
     * Metodo utilizzato per il recupero dei percorsi di studio relativi al corso di laurea scelto dall'utente.
     * @param url, l'url relativo al corso di laurea scelto dall'utente.
     * @return l'elenco dei percorsi di studio.
     */
    public TreeMap<String, String> getPercorsi(String url) {
        if(!networkConnectivity() || !isInternetWorking(url)) {
            return null;
        }

        NetworkTask nt = new NetworkTask();
        Document doc = null;
        try {
            doc = nt.execute(url).get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Elements links_percorso = doc.select("a:contains(Ord.)");
        TreeMap<String, String> percorsi = new TreeMap<String, String>();
        percorsi.put("- - - Scegli il percorso di studi - - -","firstTag");
        for(Element link : links_percorso) {
            percorsi.put(link.text(), "https://esse3web.unisa.it/" + link.attr("href"));
        }

        return percorsi;
    }

    /**
     * Metodo utilizzato per il recupero della durata del CdL.
     * @param url, l'url del corso di laurea scelto dall'utente.
     * @return la durata del CdL.
     */
    public int durataCdL(String url) {
        NetworkTask nt = new NetworkTask();
        Document doc = null;
        try {
            doc = nt.execute(url).get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        int durata = Integer.parseInt(doc.getElementsByTag("durata_effettiva").first().text());

        return durata;
    }

    /**
     * Metodo utilizzato per il recupero degli insegnamenti relativi al percorso di studi scelto.
     * @param url, l'url relativo all'elenco degli insegnamenti.
     * @param matricola, la matricola del corso di laurea scelto dall'utente.
     * @return l'elenco degli insegnamenti.
     */
    public ArrayList<Insegnamento> getCdS(String url, String matricola) {
        if(!networkConnectivity() || !isInternetWorking(url)) {
            return null;
        }

        NetworkTask nt = new NetworkTask();
        Document doc = null;
        try {
            doc = nt.execute(url).get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        int durata = durataCdL(selectCdL(matricola));

        ArrayList<Insegnamento> insegnamenti = new ArrayList<Insegnamento>();
        long in = System.currentTimeMillis();
        for(int i=1; i<=durata; i++) {
            Element table = doc.getElementById("table1_" + i);
            Element tbody = table.getElementsByTag("tbody").first();
            Elements rows = tbody.children();
            for(Element row : rows) {
                Insegnamento ins = new Insegnamento();
                Elements data = row.getElementsByTag("td");
                Pattern pattern = Pattern.compile("\\[(.*?)\\]");
                Matcher matcher = pattern.matcher(data.get(0).text());
                if (matcher.find()) {
                    ins.setAd_insegnamento(matcher.group(1));
                }
                ins.setNome_insegnamento(data.get(0).text().substring(13));
                if(data.get(1).text().equals("S"))
                    ins.setObbligatorieta(true);
                else ins.setObbligatorieta(false);
                if(data.get(2).text().equals("PRIMO SEMESTRE"))
                    ins.setSemestre(1);
                else ins.setSemestre(2);
                ins.setCfu(Integer.parseInt(data.get(3).text()));
                ins.setSsd(data.get(4).text());
                ins.setTaf(data.get(5).text());
                ins.setAnno(i);
                insegnamenti.add(ins);
            }

        }
        long out = System.currentTimeMillis();

        return insegnamenti;
    }


    class NetworkTask extends AsyncTask<String, Integer, Document> {
        @Override
        protected Document doInBackground(String... values) {

            try {

                Document doc = Jsoup.connect(values[0]).get();
                return doc;

            } catch (IOException exception) {
                exception.printStackTrace();
            }
            return null;
        }
    }

    class NetworkTaskInternet extends AsyncTask<String, Integer, Boolean> {
        @Override
        protected Boolean doInBackground(String... values) {
            boolean success = false;
            try {
                URL url = new URL(values[0]);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(10000);
                connection.connect();
                success = connection.getResponseCode() == 200;
            } catch (IOException exception) {
                exception.printStackTrace();
            }
            return success;
        }
    }

    public boolean isInternetWorking(String url) {
        NetworkTaskInternet nti = new NetworkTaskInternet();
        boolean success = false;
        try {
            success = nti.execute(url).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success;
    }

    private boolean networkConnectivity() {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isConnected()) {
            return true;
        }
        return false;
    }

}

It's because you're calling get() on the AsyncTask. That effectively renders it useless, since it's waiting for the AsyncTask to complete before continuing.

Instead, use a callback. Make a simple interface:

interface NetworkCallback {
    void onDocumentLoaded(Document document);
}

Then add that as a parameter for the constructor of your AsyncTask, and assign it to a global variable:

class NetworkTask extends AsyncTask<String, Integer, Document> {
    private NetworkCallback callback;

    public NetworkTask(NetworkCallback callback) {
        this.callback = callback;
    }
}

Then invoke that listener in onPostExecute() :

class NetworkTask extends AsyncTask<String, Integer, Document> {
    private NetworkCallback callback;

    public NetworkTask(NetworkCallback callback) {
        this.callback = callback;
    }

    // your doInBackground logic

    @Override
    protected void onPostExecute(Document document) {
        callback.onDocumentLoaded(document);
    }
}

Now, when you make a new instance of NetworkTask, it should look like this:

new NetworkTask(new NetworkCallback() {
    @Override
    public void onDocumentLoaded(Document document) {
        //do whatever you want to do with the document
    }).execute(url);

I suggest you do this for all of your AsyncTasks. You'll just need to make an appropriate callback interface for each one.

Also, make your AsyncTasks static:

static class NetworkTask extends AsyncTask<String, Integer, Document>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM