Приложение зависает, потому что ваш метод copy()
является длительным процессом. Следует также помнить, что вы выполняете эту трудоемкую операцию в основном потоке , который также отвечает за поддержаниепользовательский интерфейс.
Поскольку поток пользовательского интерфейса занят завершением длительной операции, он избегает обновления и выполнения операций пользовательского интерфейса. В результате приложение, наконец, зависает и зависает.
Теперь есть два способа справиться с этой ситуацией:
Вы можете заставить пользователя приложения подождать, пока ваш метод copy()
не будет завершен, показывая вращающийся загрузчик непосредственно передВаш метод copy()
запускается и скрывает загрузчик, как только метод завершен. Этот метод загрузчика гарантирует, что пользователь не выполнит никакого события, связанного с пользовательским интерфейсом (например, нажатие кнопки), пока метод copy()
не будет завершен. Вот кодизвините за код в Kotlin .
class DialogUtil private constructor() {
init {
throw AssertionError()
}
companion object {
private var progressDialog: ProgressDialog? = null
fun showAlertDialog(context: Context, message: String?) {
AlertDialog.Builder(context).setMessage(message)
.setCancelable(false).setPositiveButton("OK") {
dialogInterface, _ -> dialogInterface.dismiss() }.show()
}
fun showProgressDialog(context: Context) {
progressDialog = ProgressDialog(context)
progressDialog!!.setProgressStyle(ProgressDialog.STYLE_SPINNER)
progressDialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
progressDialog!!.setMessage("Please wait...")
progressDialog!!.setCancelable(false)
progressDialog!!.isIndeterminate = true
progressDialog!!.show()
}
fun hideProgressDialog() {
if (progressDialog != null) {
progressDialog!!.dismiss()
}
}
}
}
Сделайте вспомогательный класс likВыше e для loader, а затем чуть выше строки, где начинается ваш метод copy()
, вызовите этот загрузчик следующим образом
DialogUtil.showProgressDialog(this)
Above this относится к контексту, поэтому, если метод copy()
во фрагменте вам нужно передать activity
(getActivity () в java) вместо него.
Как только ваш метод copy()
завершится, вы можете скрыть вращающийся загрузчик следующим образом:
DialogUtil.hideProgressDialog()
напишите эту строку чуть ниже вашего copy()
метода.
Второй способ - запустить метод copy()
в каком-то другом потоке, так что вашему потоку пользовательского интерфейса (основному потоку) не нужно заботиться о методе copy()
и ваше приложение будет сохранено от замораживания. Одно из преимуществЭтот метод заключается в том, что даже если ваш copy()
метод все еще выполняется, пользователь все равно может выполнять события, связанные с пользовательским интерфейсом, не испытывая дрожания или задержки. Я предлагаю вам использовать AsyncTask для выполнения copy()
метод, поскольку он может выполнять длинные задачи в рабочем потоке, а затем может предоставить вам возможность уведомить пользователя о завершении задачи в основном потоке (UI).Код выглядит следующим образом:
private class MyTask extends AsyncTask<X, Y, Z>
{
protected void onPreExecute(){
//any specific setup before you start copy() method , runs on UI
// thread
}
protected Z doInBackground(X...x){
// your copy() method itself, runs on worker thread other than main UI
// thread, don't perform any UI related activities from here , since
// it is the worker thread
}
protected void onProgressUpdate(Y y){
//any event you wanna perform , while the task is in progress, runs on
//UI main thread
}
protected void onPostExecute(Z z){
//the event you wanna perform once your copy() method is complete, runs
//on UI main thread
}
}
После определения класса вы можете запустить этот AsyncTask следующим образом:
MyTask myTask = new MyTask();
myTask.execute(x);
Куда бы я ни упомянул пользовательский интерфейсЭто означает, что оттуда вы можете выполнить любую задачу или операцию, связанную с пользовательским интерфейсом.Вы должны помнить, что события пользовательского интерфейса могут выполняться только из потока пользовательского интерфейса, если вы пытаетесь выполнить операции, связанные с пользовательским интерфейсом, из потока, отличного от потока пользовательского интерфейса (основной поток) приложение может неожиданно закрыться.
Я предлагаю сделать этот AsyncTask как внутренний класс, в самом фрагменте, вместо создания нового класса полностью.