Android 简单列表与 AsyncTask 替代

Posted

技术标签:

【中文标题】Android 简单列表与 AsyncTask 替代【英文标题】:Android simple list with AsyncTask alternative 【发布时间】:2021-02-11 07:55:04 【问题描述】:

我有一个 AsyncTask,它显示来自外部 URL 的项目列表。

 private static class GetContacts extends AsyncTask<String, Void, List<Actors>> 
    ProgressDialog dialog;
    private final WeakReference<Search> activityReference;
    GetContacts(Search context) 
        activityReference = new WeakReference<>(context);
    
    
    @Override
    protected void onPreExecute() 
        Search activity = activityReference.get();
        if (activity == null || activity.isFinishing() || activity.isDestroyed()) return;
        super.onPreExecute();
        dialog = new ProgressDialog(activity);
        dialog.setMessage(activity.getResources().getString(R.string.Searching));
        dialog.setTitle(activity.getResources().getString(R.string.connecting));
        dialog.show();
        dialog.setCancelable(false);
    

    @Override
    protected  List<Actors> doInBackground(String... sText) 
        final Search activity = activityReference.get();
        List<Actors> myList = new ArrayList<>();
        HttpHandler sh = new HttpHandler();
        String url = "http://myurl?par="+sText;

        String jsonStr = sh.makeServiceCall(url);

        if (jsonStr != null) 
            try JSONObject jsonObj = new JSONObject(jsonStr);
                JSONArray actors = jsonObj.getJSONArray("result");

                for (int i = 0; i < actors.length(); i++) 
                    JSONObject c = actors.getJSONObject(i);

                    Actors actor = new Actors();
                    actor.setNazov(c.getString("title"));
                    actor.setPerex(c.getString("perex"));

                    myList.add(actor);
                

              catch (final JSONException e) 
                activity.runOnUiThread(new Runnable() 
                    @Override
                    public void run() 
                        Toast.makeText(activity,
                                R.string.Nodata,
                                Toast.LENGTH_LONG).show();
                    
                ); 

                return myList;

         else 
            activity.runOnUiThread(new Runnable() 
                @Override
                public void run() 
                    Toast.makeText(activity,
                            R.string.Network,
                            Toast.LENGTH_LONG).show();
                
            );
            return null;
        
    

    protected void onPostExecute(List<Actors>   result) 
        Search activity = activityReference.get();
        if (activity == null || activity.isFinishing() || activity.isDestroyed()) return;
        super.onPostExecute(result);
        if (dialog != null) 
            dialog.dismiss();  dialog = null;
        
        activity.actorsList.clear();
         if (result!=null)  activity.actorsList.addAll(result);
        activity.adapter.notifyDataSetChanged();
    

我是这样执行的:

new GetContacts(Search.this).execute(newText,lng);

但是这仍然可以正常工作,android 11 已弃用 AsyncTask。我已经阅读了许多关于一些替换的线程,但仍然没有找到替换我的案例的解决方案。

我尝试了它作为使用 Thread 的最简单解决方案的建议,

但这并不像预期的那么容易。存在多个问题,例如无法解析方法“runOnUIThread(java.lang.Runnable)”、无法解析方法“start()”等。

实际上,我不确定如何替换整个异步任务。

1/ 有 onPreExecute(),我不知道从那里放东西,因为我需要显示一个加载对话框。

2/ List doInBackground(String... sText) - 后台任务本身带参数(String)

3/ 最后是 onPostExecute

您能否帮助解释并建议如何重新创建此代码以使其正常工作,而不是弃用已弃用的 AsyncTask? (在 Java 中,没有 Kotlin,至于 Kotlin,我也找到了一些 CoroutineScope 解决方案)

我设法做的是这样的:

 void GetContacts(final String sText) 
        try 
            Thread thread = new Thread() 
                public void run() 
                    Looper.prepare();
                    final JSONObject[] maindata = new JSONObject();

                    final Handler handler = new Handler(Looper.getMainLooper());
                    handler.postDelayed(new Runnable() 
                        @Override
                        public void run() 
                            List<Actors> myList = new ArrayList<>();
                            HttpHandler sh = new HttpHandler();
                            String url = "https://myurl?par="+sText;

                            String jsonStr = sh.makeServiceCall(url);

                            if (jsonStr != null) 
                                try JSONObject jsonObj = new JSONObject(jsonStr);
                                    JSONArray actors = jsonObj.getJSONArray("result");

                                    for (int i = 0; i < actors.length(); i++) 
                                        JSONObject c = actors.getJSONObject(i);

                                        Actors actor = new Actors();
                                        actor.setNazov(c.getString("title"));
                                   actor.setThumb(c.getString("thumb"));


                                        myList.add(actor);
                                    

                                  catch (final JSONException e) 
                                    runOnUiThread(new Runnable() 
                                        @Override
                                        public void run() 
                                            Toast.makeText(getApplicationContext(),
                                                    R.string.Nodata,
                                                    Toast.LENGTH_LONG).show();
                                        
                                    ); 

                              //  return myList;

                             else 
                                runOnUiThread(new Runnable() 
                                    @Override
                                    public void run() 
                                        Toast.makeText(getApplicationContext(),
                                                R.string.Network,
                                                Toast.LENGTH_LONG).show();
                                    
                                );
                             //   return null;
                            

                            handler.removeCallbacks(this);
                            Objects.requireNonNull(Looper.myLooper()).quit();
                        
                    , 2000);

                    Looper.loop();
                
            ;
            thread.start();

         catch (Exception ex) 
            Log.e("ERROR =>", "" + ex.getMessage());
            ex.printStackTrace();
        

    

但是,我这里有一个错误 java.lang.IllegalStateException: Main thread not allowed to quit,这样它根本不起作用。

并且仍然缺少执行前和执行后的内容。即使我从主线程中删除退出,列表也不会出现。

【问题讨论】:

【参考方案1】:

要从服务器 api 获取,请使用 retrofit2。很简单

【讨论】:

谢谢,以后会注意到,但我现在不想使用其他一些库,因为我有一个动态 URL,其中参数根据输入搜索框而变化,而且我已经有了我的自己的适配器、布局和所有逻辑。 http 工作正常,我只需要替换已弃用的 AsyncTask retrofit 可以和动态url一起使用***.com/a/32559579/1791771 嗯,这对我来说是全新的,我查看了改造原始页面,但现在我更困惑它是如何工作的。我无法想象如何将我的代码转移到那里,因为我需要一条加载消息,然后根据用户在搜索字段中键入的字母刷新视图并显示结果。也许如果您可以发布一些类似于我的案例的示例,我将非常感激。我想这对您来说并不难,因为您提到它很容易:) 你应该通过 UI、ViewModel + Flow、Repo + Coroutines 将你的逻辑分层 协程不仅仅适用于 Kotlin?我对 android 比较陌生,而且正如我所写,从未使用过改造,所以我需要看一些类似的工作示例来学习。如果没有其他解决方案,将尝试在网络上寻找一些东西

以上是关于Android 简单列表与 AsyncTask 替代的主要内容,如果未能解决你的问题,请参考以下文章

使用 AsyncTask 中的 onPostExecute 方法列表项单击事件调用 Android 中的另一个活动

Android中AsyncTask基本用法与源码分析(API 23)

Android中使用AsyncTask实现文件下载以及进度更新提示

android:如果一个 AsyncTask 已经在运行,则阻止另一个 AsyncTask 执行

Android 中AsyncTask后台线程的理解

如何在Android中强制停止AsyncTask [重复]