Android - การตั้งค่าการหมดเวลาสำหรับ AsyncTask?


125

ฉันมีAsyncTaskคลาสที่ฉันดำเนินการซึ่งดาวน์โหลดรายการข้อมูลจำนวนมากจากเว็บไซต์

ในกรณีที่ผู้ใช้ปลายทางมีการเชื่อมต่อข้อมูลที่ช้ามากหรือขาด ๆ หาย ๆ ในขณะที่ใช้งานฉันต้องการให้AsyncTaskหมดเวลาหลังจากช่วงเวลาหนึ่ง แนวทางแรกของฉันในเรื่องนี้เป็นดังนี้:

MyDownloader downloader = new MyDownloader();
downloader.execute();
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
  @Override
  public void run() {
      if ( downloader.getStatus() == AsyncTask.Status.RUNNING )
          downloader.cancel(true);
  }
}, 30000 );

หลังจากเริ่มต้นAsyncTaskตัวจัดการใหม่จะเริ่มทำงานซึ่งจะยกเลิกAsyncTaskหลังจาก 30 วินาทีหากยังทำงานอยู่

นี่เป็นแนวทางที่ดีหรือไม่? หรือมีบางอย่างในตัวAsyncTaskที่เหมาะสมกว่าสำหรับจุดประสงค์นี้?


18
หลังจากลองใช้หลายวิธีแล้วฉันสรุปได้ว่าคำถามของคุณควรเป็นคำตอบที่ยอมรับได้
JohnEye

ขอบคุณสำหรับคำถามที่ฉันตกอยู่ในปัญหาเดียวกันและโค้ดของคุณช่วยฉันได้ +1
Ahmad Dwaik 'Warlock'

1
คำถามของคุณคือคำตอบที่ดี +50 :)
karthik kolanji

คำตอบ:


44

ใช่มีAsyncTask.get ()

myDownloader.get(30000, TimeUnit.MILLISECONDS);

โปรดทราบว่าการเรียกสิ่งนี้ในเธรดหลัก (เธรด UI ของ AKA) จะบล็อกการดำเนินการคุณอาจต้องเรียกมันในเธรดแยกต่างหาก


9
ดูเหมือนว่ามันจะเอาชนะจุดประสงค์ของการใช้ AsyncTask เพื่อเริ่มต้นด้วยหากเมธอดการหมดเวลานี้ทำงานบนเธรด UI หลัก ... ทำไมไม่ใช้handlerวิธีการที่ฉันอธิบายไว้ในคำถามของฉัน? ดูเหมือนจะตรงไปตรงมามากขึ้นเนื่องจากเธรด UI ไม่หยุดนิ่งในขณะที่รอรัน Handler's Runnable ...
Jake Wilson

โอเคขอบคุณฉันไม่แน่ใจว่ามีวิธีที่เหมาะสมที่จะทำหรือไม่
Jake Wilson

3
ฉันไม่เข้าใจว่าทำไมคุณถึงเรียก get () ในชุดข้อความอื่น มันดูแปลก ๆ เพราะ AsyncTask เป็นเธรดชนิดหนึ่ง ฉันคิดว่าวิธีแก้ปัญหาของ Jakobud นั้นโอเคกว่า
emeraldhieu

ฉันคิดว่า. get () คล้ายกับการเข้าร่วมของ posix ซึ่งจุดประสงค์คือรอให้เธรดเสร็จสมบูรณ์ ในกรณีของคุณจะทำหน้าที่เป็นการหมดเวลาซึ่งเป็นคุณสมบัติตามสถานการณ์ นั่นเป็นเหตุผลที่คุณต้องเรียก. get () จากตัวจัดการหรือจากเธรดอื่นเพื่อหลีกเลี่ยงการบล็อก UI หลัก
Constantine Samoilenko

2
ฉันรู้ว่านี่เป็นเวลาหลายปีต่อมา แต่สิ่งนี้ยังไม่ได้ติดตั้งใน Android ดังนั้นฉันจึงสร้างคลาสสนับสนุน ฉันหวังว่ามันจะช่วยใครบางคนได้ gist.github.com/scottTomaszewski/…
Scott Tomaszewski

20

ในกรณีนี้โปรแกรมดาวน์โหลดของคุณจะขึ้นอยู่กับการเชื่อมต่อ URL คุณมีพารามิเตอร์หลายตัวที่สามารถช่วยคุณกำหนดระยะหมดเวลาโดยไม่มีรหัสที่ซับซ้อน:

  HttpURLConnection urlc = (HttpURLConnection) url.openConnection();

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

หากคุณเพียงแค่นำรหัสนี้ไปใช้ในงาน async ของคุณก็ใช้ได้

'Read Timeout' คือการทดสอบเครือข่ายที่ไม่ดีตลอดการถ่ายโอน

'การหมดเวลาการเชื่อมต่อ' จะถูกเรียกเมื่อเริ่มต้นเพื่อทดสอบว่าเซิร์ฟเวอร์ทำงานอยู่หรือไม่


1
ฉันอยู่ในข้อตกลง การใช้แนวทางนี้ง่ายกว่าและจะยุติการเชื่อมต่อเมื่อถึงระยะหมดเวลา การใช้วิธี AsyncTask.get () คุณจะได้รับแจ้งเพียงว่าถึงเวลาที่ จำกัด แล้ว แต่การดาวน์โหลดยังอยู่ระหว่างดำเนินการและอาจเสร็จสมบูรณ์ในภายหลังซึ่งทำให้เกิดความยุ่งยากในโค้ดมากขึ้น ขอบคุณ
มึนงง

โปรดทราบว่าสิ่งนี้ไม่เพียงพอเมื่อใช้เธรดจำนวนมากในการเชื่อมต่ออินเทอร์เน็ตที่ช้ามาก ข้อมูลเพิ่มเติม: leakfromjavaheap.blogspot.nl/2013/12/…และthushw.blogspot.nl/2010/10/…
Kapitein Witbaard

20

ใช้ CountDownTimer Class ในด้านข้างของคลาสเสริมสำหรับ AsyncTask ในเมธอด onPreExecute ():

ข้อได้เปรียบหลักการตรวจสอบ Async ทำภายในคลาส

public class YouExtendedClass extends AsyncTask<String,Integer,String> {
...
public YouExtendedClass asyncObject;   // as CountDownTimer has similar method -> to prevent shadowing
...
@Override
protected void onPreExecute() {
    asyncObject = this;
    new CountDownTimer(7000, 7000) {
        public void onTick(long millisUntilFinished) {
            // You can monitor the progress here as well by changing the onTick() time
        }
        public void onFinish() {
            // stop async task if not in progress
            if (asyncObject.getStatus() == AsyncTask.Status.RUNNING) {
                asyncObject.cancel(false);
                // Add any specific task you wish to do as your extended class variable works here as well.
            }
        }
    }.start();
...

เปลี่ยน CountDownTimer (7000, 7000) -> CountDownTimer (7000, 1000) เป็นต้นและมันจะเรียก onTick () 6 ครั้งก่อนที่จะเรียก onFinish () นี่เป็นสิ่งที่ดีหากคุณต้องการเพิ่มการตรวจสอบ

ขอบคุณสำหรับคำแนะนำที่ดีทั้งหมดที่ฉันได้รับในหน้านี้ :-)


2

ฉันไม่คิดว่าจะมีอะไรแบบนี้ใน AsyncTask แนวทางของคุณดูเหมือนจะดี อย่าลืมตรวจสอบค่า isCancelled () เป็นระยะในเมธอด doInBackground ของ AsyncTask เพื่อสิ้นสุดเมธอดนี้เมื่อเธรด UI ยกเลิก

หากคุณต้องการหลีกเลี่ยงการใช้ตัวจัดการด้วยเหตุผลบางประการคุณสามารถตรวจสอบ System.currentTimeMillis เป็นระยะภายใน AsyncTask ของคุณและออกเมื่อหมดเวลาแม้ว่าฉันจะชอบโซลูชันของคุณดีกว่าเนื่องจากสามารถขัดจังหวะเธรดได้


0
         Context mContext;

         @Override
         protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
                                    mContext = this;

            //async task
            final RunTask tsk = new RunTask (); 
            tsk.execute();

            //setting timeout thread for async task
            Thread thread1 = new Thread(){
            public void run(){
                try {
                    tsk.get(30000, TimeUnit.MILLISECONDS);  //set time in milisecond(in this timeout is 30 seconds

                } catch (Exception e) {
                    tsk.cancel(true);                           
                    ((Activity) mContext).runOnUiThread(new Runnable()
                    {
                         @SuppressLint("ShowToast")
                        public void run()
                         {
                            Toast.makeText(mContext, "Time Out.", Toast.LENGTH_LONG).show();
                            finish(); //will close the current activity comment if you don't want to close current activity.                                
                         }
                    });
                }
            }
        };
        thread1.start();

         }

2
พิจารณาเพิ่มคำอธิบายด้วย
Saif Asif

0

คุณสามารถวางเงื่อนไขได้อีกหนึ่งข้อเพื่อให้การยกเลิกมีประสิทธิภาพมากขึ้น เช่น,

 if (downloader.getStatus() == AsyncTask.Status.RUNNING || downloader.getStatus() == AsyncTask.Status.PENDING)
     downloader.cancel(true);

0

แรงบันดาลใจจากคำถามฉันได้เขียนวิธีการที่ทำงานเบื้องหลังผ่าน AsyncTask และหากการประมวลผลใช้เวลานานกว่านั้น LOADING_TIMEOUT บทสนทนาแจ้งเตือนเพื่อลองอีกครั้งจะปรากฏขึ้น

public void loadData()
    {
        final Load loadUserList=new Load();
        loadUserList.execute();
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (loadUserList.getStatus() == AsyncTask.Status.RUNNING) {
                    loadUserList.cancel(true);
                    pDialog.cancel();
                    new AlertDialog.Builder(UserList.this)
                            .setTitle("Error..!")
                            .setMessage("Sorry you dont have proper net connectivity..!\nCheck your internet settings or retry.")
                            .setCancelable(false)
                            .setPositiveButton("Retry", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    loadData();
                                }
                            })
                            .setNegativeButton("Exit", new DialogInterface.OnClickListener() {
                                @Override


                      public void onClick(DialogInterface dialogInterface, int i) {
                                System.exit(0);
                            }
                        })
                        .show();
            }
        }
    }, LOADING_TIMEOUT);
    return;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.