I would like to know how to implement a thread in this class to make it safe from the problems of ANR (Application Not Responding)
public class myClass {
private static String LOG_TAG = Root.class.getName();
public boolean isDeviceRooted() throws IOException {
if (checkRootMethod1()){return true;}
if (checkRootMethod2()){return true;}
if (checkRootMethod3()){return true;}
return false;
}
public boolean checkRootMethod1(){
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
return false;
}
public boolean checkRootMethod2(){
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
return true;
}
else {
return false;
}
} catch (Exception e) {
}
return false;
}
public boolean checkRootMethod3() {
if (new ExecShell().executeCommand(SHELL_CMD.check_su_binary) != null){
return true;
}else{
return false;
}
}
}
If for example this code is execute when i press a button, if i press many times this button, my app have an ANR.
You don't want to use a Thread, but an AsyncTask. Here's how:
Based on the following, figure out what you need for your app: AsyncTask<TypeOfVarArgParams, ProgressValue, ResultValue>
Some inspiration:
public class MyClass {
//Something
public MyClass() {
new BackgroundTask().execute("Hello World");
}
}
private class BackgroundTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
// Prepare your background task. This will be executed before doInBackground
}
#Override
protected String doInBackground(String... params) {
// Your main code goes here
String iAmAString = "I have done something very heavy now...";
return iAmAString;
}
#Override
protected void onPostExecute(String result) {
// Whatever should happen after the background task has completed goes here
}
#Override
protected void onProgressUpdate(Void... values) {
// In here, you can send updates to you UI thread, for example if you're downloading a very large file.
}
}
Thread thread = new Thread()
{
#Override
public void run()
{
myClass rootChecker = new myClass();
isRooted = rootChecker.isDeviceRooted();
}
};
Related
This question already has answers here:
How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
(17 answers)
Closed 5 years ago.
I have two classes, MainActivity and Tempo and their codes
MainActity.java
public class MainActivity extends AppCompatActivity {
Tempo m_context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
m_context = Tempo.getInstance();
}
}
public void button_clicked(View v){
if( m_context.connect("a1",1)){
setTitle("Yeah!");
}else {
setTitle("No");
}
}
and Tempo.java
public class Tempo{
public boolean isConnected=false;
private static Tempo insta;
private Tempo() { }
public synchronized static Tempo getInstance() {
if (insta == null) {
insta = new Tempo();
}
return insta;
}
public boolean connect(String a, int aa) {
new DoTask().execute(a);
return isConnected;
}
public class DoTask extends AsyncTask<String,Void,Boolean> {
#Override
protected Boolean doInBackground(String... params) {
boolean result = true;
try {
//If I'm here everything is okay
} catch (IOException e) {
//If I'm here everything is !okay
result = false;
}
return result;
}
#Override
protected void onPostExecute(Boolean result)
{
isConnected = result;
}
}
}
Even though my work is done inside Tempo perfectly which means the boolean vars in Tempo class "result" and "isConnected" is meant to be true. No doubt they transformed to True after my work but the main issue is using those vars, I'm not able to go in if block of MainActivity.. which will change my title to "Yeah!". As per me it's because of AsyncTask throwing task in background hence making my vars remains the same(false) for some particular time??
Well, I need AsyncTask so that the UI won't stuck.
onPostExecute runs in the UI thread. so you can update the ui in this method instead of your MainActivity.
public class Tempo{
Activity activity;
public boolean isConnected=false;
private static Tempo insta;
private Tempo() { }
public synchronized static Tempo getInstance() {
if (insta == null) {
insta = new Tempo();
}
return insta;
}
public boolean connect(String a, int aa,Activity a) {
this.activity= a;
new DoTask().execute(a);
return isConnected;
}
public class DoTask extends AsyncTask<String,Void,Boolean> {
#Override
protected Boolean doInBackground(String... params) {
boolean result = true;
try {
//If I'm here everything is okay
} catch (IOException e) {
//If I'm here everything is !okay
result = false;
}
return result;
}
#Override
protected void onPostExecute(Boolean result)
{
if( result){
Activity.setTitle("Yeah!");
}else {
Activity.setTitle("No");
}
}
}
}
So as you can see I am passing the activity as a parameter then using that to update the UI in onPostExecute() method.
I've created a component which downloads an Image (in the Android side) and I want to send back size details about that image (to the JS side) of my app.
Now, I can safely say that I can call my component from JS and it will respond back with data but as soon as I add in the Async element to download the image from an URL, read it and respond I get a NullpointerException as soon as I call my callback.invoke("response text");
My problematic code is:
public void loadImage(final String url, final Callback onLoadCallback) {
...
new AsyncTask<String, Void, Void>() {
#Override
protected Void doInBackground(String... url) {
try {
theImage = Glide.with(getReactApplicationContext()).load(url[0]).asBitmap().into(-1, -1).get();
}
catch ...
return null;
}
#Override
protected void onPostExecute(Void dummy) {
if (null != theImage) {
onLoadCallback.invoke("Success"); //<== THIS LINE HERE
}
}
}.execute(url);
...
}
Now, I get that it's because I'm trying to return on a sep thread back to the main thread via the callback but I'm not sure how in the heck I'm supposed to get the info I want back to the JS side?! This is my first attempt at a component in RN so be kind! :)
Extra Info - My React module:
var MY_Image = require('NativeModules').MYImage;
var myimage = {
loadImage(url, onLoad) {
MY_Image.loadImage(url, onLoad)
},
};
module.exports = myimage;
Then in my React app view:
...
componentDidMount: function() {
myImage.loadImage('[URL to Image]',onLoad=> {
console.log('Success: '+onLoad);
});
}
Thanks for the input everyone. I've managed to sort this. I needed a class-wide variable to hold the callback in and a callback handler. Here's my code:
public class MyClass extends ReactContextBaseJavaModule {
private Bitmap mTheImage;
private Callback mCallback;
private WritableMap mResults;
public MyClass(ReactApplicationContext reactContext) {
super(reactContext);
this.mContext = reactContext;
}
private void consumeCallback(String type, WritableMap obj) {
if(mCallback!=null) {
obj.putString("type", type);
mCallback.invoke(obj);
mCallback = null;
}
}
#ReactMethod
public void doMyStuff(final String input, final Callback callback) {
if(mCallback==null) {
mResults = Arguments.createMap();
}
mCallback = callback;
new AsyncTask<String, Void, Void>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(String... params) {
try {
String myValue = params[0];
mResults.putString("myValue", myValue);
mTheImage = [method to get the image]
}
catch(Exception e) {
}
return null;
}
protected void onPostExecute(Void dummy) {
if(null!=mTheImage && null!=mCallback) {
mResults.putInt("width", mImage.getWidth());
mResults.putInt("height",mImage.getHeight());
consumeCallback("success", mResults);
}
else {
consumeCallback("error", mResults);
}
}
}.execute(url);
}
}
I want create Socket connection but i have some problem. I must create it in new Thread but i can not.
public class SocketManager {
private static SocketManager instance;
private BufferedReader in;
private PrintWriter out;
private Socket mSocket = null;
public static SocketManager me() {
if (instance == null) {
instance = new SocketManager();
}
return instance;
}
public void connection() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
mSocket = new Socket(Constants.CHAT_SERVER_URL, 4444);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
public boolean isConnected() {
return mSocket.isConnected();
}
and
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
status = (TextView) findViewById(R.id.status);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
SocketManager.me().connection();
if (SocketManager.me().isConnected()) {
status.setText("Connected");
} else {
status.setText("Disconnected");
}
I have error:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.net.Socket.isConnected()' on a null object reference
Becouse mSocket create in new Thread and when i call it it == null; How can create mSocket in new Thread and use it?
Best way is to use an interface.
Create an interface in your Socketmanager class
public class SocketManager {
private static SocketManager instance;
private SocketListner listner;
public interface SocketListner {
void onConnectionSuccess();
void onConnectionFailed();
}
public void connection(SocketListner listner) {
this.listner = listner;
new ConnectionTask().execute();
}
And return a boolean value from doInBackGround() method to check if the connection is success or not
class ConnectionTask new AsyncTask<Void, Void, Boolean>() {
#Override
protected Void doInBackground(Void... params) {
//...your code
}
#Override
protected void onPostExecute(Boolean result) {
if(result) {
listner.onConnectionSuccess();
} else {
listner.onConnectionFailed();
}
}
}
And in your activity implement the interface
public class YourActivity imlpements SocketListner {
#Override
protected void onCreate(Bundle savedInstanceState) {
//your code
..
}
#Override
void onConnectionSuccess() {
//your socket is connected
status.setText("Connected");
}
#Override
void onConnectionFailed() {
status.setText("Disconnected");
}
}
I think method "isConnected()" is trying to access mSocket before it is initialized.
Try to change it to:
public boolean isConnected() {
return mSocket == null ? false : mSocket.isConnected();
}
This will avoid the NullPointerException on this method.
But the correct approach here would be to use a callback so the child thread can inform the main thread when it has finished.
public class SocketTask extends AsyncTask<Void, Void, Void> {
public interface AsyncTaskListener<T> {
void onTaskCompleted(T t);
}
private final AsyncTaskListener<String> listener;
public SocketTask(AsyncTaskListener<String> listener) {
this.listener = listener;
}
#Override
protected Void doInBackground(Void... params) {
try {
mSocket = new Socket(Constants.CHAT_SERVER_URL, 4444);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute() {
listener.onTaskCompleted();
}
}
You class SocketManager need to implement the callback:
public class SocketManager implements SocketTask.AsyncTaskListener {
}
Add boolean to know your asynctask is complete or not.
boolean mIsSocketInstanceCreated = false;
public void connection() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
mSocket = new Socket(Constants.CHAT_SERVER_URL, 4444);
mIsSocketInstanceCreated = true;
} catch (IOException e) {
e.printStackTrace();
mIsSocketInstanceCreated = false;
}
return null;
}
}.execute();
}
public boolean isConnected() {
if (mIsSocketInstanceCreated)
return mSocket.isConnected();
return false;
}
Currently building an Android app and checking it on Genymotion running 4.1.1. I'm using AsyncTask to call the Bing Translate API to translate from text:
class TranslateFacebookText extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... message) {
String translatedText = "";
try {
translatedText = Translate.execute(message[0], Language.AUTO_DETECT, Language.ENGLISH);
} catch (Exception e) {
....
}
return translatedText;
}
#Override
protected void onPostExecute(String translatedText) {
message = translatedText;
confirmTTSData();
}
}
public void onClick(View src) {
TranslateFacebookText translateTask = new TranslateFacebookText();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
translateTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message);
}
else {
translateTask.execute(message);
}
}
I'm using this method to start the task after reading this question: Android SDK AsyncTask doInBackground not running (subclass)
I'm doing so, since after about 2-5 minutes from the programs start, the AsyncTask refuses to run. That is, doInBackground does not get called, nor does onPostExecute. the onClick DOES get called, creates the new AsyncTask and runs the execution code, but the doInBackground does not get called.
This is completely random. I'm not doing anything else - just waiting there for a couple of minutes, and afterwards clicking the button again to see this happen. This is also true with a service which runs every specified time using a Handler and postDelayed. Here's an example:
public class MyService extends Service {
private Handler periodicEventHandler;
private final int PERIODIC_EVENT_TIMEOUT = 600000;
#Override
public void onCreate() {
periodicEventHandler = new Handler();
periodicEventHandler.postDelayed(doPeriodicTask, PERIODIC_EVENT_TIMEOUT);
}
private Runnable doPeriodicTask = new Runnable()
{
public void run()
{
TranslateFacebookText translateTask = new TranslateFacebookText();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
translateTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message);
}
else {
translateTask.execute(message);
}
periodicEventHandler.postDelayed(doPeriodicTask, PERIODIC_EVENT_TIMEOUT);
}
};
class TranslateFacebookText extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... message) {
String translatedText = "";
try {
translatedText = Translate.execute(message[0], Language.AUTO_DETECT, Language.ENGLISH);
} catch (Exception e) {
....
}
return translatedText;
}
#Override
protected void onPostExecute(String translatedText) {
message = translatedText;
confirmTTSData();
}
}
}
The doPeriodicTask runs fine, again creating the AsyncTask and calling the execution code, but doInBackground never gets called. If I change PERIODIC_EVENT_TIMEOUT to 8000, for example, doInBackground would get called fine.
Ideas?
public interface DownloadListener {
public void onDownloaded();
}
public class DownloadManager {
private static DownloadManager instance;
private DownloadListener mDownloadListener;
public static synchronized DownloadManager getInstance(){
if(instance == null)
instance = new DownloadManager();
return instance;
}
private DownloadManager() {
myHandler.sendEmptyMessageDelayed(29, 3 * 1000);
}
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListener = downloadListener;
}
Handler myHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
if (msg.what == 29) {
mDownloadListener.onDownloaded();
return true;
}
return false;
}
});
}
public class I implements DownloadListener {
public I() {
DownloadManager.getInstance().registerDownloadListener(this);
}
#Override
public void onDownloaded() {
Log.e("TAG", "I onDownloaded");
}
}
public class You implements DownloadListener {
public You() {
DownloadManager.getInstance().registerDownloadListener(this);
}
#Override
public void onDownloaded() {
Log.e("TAG", "You onDownloaded");
}
}
public class PATTERNSActivity extends Activity implements DownloadListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new I();
new You();
DownloadManager.getInstance().registerDownloadListener(this);
}
#Override
public void onDownloaded() {
Log.e("TAG","PATTERNSActivity onDownloaded");
}
}
I am expecting to get:
I onDownloaded
You onDownloaded
PATTERNSActivity onDownloaded
But I am getting only:
PATTERNSActivity onDownloaded
What could it be the problem?
You keep registered downloaders in a single instance property:
// Last call's downloadListener wins.
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListener = downloadListener;
}
The last one registered is the activity's:
new I(); // First set singleton's property to an instance of I...
new You(); // ...then to an instance of You...
// ...then to the current instance.
DownloadManager.getInstance().registerDownloadListener(this);
Edit based on your comment.
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListeners.add(downloadListener);
}
...
public boolean handleMessage(Message msg) {
if (msg.what != 29) {
return false;
}
for (DownloadListener listener : mDownloadListeners) {
listener.onDownloaded();
}
return true;
}
In your code, this gets executed by calling mDownloadListener.onDownloaded(); in the DownloadManager class.
#Override
public void onDownloaded() {
Log.e("TAG","PATTERNSActivity onDownloaded");
}
In don't see why the onDownloaded methods of the I and YOU class should be executed, they're never called. Only the OnDownloaded method of your Listener is called.
For starters, I think you are not using a list. You just override the value so you will always get the last one:
public void registerDownloadListener(DownloadListener downloadListener) {
mDownloadListener = downloadListener;
}