سلام
من در یک اکتیویتی یک تابعی دارم که زمان اجراش طولانی است_حدودا 10 ثانیه _ و می خواهم در این مدت پیغام مثلا لطفا منتظر باشید نمایش داده شود ولی به صورت ساده که می نویسم اجرا نمیشه ظاهرا باید با ترد یا چیز دیگری نوشت
آیا کسی میتونه کمک کنه؟
سلام
من در یک اکتیویتی یک تابعی دارم که زمان اجراش طولانی است_حدودا 10 ثانیه _ و می خواهم در این مدت پیغام مثلا لطفا منتظر باشید نمایش داده شود ولی به صورت ساده که می نویسم اجرا نمیشه ظاهرا باید با ترد یا چیز دیگری نوشت
آیا کسی میتونه کمک کنه؟
تنها نکته ای که همیشه باید بهش توجه کنید این هست که از Thread دیگه اجازه ندارید عناصر ترد UI رو دستکاری کنید، برای همین کدهایی که قراره UI رو دستکاری کنه رو توسط Handler به ترد اصلی میفرستید تا در اونجا اجرا بشه.
البته اگه در کلاس Activity باشید، از متد runOnUiThread هم میتونید استفاده کنید
final ProgressDialog pd = new ProgressDialog(this);pd.setMessage("Please wait...");
pd.setIndeterminate(true);
Thread t = new Thread(new Runnable() {
@Override public void run() {
// Your long-running code
// .......
// After everything finished, close the ProgressDialog
new Handler(getMainLooper()).post(new Runnable() {
@Override public void run() {
pd.dismiss();
}
});
}
});
pd.show();
t.run();
---------------
برای اینکه در جریان تغییرات اندروید باشید، Android Studio 3 از Java 8 به درستی پشتیبانی می کنه، و همین کد در Java 8 به این شکل در میاد:
final ProgressDialog pd = new ProgressDialog(this);
pd.setMessage("Please wait...");
pd.setIndeterminate(true);
Thread t = new Thread(() -> {
// Your long-running code
// .......
// After everything finished, close the ProgressDialog
new Handler(getMainLooper()).post(pd::dismiss);
});
pd.show();
t.run();
علاوه بر اون، پشتیبانی از زبان Kotlin هم به Android Studio 3 اضافه شده، معادل همین کد Kotlin به شکل زیر هست:
val pd = ProgressDialog(this)
pd.setMessage("Please wait...")
pd.isIndeterminate = true
val t = Thread {
// Your long-running code
// .......
// After everything finished, close the ProgressDialog
Handler(mainLooper).post({ pd.dismiss() })
}
pd.show()
t.run()
من اینو نوشتم ولی کار نمی کنه:
final ProgressDialog pd = new ProgressDialog(Suggests.this);pd.setMessage("Pleas e wait...");
pd.setIndeterminate(true);
new Thread() {
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
DoSelectUnit();
DisplayUnits(SpeNorm);
}
});
new Handler(getMainLooper()).post(new Runnable() {
@Override public void run() {
pd.dismiss();
Log.d("eeeee" , "Eeee77");
}
});
}
}.start();
pd.show();
کار نمی کنه یعنی چی ؟ یعنی لاگ هم در لاگ کت چاپ نمیشه ؟
این دوخط رو چرا در runOnUiThread نوشتید ؟
DoSelectUnit();
DisplayUnits(SpeNorm);
اون دو خط همون توابعی هستند که اجراشون طول میکشه. مگه نباید همونجا نوشت؟
لاگ چاپ میشه ولی پنجره لطفا صبر نمایید اجرا نمیشه
اون دو خط همون توابعی هستند که اجراشون طول میکشه. مگه نباید همونجا نوشت؟
نه، با نوشان اون خط دارید اجرای اون فرآیند رو به ترد اصلی منتقل می کنید، اون چندخط باید از اون بلاک runOnUiThread خارج و توی تردی که ساختید اجرا بشن، در عیر اینصورت کل هدف ساخت ترد جدید بی معنی میشه
تنها و تنها قسمت هایی از کد که اشیاء گرافیکی رو دستکاری می کنن باید تو این متد یا Handler نوشته بشن، مثل setText و ...
ببین یه نکته ای رو باید همیشه در نظر داشته باشی .
توی اندروید فقط یک thread میتونه با رابط کاربری (همون UI) کار کنه که بهش main Thread یا UI Thread هم گفته می شه.
نکته ی مهمی هم که در مورد آبجکت ProgressDialog وجود داره , اینه که این کلاس کلاً برای این هست که در thread اصلی صدا زده بشه (به کاربر نشونش بدیم ) و بعد که کارمون در thread پشت صحنه تموم شد , بر می گردیم به thread اصلی و اون رو پاک می کنیم.
پیشنهاد من اینه که به جای runonUIThread() از کلاس AsyncTask استفاده بکنی. مثلاً کد زیر رو ببین!
class Loader extends AsyncTask<Void, Void, Void> {
ProgressDialog dialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog = ProgressDialog.show(this, "title", "body");
//shows the dialog
}
@Override
protected Void doInBackground(Void... params) {
//do the heavy job here
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
dialog.dismiss();
// dismiss the dialog
}
}
حالا توی کلاس اصلی ات هر وقت خواستی اون کار سنگین رو انجام بدی , کافیه یک متغیر از نوع این کلاس بالا بسازی (که من اینجا اسمش رو گذاشتم Loader ) و اون رو اجرا کنی بدین شکل:
Loader myloader;
myloader.execute();
یادت باشه که اگر این کارها رو از داخل فرگمنت انجام می دی , باید تمام جاهایی که با this نوشته شده است رو با getActivity() عوض کنی.
این کد رو خودم تست کرده ام و کار می کند. برای اطلاعات بیشتر حتماً سند مربوط به AsyncTask رو حتما از مستندات گوگل بخونید.