Невозможно использовать asyncTask.cancel () - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть класс dataGetter, в который я загружаю необходимые данные (часть URL-адреса, адрес электронной почты, ...), а затем вызываю AsyncTask. Я использую меню ящика, где каждый отдельный фрагмент вызывает при создании dataGetter из нового потока. Если я быстро переключусь между фрагментами (до завершения AsyncTask), данные будут смешаны (в новом фрагменте я выпущу данные из предыдущего). Я пытался использовать AsyncTask.cancel, но всегда получаю ошибку.

public class dataGetter {

    @SuppressLint("StaticFieldLeak")
    public static Context context;
    private static String siteURL;
    private static String domain;
    private static boolean login;
    private static String email;
    private static String password;
    private static AsyncRetrieve asyncRetrieve;

    public static String getData(Context context, String url, String domain, boolean login, String email, String password) {
        dataGetter.context = context;
        dataGetter.siteURL = url;
        dataGetter.domain = domain;
        dataGetter.login = login;
        dataGetter.email = email;
        dataGetter.password = password;

        String result = "";
        try {
            if (asyncRetrieve != null)
                asyncRetrieve.cancel(true);
            asyncRetrieve = new AsyncRetrieve();
            result = asyncRetrieve.execute().get();
        }
        catch (ExecutionException | InterruptedException e) {
            Sentry.capture(e);
            e.printStackTrace();
        }

        return result;
    }

    public static class AsyncRetrieve extends AsyncTask<String, Void, String> {
        HttpsURLConnection conn;
        URL url = null;

        // This method does not interact with UI, You need to pass result to onPostExecute to display
        @Override
        protected String doInBackground(String... params) {
            .....
        }

    }

}

Любой вызов asyncRetrieve.cancel () возвращает следующую ошибку

E/AndroidRuntime: FATAL EXCEPTION: Thread-9
    Process: com.example.wedos, PID: 6709
    java.util.concurrent.CancellationException
        at java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.util.concurrent.FutureTask.get(FutureTask.java:193)
        at android.os.AsyncTask.get(AsyncTask.java:542)
        at com.example.xyz.dataGetter.getData(dataGetter.java:45)
        at com.example.xyz.ui.domains.DomainsFragment.getDetails(DomainsFragment.java:195)
        at com.example.xyz.ui.domains.DomainsFragment.access$100(DomainsFragment.java:36)
        at com.example.xyz.ui.domains.DomainsFragment$1.run(DomainsFragment.java:74)
        at java.lang.Thread.run(Thread.java:764)

Я пытался найти inte rnet, но, к сожалению, ничего. Кто-нибудь посоветует мне, как отменить асинхронную задачу, чтобы данные из предыдущего фрагмента не появлялись в новом?

Correct resultIncorrect result

Большое спасибо заранее

РЕДАКТИРОВАТЬ

Первый фрагмент "доменов"

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    //new ViewModelProvider(this).get(DomainsViewModel.class);
    root = inflater.inflate(R.layout.fragment_domains, container, false);
    context = root.getContext();
    setHasOptionsMenu(true);

    models = new ArrayList<>();
    result = new ArrayList<>();

    progressBar = root.findViewById(R.id.loading);
    viewPager2 = root.findViewById(R.id.viewPager);
    tabLayout = root.findViewById(R.id.tabs);
    linearLayout = root.findViewById(R.id.DomainsLinearLayout);

    thread = new Thread(new Runnable() {
        @Override public void run() {
            try {
                getData();
            } catch (JSONException e) {
                Sentry.capture(e);
                e.printStackTrace();
            }
            for (String domena : result) {
                try {
                    getDetails(domena);
                } catch (JSONException e) {
                    Sentry.capture(e);
                    e.printStackTrace();
                }
            }
        }
    });
    thread.start();

    check();

    return root;
}

@Override
public void onDestroy() {
    super.onDestroy();
    asyncRetrieve.cancel(true);
    System.out.println("On Destroy");
    if (thread.isAlive())
        thread.interrupt();
}

Второй фрагмент "ca sh "

public View onCreateView(@NonNull LayoutInflater inflater,
                         ViewGroup container, Bundle savedInstanceState) {
    //new ViewModelProvider(this).get(CashViewModel.class);
    View root = inflater.inflate(R.layout.fragment_cash, container, false);
    context = root.getContext();
    setHasOptionsMenu(true);

    textView = root.findViewById(R.id.cash_amount);
    progressBar = root.findViewById(R.id.loading);
    linearLayout = root.findViewById(R.id.CashLinearLayout);
    Button cashHistory = root.findViewById(R.id.showHistory);
    cashHistory.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int index = result.indexOf(' ');
            Intent i = new Intent(context, CashHistoryActivity.class);
            i.putExtra("CURRENCY", result.substring(index));
            startActivity(i);
        }
    });

    thread = new Thread(new Runnable() {
        @Override
        public void run() {
            getData();
        }
    });
    thread.start();

    return root;
}

getData () метод

result = dataGetter.getData(context, "cashCheck", "", false, "", "");

Последняя ошибка

I/System.out: On Destroy
E/AndroidRuntime: FATAL EXCEPTION: Thread-12
    Process: com.example.wedos, PID: 9115
    java.util.concurrent.CancellationException
        at java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.util.concurrent.FutureTask.get(FutureTask.java:193)
        at android.os.AsyncTask.get(AsyncTask.java:542)
        at com.example.wedos.dataGetter.getData(dataGetter.java:45)
        at com.example.wedos.ui.cash.CashFragment.getData(CashFragment.java:90)
        at com.example.wedos.ui.cash.CashFragment.access$200(CashFragment.java:25)
        at com.example.wedos.ui.cash.CashFragment$2.run(CashFragment.java:59)
        at java.lang.Thread.run(Thread.java:764)
D/io.sentry.android.event.helper.AndroidEventBuilderHelper: Proguard UUIDs file not found.
W/System.err: SLF4J: Failed to load class "org.slf4j.impl.StaticMDCBinder".
    SLF4J: Defaulting to no-operation MDCAdapter implementation.
    SLF4J: See http://www.slf4j.org/codes.html#no_static_mdc_binder for further details.
W/System.err: java.lang.InterruptedException
        at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:420)
        at java.util.concurrent.FutureTask.get(FutureTask.java:192)
        at android.os.AsyncTask.get(AsyncTask.java:542)
        at com.example.wedos.dataGetter.getData(dataGetter.java:45)
        at com.example.wedos.ui.domains.DomainsFragment.getDetails(DomainsFragment.java:198)
        at com.example.wedos.ui.domains.DomainsFragment.access$100(DomainsFragment.java:38)
        at com.example.wedos.ui.domains.DomainsFragment$1.run(DomainsFragment.java:76)
        at java.lang.Thread.run(Thread.java:764)
I/Process: Sending signal. PID: 9115 SIG: 9

1 Ответ

1 голос
/ 21 апреля 2020

Я рекомендую удалить класс dataGetter и удалить лишние Thread, которые запускают AsyncTask. Поскольку способ обработки ответа API зависит от фрагмента, вам следует создать базовый класс publi c, например, AsyncReceiver в отдельном файле.

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

    private Context context;   
    private Domain domain;
    // etc.

    public AsyncRetrieve(Context context, String domain, boolean login, String email, String password) {
        this.context = context;
        this.url = url;
        this.domain = domain; 
        // etc.
    }

    @Override
    public String doInBackground(String... params) {
        return fetchData("domainList");
    }

    private String fetchData(String url) {
        // do what you originally did in the old doInBackground
        // of the old AsyncRetriever class, but use the url argument
        // passed to this method
        return result;
    }
}

Затем в свои фрагменты добавить приватный расширенный подкласс AsyncReceiver, который реализует метод onPostExecute. Именно здесь вы обрабатываете ответ API и обновляете свои представления соответственно.

Например:

public class DomainsFragment extends Fragment {

    private DomainsAsyncReceiver receiver;
    // example text view that is updated on results
    private TextView tv_results;

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // instantiate your views
        // e.g.
        tv_results = findViewById(R.id.tv_results);

        // etc.

        // instantiate the async task
        receiver = new DomainsAsyncReceiver(domain, url, etc.);
        receiver.execute();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // cancel the async task
        receiver.cancel(true);
    }

    private class DomainsAsyncReceiver extends AsyncRetrieve {

        @Override
        protected String doInBackground(String... params) {
            String result = fetchData("domainList");
            // do something with the result, e.g.
            String details = fetchData("domainDetails");
            return details;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            tv_results.setText(result);
        }
    }
}
...