Hello!

Such a problem. I use ASyncTask to perform a heavy operation that is beyond the capacity of the main thread (there was already my topic about it: Skipped 2137 frames! The application may be doing very much )

But there was such a problem. In the code, everything seems to be correct, it does not give any errors, but the code does not work properly

So there is an interface. After the user, using the Navigation Drawer, enters the necessary fragment, ASyncTask (third in the code) should immediately be executed. It requests root rights and checks if the system service is running (pgrep rngd command), in this case the Entropy service. All this is done on the OnBackground. After checking, it must set the oneperem variable to the value 1, if the service is running, or 0, if the service is not running. After this, the process should go to the onPostExecute stage, where the onBackground result is processed, that is, the interface is updated in accordance with the oneperem value (see above). It updates 3 items - TextView, which shows whether the service is running, as well as the "Start service" and "Stop service" buttons that run under certain conditions (for example, if the service is started, then the "Start service" button is blocked and remains active just the stop button and vice versa). But it works somehow strange. When a fragment is started, ASyncTask is launched - the superuser rights are requested, then the buttons and the service status are updated in the interface. But for some reason, the status of the service is always "Service not started", although it is running on the system. But after clicking the "Start service" button, it shows toast that the service is running (although in reality the service is already running), and after updating the fragment (after I re-enter it), ASyncTask is either not running or running through 15 seconds, with the same result. In this case, there are no errors in the log, the code seems to be written correctly in my opinion. I hope that someone will help solve the problem, because I do not know what to do already ....

AsyncTask code

public class Wrapper { public int oneperem; } public class third extends AsyncTask<String, Void, Wrapper> { private Context mContext; private View rootView; public Button startentropy, stopentropy; public TextView entropystatus; public third(Context context, View rootView){ this.mContext=context; this.rootView=rootView; } @Override public Wrapper doInBackground(String... args) { final Wrapper w = new Wrapper(); if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "pgrep rngd") { @Override public void commandOutput(int id, String line) { super.commandOutput(id, line); if (line.matches("[0-9]+")) { w.oneperem = 1; } } @Override public void commandCompleted(int id, int exitcode) { super.commandCompleted(id, exitcode); if (exitcode == 1) { w.oneperem = 0; } } }; try { RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); } } else { } return w; } @Override public void onPostExecute(Wrapper w) { if (w.oneperem == 1) { entropystatus = (TextView) rootView.findViewById(R.id.entropystatus); entropystatus.setText("СТАТУС СЕРВИСА: ВКЛЮЧЕН"); entropystatus.setBackgroundResource(R.drawable.roundbuttongood); startentropy = (Button) rootView.findViewById(R.id.startentropy); startentropy.setBackgroundResource(R.drawable.roundbuttonfuck); startentropy.setEnabled(false); startentropy.setTextColor(Color.WHITE); stopentropy = (Button) rootView.findViewById(R.id.stopentropy); stopentropy.setBackgroundResource(R.drawable.roundbuttoncal); stopentropy.setEnabled(true); stopentropy.setTextColor(Color.WHITE); stopentropy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "entropy_disable"); try { Toast.makeText(mContext, "Сервис остановлен!", Toast.LENGTH_SHORT).show(); RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); Toast.makeText(mContext, "ОШИБКА, СВЯЖИТЕСЬ С РАЗРАБОТЧИКОМ!", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(mContext, "ОШИБКА!", Toast.LENGTH_SHORT).show(); } } }); } if (w.oneperem == 0) { entropystatus = (TextView) rootView.findViewById(R.id.entropystatus); entropystatus.setText("СТАТУС СЕРВИСА: ВЫКЛЮЧЕН"); entropystatus.setBackgroundResource(R.drawable.roundbuttonbad); stopentropy = (Button) rootView.findViewById(R.id.stopentropy); stopentropy.setBackgroundResource(R.drawable.roundbuttonfuck); stopentropy.setEnabled(false); stopentropy.setTextColor(Color.WHITE); startentropy = (Button) rootView.findViewById(R.id.startentropy); startentropy.setBackgroundResource(R.drawable.roundbuttoncal); startentropy.setEnabled(true); startentropy.setTextColor(Color.WHITE); startentropy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "entropy_enabler"); try { Toast.makeText(mContext, "Сервис запущен!", Toast.LENGTH_SHORT).show(); RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); Toast.makeText(mContext, "ОШИБКА, СВЯЖИТЕСЬ С РАЗРАБОТЧИКОМ!", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(mContext, "ОШИБКА!", Toast.LENGTH_SHORT).show(); } } }); } } } 

ASyncTask startup code

  Handler handler = new Handler(); handler.postDelayed( new Runnable() { public void run() { Context cont=getActivity(); if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) { new third(cont, view ).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { new third(cont, view ).execute(); } } }, 1); 

Full EntropyFragment Code

 package com.nowenui.systemtweaker.fragments; import android.support.v4.app.Fragment; import android.content.Context; import android.graphics.Color; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import com.nowenui.systemtweaker.R; import com.stericson.RootShell.exceptions.RootDeniedException; import com.stericson.RootShell.execution.Command; import com.stericson.RootTools.RootTools; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeoutException; public class EntropyFragment extends Fragment { private Button entropy, delete; public static EntropyFragment newInstance(Bundle bundle) { EntropyFragment messagesFragment = new EntropyFragment(); if (bundle != null) { messagesFragment.setArguments(bundle); } return messagesFragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_entropy, parent, false); Handler handler = new Handler(); handler.postDelayed( new Runnable() { public void run() { Context cont=getActivity(); if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) { new third(cont, view ).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { new third(cont, view ).execute(); } } }, 1); entropy = (Button) view.findViewById(R.id.entropy); entropy.setBackgroundResource(R.drawable.roundbuttoncal); entropy.setTextColor(Color.WHITE); File f = new File("/system/xbin/rngd"); if (f.exists()) { entropy.setEnabled(false); entropy.setBackgroundResource(R.drawable.roundbuttonfuck); entropy.setText("Необходимые библиотеки уже установлены. \nУстановка не требуется, просто пользуйтесь"); } else { entropy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (RootTools.isBusyboxAvailable()) { if (RootTools.isRootAvailable()) { if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "cp /sdcard/Android/data/com.nowenui.systemtweaker/files/rngd /system/xbin/rngd", "chmod 755 /system/xbin/rngd", "cp /sdcard/Android/data/com.nowenui.systemtweaker/files/entro /system/xbin/entro", "chmod 755 /system/xbin/entro", "cp /sdcard/Android/data/com.nowenui.systemtweaker/files/entropy_enabler /system/bin/entropy_enabler", "chmod 777 /system/bin/entropy_enabler", "cp /sdcard/Android/data/com.nowenui.systemtweaker/files/entropy_disable /system/bin/entropy_disable", "chmod 777 /system/bin/entropy_disable"); try { Toast.makeText(getActivity(), "Необходимые файлы установлены!", Toast.LENGTH_SHORT).show(); RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); Toast.makeText(getActivity(), "ОШИБКА. СВЯЖИТЕСЬ С РАЗРАБОТЧИКОМ", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(getActivity(), "ОШИБКА! ", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(getActivity(), "ОШИБКА!", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(getActivity(), "ОШИБКА! НЕ УСТАНОВЛЕН BUSYBOX!", Toast.LENGTH_SHORT).show(); RootTools.offerBusyBox(getActivity()); } } }); } return view; } public class Wrapper { public int oneperem; } public class third extends AsyncTask<String, Void, Wrapper> { private Context mContext; private View rootView; public Button startentropy, stopentropy; public TextView entropystatus; public third(Context context, View rootView){ this.mContext=context; this.rootView=rootView; } @Override public Wrapper doInBackground(String... args) { final Wrapper w = new Wrapper(); if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "pgrep rngd") { @Override public void commandOutput(int id, String line) { super.commandOutput(id, line); if (line.matches("[0-9]+")) { w.oneperem = 1; } } @Override public void commandCompleted(int id, int exitcode) { super.commandCompleted(id, exitcode); if (exitcode == 1) { w.oneperem = 0; } } }; try { RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); } } else { } return w; } @Override public void onPostExecute(Wrapper w) { if (w.oneperem == 1) { entropystatus = (TextView) rootView.findViewById(R.id.entropystatus); entropystatus.setText("СТАТУС СЕРВИСА: ВКЛЮЧЕН"); entropystatus.setBackgroundResource(R.drawable.roundbuttongood); startentropy = (Button) rootView.findViewById(R.id.startentropy); startentropy.setBackgroundResource(R.drawable.roundbuttonfuck); startentropy.setEnabled(false); startentropy.setTextColor(Color.WHITE); stopentropy = (Button) rootView.findViewById(R.id.stopentropy); stopentropy.setBackgroundResource(R.drawable.roundbuttoncal); stopentropy.setEnabled(true); stopentropy.setTextColor(Color.WHITE); stopentropy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "entropy_disable"); try { Toast.makeText(mContext, "Сервис остановлен!", Toast.LENGTH_SHORT).show(); RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); Toast.makeText(mContext, "ОШИБКА, СВЯЖИТЕСЬ С РАЗРАБОТЧИКОМ!", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(mContext, "ОШИБКА!", Toast.LENGTH_SHORT).show(); } } }); } if (w.oneperem == 0) { entropystatus = (TextView) rootView.findViewById(R.id.entropystatus); entropystatus.setText("СТАТУС СЕРВИСА: ВЫКЛЮЧЕН"); entropystatus.setBackgroundResource(R.drawable.roundbuttonbad); stopentropy = (Button) rootView.findViewById(R.id.stopentropy); stopentropy.setBackgroundResource(R.drawable.roundbuttonfuck); stopentropy.setEnabled(false); stopentropy.setTextColor(Color.WHITE); startentropy = (Button) rootView.findViewById(R.id.startentropy); startentropy.setBackgroundResource(R.drawable.roundbuttoncal); startentropy.setEnabled(true); startentropy.setTextColor(Color.WHITE); startentropy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (RootTools.isAccessGiven()) { Command command1 = new Command(0, "entropy_enabler"); try { Toast.makeText(mContext, "Сервис запущен!", Toast.LENGTH_SHORT).show(); RootTools.getShell(true).add(command1); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); Toast.makeText(mContext, "ОШИБКА, СВЯЖИТЕСЬ С РАЗРАБОТЧИКОМ!", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(mContext, "ОШИБКА!", Toast.LENGTH_SHORT).show(); } } }); } } } } 

Layout Code

 <?xml version="1.0" encoding="utf-8"?> 

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:weightSum="1"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="" android:id="@+id/entropystatus" android:layout_weight="0.04" android:gravity="center_vertical|center|center_horizontal" android:textColor="#ffffff" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Entropy Generator позволяет ускорить работу устройства путем выполнения специальных операций в /dev/random. Учтите, что данная утилита действительно полезна только для старых версий Android (ниже 4.4), на Android 4.4-6.0 она, естественно, работает, но существенного эффекта прироста производительности Вы скорее всего не заметите" android:id="@+id/textView33" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Сначала, если требуется, установите библиотеку по работе с Entropy, потом чтобы включить Entropy Generator, нажмите соответствующую кнопку\n\n" android:id="@+id/textView35" /> <Button android:layout_width="330dp" android:layout_height="55dp" android:text="Установить библиотеку работы с Entropy Generator\n" android:id="@+id/entropy" android:layout_gravity="top|center_horizontal" android:layout_marginBottom="10dp" android:gravity="center_vertical|center|center_horizontal" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:text="Статус кнопки обновляется только после перезагрузки страницы" android:id="@+id/textView9" android:layout_gravity="center_horizontal" android:layout_marginTop="-10dp" android:layout_marginBottom="10dp" android:gravity="center_vertical|center|center_horizontal" android:textSize="10dp" /> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0.03"> <Button android:layout_width="162dp" android:layout_height="wrap_content" android:text="Запустить сервис" android:id="@+id/startentropy" android:layout_weight="0.04" android:layout_gravity="left|top" /> <Button android:layout_width="159dp" android:layout_height="wrap_content" android:text="Остановить сервис" android:id="@+id/stopentropy" android:layout_weight="0.04" android:layout_gravity="right|top" /> </FrameLayout> <Button android:layout_width="322dp" android:layout_height="wrap_content" android:text="Удалить Entropy Generator из системы" android:id="@+id/delete" android:layout_gravity="center_horizontal" android:layout_weight="0.04" android:layout_marginTop="10dp" /> </LinearLayout> 

  • honestly say, too lazy to read, a lot of text. I think it's not my laziness alone. Locate the problem, reduce the text once in 5 - Vladyslav Matviienko
  • I myself do not understand why the code does not work properly, or if the conditions in the doBackground are not fulfilled, or why the hell knows what ... - NowenUI
  • one
    Because the answer comes in callback. The AsyncTask thread does not wait for responses from the callback if they are running on another thread. - temq 6:51 pm
  • Thank! Here such implementation of callback will approach? stackoverflow.com/questions/15271271/… - NowenUI 6:59 pm

1 answer 1

Because the answer comes in callback. The AsyncTask thread does not wait for responses from the callback if they are running on another thread.

If RootTools.getShell(true).add(command1); executed in a separate thread, and after execution only one of the callbacks is called, then you can use CountDownLatch

The code will doInBackground() will be something like this:

 @Override public Wrapper doInBackground(String... args) { final Wrapper w = new Wrapper(); if (RootTools.isAccessGiven()) { CountDownLatch latch = new CountDownLatch(1); Command command1 = new Command(0,"pgrep rngd") { @Override public void commandOutput(int id, String line) { super.commandOutput(id, line); latch.countDown(); // остальной код } @Override public void commandCompleted(int id, int exitcode) { super.commandCompleted(id, exitcode); latch.countDown(); // остальной код } }; try { RootTools.getShell(true).add(command1); latch.await(); } catch (IOException | RootDeniedException | TimeoutException ex) { ex.printStackTrace(); } } else { } return w; } 

Call latch.await(); locks the current thread, and unlocks when the counter in the latch reaches 0. Because doInBackground() is executed in a separate thread, its blocking will not cause the UI to be blocked.

  • Thank you very much!!! Tomorrow I will try! - NowenUI
  • @NowenUI shoved await() little wrong. It should be after the launch of the command. Updated the answer. - temq
  • Thank you very much! Now ASyncTask works correctly, but there is a small problem. Apparently ASyncTask is executed only once, but it is necessary that it be executed when the fragment is restarted. It manifests itself this way: I enter the fragment, the program shows that the service is started, I click on the service stop button, I re-enter the fragment, the status is updated to "off". I press the "Start" button, reboot the fragment, and ... stupidly nothing happens, after a long wait (sec 20) the program returns that the service is off (although I pressed the enable button) - NowenUI
  • @NowenUI Well, here I can advise you to secure the code and see what happens. Keep in mind that when you exit the fragment, AsyncTask does not shut down, but continues to work until it reaches the end, and when you re-enter, another task will start. And you also have a strange launch of AsyncTask - it’s enough to execute only new third(cont, view ).execute(); without any handlers there. - temq 7:49 pm