-1

I've been learning Java for a few months. Nowadays I'm creating an app which downloads web content and shows the data in a ListView. The problem is that everything takes a very long time - about 25 second from the launch of the app to fill the list with elements. What is more, there is no difference between it running on a real device or an Android emulator.

In my opinion, the Java code is not bad because most of it is from my course on Udemy.

How can I improve this? Where is the problem?

Reports from logcat and AVD setting [ss]: Reports from logcat and AVD setting [ss]

Here's my code below:

MainActivity.java

package com.example.user.legionisciapp;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity {

    ListView listView;
    List<News> newsList = new ArrayList<>();
    ArrayList<String> titles = new ArrayList<>();
    ArrayList<String> desc = new ArrayList<>();
    ArrayList<String> urls = new ArrayList<>();

    public class DownloadTask extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... strings) {

            URL url;
            HttpURLConnection connection = null;
            String result = "";

            try {

                url = new URL(strings[0]);
                connection = (HttpURLConnection) url.openConnection();
                InputStream inputStream = connection.getInputStream();
                InputStreamReader reader = new InputStreamReader(inputStream);

                int data = reader.read();

                while (data != -1) {

                    char current = (char) data;
                    result += current;
                    data = reader.read();

                }

                return result;

            } catch (Exception e) {

                e.printStackTrace();
                return "Failed";

            }

        }
    }

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

        DownloadTask downloadTask = new DownloadTask();

        try {

            String result = downloadTask.execute("https://www.legionisci.com").get();
            String[] resultSplit = result.split("<div id=\"mecze\">");
            result = resultSplit[0];
            resultSplit = result.split("<div id=\"listanewsow\">");
            result = resultSplit[1];

            Pattern p = Pattern.compile("class=\"b\" title=\"(.*?)\">");
            Matcher m = p.matcher(result);

            while (m.find()) {

                titles.add(m.group(1));

            }

            p = Pattern.compile("></a>(.*?)</div>");
            m = p.matcher(result);

            while (m.find()) {

                desc.add(m.group(1));

            }

            p = Pattern.compile("alt=\"\" class=\"zl\" /></a>(.*?)<");
            m = p.matcher(result);

            while (m.find()) {

                urls.add("https://www.legionisci.com" + m.group(1));

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        listView = findViewById(R.id.listView);


        for (int i = 0; i < 4; i++) {


            newsList.add(new News(R.drawable.ll, titles.get(i), desc.get(i)));


            NewsListAdapter newsListAdapter = new NewsListAdapter(this, R.layout.news_list, newsList);
            listView.setAdapter(newsListAdapter);


        }
    }
}

News.java

package com.example.user.legionisciapp;

    public class News {

        int image;

        String title, desc;

        public News(int image, String title, String desc) {
            this.image = image;
            this.title = title;
            this.desc = desc;
        }

        public int getImage() {
            return image;
        }

        public String getTitle() {
            return title;
        }

        public String getDesc() {
            return desc;
        }
    }

NewsListAdapter.class

package com.example.user.legionisciapp;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class NewsListAdapter extends ArrayAdapter<News> {

    Context ctx;
    int resource;
    List<News> newsList;

    public NewsListAdapter (Context ctx, int resource, List<News> newsList){
        super(ctx, resource, newsList);

        this.ctx = ctx;
        this.resource = resource;
        this.newsList = newsList;

    }

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        LayoutInflater inflater = LayoutInflater.from(ctx);

        View view = inflater.inflate(R.layout.news_list, null);

        TextView title = view.findViewById(R.id.tvTitle);
        TextView desc = view.findViewById(R.id.tvDesc);
        ImageView image = view.findViewById(R.id.thumb);

        News news = newsList.get(position);

        title.setText(news.getTitle());
        desc.setText(news.getDesc());
        image.setImageDrawable(ctx.getResources().getDrawable(news.getImage()));

        return view;

    }
}
Adil B
  • 14,635
  • 11
  • 60
  • 78
Janek
  • 109
  • 1
  • 7
  • As you can imagine this is my own idea to extract the part of site which I was interested in. I had a problem because
    was about 3/4 of full page so I can't extract this with a single split of full html code in "result". I know there is a probably a better way to do it. Can you let me know if there is any?
    – Janek Jun 20 '18 at 19:51
  • For a start, use an HTML parser instead, e.g. [jsoup](https://jsoup.org/). And read: https://blog.codinghorror.com/parsing-html-the-cthulhu-way/ – wp78de Jun 20 '18 at 19:58

1 Answers1

0

You can't do something like this:

String result = downloadTask.execute("https://www.legionisci.com").get();

That is not the right way to use an AsyncTask! The problem is that the async task is executed in a background thread but if you do .get() the main thread is paused until the async task finishes his job. So this is the reason of the long wait at startup.

What you have to do is:

Starting the task this way

downloadTask.execute("https://www.legionisci.com");

Using the onPostExecute(String result) method (executed on the main thread) to get the result and update the UI .

More on this: https://developer.android.com/reference/android/os/AsyncTask

Francesco Re
  • 836
  • 6
  • 22
  • You are right. I should use `onPostExecute(String result)` . For testing your solution I've created a new very simple project. There is only MainActivity.class and AsyncTask and... it happened again.. MainAcitivity.class - https://codeshare.io/5N9VPr Of course I added into Manifest permission for Internet. Did i do something wrong? Screen of Logs: https://imgur.com/a/TXXndyA – Janek Jun 20 '18 at 20:30
  • @Janek well there's another problem: garbage collector is called too many times. This usually happens when you allocate too many objects. I can see that in the task you read from the InputStream with a while cycle. So try to optimize that cycle allocating less objects or using something different to decode the stream(https://stackoverflow.com/q/309424/9796205) – Francesco Re Jun 20 '18 at 20:48
  • `ByteArrayOutputStream` works perfect for me. So the problem was incorrect InputStreamReader... Thank you! – Janek Jun 20 '18 at 21:15