I am writing a programm that returns me a ArrayList of Strings. Problem is, when I call the method the list is not filled yet so I get an empty list back .
I tried it with a thread but now I get a null reference when I call the method. By the way i had to implement a async task, otherwise I get an exception when trying to use InetAddress.
private class DeviceManager extends Thread {
private ArrayList<String> deviceList;
private String networkIP;
public DeviceManager(String networkIP) {
this.networkIP = networkIP;
}
public void run() {
getDeviceList();
}
public ArrayList<String> getDeviceList() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
deviceList = new ArrayList<String>();
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
return deviceList;
}
public ArrayList<String> getList() {
return this.deviceList;
}
}
Artur what you are doing in your code is starting a thread to retrieve device list and then another thread(AsyncTask) to actually creates the device list. So you have three threads running here simultaneously (assuming you are using DeviceManager class in UIThread). The reason getDeviceList() is returning null is because AsyncTasks doInBackground hasn't run yet to collect your device list it might be waiting for its chance to get scheduled. so to conclude that, you just need one thread(other than UIThread), it can either be a Thread or AsyncTask (more preferable as it gives better control) as rusted brain has used in his answer. I prefer to make DeviceManager as AsyncTask (just a bit cleaner and if device managers only task is to retrieve device list) as code below.
in AsyncTask doInBackground runs in a background thread(as name suggests) and onPostExecute runs on the UI thread after doInBackground
class DeviceManager extends AsyncTask<String, Void, List<String>> {
private ConnectionCompleteListener listener;
public interface ConnectionCompleteListener {
void onSuccess(List<String> deviceList);
// if you need to know reason for failure you can add
// parameter to onFailure
void onFailure();
}
public DeviceManager(ConnectionCompleteListener listener) {
this.listener = listener;
}
#Override
protected List<String> doInBackground(String... params) {
List<String> deviceList = new ArrayList<>();
String networkIP = params[0];
try {
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
} catch (IOException e) {
deviceList = null;
e.printStackTrace();
}
return deviceList;
}
#Override
protected void onPostExecute(List<String> deviceList) {
if (deviceList == null) {
this.listener.onFailure();
} else {
this.listener.onSuccess(deviceList);
}
}
}
so in your activity you can call
new DeviceManager(new DeviceManager.ConnectionCompleteListener
() {
#Override
public void onSuccess(List<String> deviceList) {
}
#Override
public void onFailure() {
}
}).execute("YOUR_NETWORK_IP");
You are doing it completely wrong. A Thread runs in the background and so does AsyncTask, so basically you are making a background task run in background. Inception.
Try this:
public class DeviceManager {
private ArrayList<String> deviceList;
private String networkIP;
private ConnectionCompleteListener listener;
public interface ConnectionCompleteListener {
void onSuccess();
void onFailure();
}
public void setConnectionCompleteListener(ConnectionCompleteListener listener) {
this.listener = listener;
}
public DeviceManager(String networkIP) {
this.networkIP = networkIP;
}
public void getDeviceList() {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected void onPostExecute(Boolean result) {
if(result) listener.onSuccess();
else listener.onFailure();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
deviceList = new ArrayList<String>();
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
return true;
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return null;
}
}.execute();
}
public ArrayList<String> getList() {
return this.deviceList;
}
}
Then in your other class:
private class classname{
DeviceManager manager=new DeviceMnager(networkIp);
manger.setConnectionCompleteListener(new DeviceManager.ConnectionCompleteListener() {
#Override
public void onSuccess() {
// get your list here
manager.getList();
}
#Override
public void onFailure() {
// connection failed show error
}
});
}
You are getting empty array list because as you are using async task for getting array list and async task doINBackground method runs on different thread(means not on main thread). So when your program runs then your program doesn't wait for async task response.
You can solve this like that...
Use onPostExecute method in async task class and return the arraylist
#Override
protected void onPostExecute(Void result) {
//return array list here
getList();
}
Hope this will help you
First of All you don't need to make DeviceManager a thread as the task which you are running in getDeviceList will start in another new thread. Second You shouldn't wait on main(UI) thread so instead of waiting callback is a better mechanism.
If you insist on the same code try this..
public class DeviceManager extends Thread {
private ArrayList<String> deviceList;
private String networkIP;
private boolean dataAvailable;
public DeviceManager(String networkIP) {
this.networkIP = networkIP;
}
public void run() {
getDeviceList();
}
public ArrayList<String> getDeviceList() {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
deviceList = new ArrayList<String>();
InetAddress address;
Log.i("NetworkIPgetDeviceList", networkIP);
String deviceIP = networkIP;
for (int i = 0; i < 255; i++) {
System.out.println("checking " + i);
address = InetAddress.getByName(deviceIP += "" + i);
if (address.isReachable(2000)) {
Log.i("Devicefound", deviceIP);
deviceList.add(deviceIP);
}
deviceIP = networkIP;
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
dataAvailable = true;
synchronized (DeviceManager.this) {
DeviceManager.this.notify();
}
return null;
}
}.execute();
return deviceList;
}
synchronized public ArrayList<String> getList() {
while (!dataAvailable) {
try {
wait();
} catch (InterruptedException e) {
}
}
return this.deviceList;
}
}
Related
private final WorkerRunnable<Params, Result> mWorker;
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
I take red line in mWorker = new WorkerRunnable<Params, Result>() row.This is java own class.I don't understand how can i take error.Please help me.
public AsyncTask(Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
I called execute in oncreate() method like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_solution);
resultt = findViewById(R.id.recognizeResult2);
resultview = findViewById(R.id.textView);
new WolframFeed().execute();
}
and I use AsyncTask like this
private class WolframFeed extends AsyncTask<Void, Void, String> {
private WAException exception;
#Override
protected String doInBackground(Void... params) {
String result="";
inputText = "solve " +resultt.getText().toString();
try {
Log.e("TRYing", "wolfram try/");
WAEngine engine = new WAEngine();
engine.setAppID(APP_ID);
//engine.addPodState("Result__Step-by-step solution");
engine.addFormat("plaintext");
WAQuery query = engine.createQueryFromURL(createFullURL());
/*WAQuery query = engine.createQuery();
query.setInput(inputText);*/
WAQueryResult queryResult = engine.performQuery(query);
if (queryResult.isError()) {
String err= "Query error" + " error code: " + queryResult.getErrorCode() + " error message: " + queryResult.getErrorMessage();
Log.e("err: ",err);
} else if (!queryResult.isSuccess()) {
Log.e("err: " ,"Query was not understood; no results available.");
} else {
// Got a result.
Log.e("err: ","Successful query. Pods follow:\n");
for (WAPod pod : queryResult.getPods()) {
if (!pod.isError()) {
result+="\n";
for (WASubpod subpod : pod.getSubpods()) {
for (Object element : subpod.getContents()) {
if (element instanceof WAPlainText) {
if(((WAPlainText) element).getText()!=""){
result+=pod.getTitle();
result+= ((WAPlainText) element).getText();
result+="\n";
}
}
}
}
}
}
}
} catch (WAException e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
resultview.setText(result);
}
}
Please help me where am i making a mistake.
I am having a problem which is I think that I can't access th,e ListView from the asyncTask
Actually, I really don't know the real problem here
Let me show you what is happening
I have an activity which is executing AsyncTask and creates HttpURLConnection. Sometimes I get an exception (ProtocolException) because the stream un-expectedly ends.
So, I created a handler for this exception that calls a function or a method inside the class of the activity to display a message to the user
Here is a picture so you understand what is my project.
image
the problem here whenever the exception is thrown, the same function/method that I use to add the text to the listView is called, but after it called the listView disappear, but when I minimize the soft keyboard manually the everything becomes fine.
the structure of my class is
public class MainActivity extends AppCompatActivity
{
protected void onCreate(Bundle savedInstanceState)
{
addMessageToListView()//works fin here
}
protected void addMessage(String message, int userMessage, ListView listView) // the function
{
try
{
messages.add(new Message(message,userMessage));
MessagesAdapter messagesAdapter = new MessagesAdapter(messages, getBaseContext());
messagesAdapter.notifyDataSetChanged();
listView.setAdapter(messagesAdapter);
}
catch (Exception exception)
{
}
}
private class HttpPostAsyncTask extends AsyncTask<String, Void, String>
{
...
#Override
protected void onPostExecute(String result)
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
}
}
protected String doInBackground(String... params)
{
String result = "";
for (int i = 0; i <= 0; ++i)
{
result = this.invokePost(params[i], this.postData);
}
return result;
}
private String invokePost(String requestURL, HashMap<String, String> postDataParams)// called from doInBackground
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
addMessageToListView()//not orking here
}
}
}
}
I don't know how to explain more actually.
You can change Views only in mainthread of your app. The doInBackground doesn't run in mainthread of your app.
Solved by adding:
new Thread()
{
#Override
public void run()
{
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
addMessageToListView()//not orking here
}
});
super.run();
}
}.start();
Editing the previous code in my question:
public class MainActivity extends AppCompatActivity
{
protected void onCreate(Bundle savedInstanceState)
{
addMessageToListView()//works fin here
}
protected void addMessage(String message, int userMessage, ListView listView) // the function
{
try
{
messages.add(new Message(message,userMessage));
MessagesAdapter messagesAdapter = new MessagesAdapter(messages, getBaseContext());
messagesAdapter.notifyDataSetChanged();
listView.setAdapter(messagesAdapter);
}
catch (Exception exception)
{
}
}
private class HttpPostAsyncTask extends AsyncTask<String, Void, String>
{
...
#Override
protected void onPostExecute(String result)
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
}
}
protected String doInBackground(String... params)
{
String result = "";
for (int i = 0; i <= 0; ++i)
{
result = this.invokePost(params[i], this.postData);
}
return result;
}
private String invokePost(String requestURL, HashMap<String, String> postDataParams)// called from doInBackground
{
try
{
addMessageToListView()//works fin here
}
catch (Exception exception)
{
new Thread()
{
#Override
public void run()
{
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
addMessageToListView()//not orking here
}
});
super.run();
}
}.start();
}
}
}
}
Other class:
SpotifyTask st = new SpotifyTask(new Closure<JSONObject>() {
#Override
public void executeOnSuccess(JSONObject result) {
track.setJson(result);
}
});
st.execute("asd");
Being SpotifyTask:
public class SpotifyTask extends AsyncTask<Object, Void, JSONObject> {
private final Closure<JSONObject> closure;
public SpotifyTask(Closure<JSONObject> closure) {
this.closure = closure;
}
public static void getTrack(Closure<JSONObject> closure) {
new SpotifyTask(closure).execute("asd");
}
#Override
protected JSONObject doInBackground(Object... params) {
JSONObject result = null;
SpotifyCall spcall = new SpotifyCall();
try {
result = spcall.getTrack();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
#Override
protected void onPostExecute(JSONObject result) {
System.out.println("ASD: on post execute "+result);
closure.executeOnSuccess(result);
}
}
So... doInBackground is running OK, and and returning a JSONObject all right; I know because Im debbuging it and "result" IS a JSONObject.
But onPostExecute is never executed, the debugger never gets there and "ASD: on postexecute "+result is never logged.
Any suggestions?
Thanks in advance!
The problem was that I was "holding" the UI Thread:
this.status = "loading";
final Track track = new Track();
SpotifyTask.getTrack(new Closure<JSONObject>() {
#Override
public void executeOnSuccess(JSONObject result) {
track.setJson(result);
}
});
while (this.status.equals("loading")) {
if (track.getJson() != null) {
this.trackUno = track.getJson();
this.status = "ready";
} else {
try {
System.out.println("Not ready, waiting.");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
As soon I removed the while block, it worked perfectly.
I would have to find another way to "wait" for the call to be complete.
Thanks for your time fellas!
I added the AsyncTask to offload network operations to a background thread.I need to make sure the UI operations are on the UI thread.So i want to Use runOnUiThread() in my Activity.
Thanks for your help
WifiApManager
public class WifiApManager {
private final WifiManager mWifiManager;
public WifiApManager(Context context) {
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
try {
if (enabled) { // disable WiFi in any case
mWifiManager.setWifiEnabled(false);
}
Method method = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
return (Boolean) method.invoke(mWifiManager, wifiConfig, enabled);
} catch (Exception e) {
Log.e(this.getClass().toString(), "wifi", e);
return false;
}
}
public WIFI_AP_STATE getWifiApState() {
try {
Method method = mWifiManager.getClass().getMethod("getWifiApState");
int tmp = ((Integer)method.invoke(mWifiManager));
// Fix for Android 4
if (tmp > 10) {
tmp = tmp - 10;
}
return WIFI_AP_STATE.class.getEnumConstants()[tmp];
} catch (Exception e) {
Log.e(this.getClass().toString(), "wifi", e);
return WIFI_AP_STATE.WIFI_AP_STATE_FAILED;
}
}
public boolean isWifiApEnabled() {
return getWifiApState() == WIFI_AP_STATE.WIFI_AP_STATE_ENABLED;
}
public WifiConfiguration getWifiApConfiguration() {
try {
Method method = mWifiManager.getClass().getMethod("getWifiApConfiguration");
return (WifiConfiguration) method.invoke(mWifiManager);
} catch (Exception e) {
Log.e(this.getClass().toString(), "wifi", e);
return null;
}
}
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
Method method = mWifiManager.getClass().getMethod("setWifiApConfiguration", WifiConfiguration.class);
return (Boolean) method.invoke(mWifiManager, wifiConfig);
} catch (Exception e) {
Log.e(this.getClass().toString(), "wifi", e);
return false;
}
}
public ArrayList<ClientScanResult> getClientList(boolean onlyReachables) {
return getClientList(onlyReachables, 10);
}
public ArrayList<ClientScanResult> getClientList(boolean onlyReachables, int reachableTimeout) {
BufferedReader br = null;
ArrayList<ClientScanResult> result = null;
try {
result = new ArrayList<ClientScanResult>();
br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null) {
String[] splitted = line.split(" +");
if ((splitted != null) && (splitted.length >= 4)) {
// Basic sanity check
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")) {
boolean isReachable = InetAddress.getByName(splitted[0]).isReachable(reachableTimeout);
if (!onlyReachables || isReachable) {
result.add(new ClientScanResult(splitted[0], splitted[3], splitted[5], isReachable));
}
}
}
}
} catch (Exception e) {
Log.e(LOGTAG, e.toString());
} finally {
try {
br.close();
} catch (IOException e) {
Log.e(LOGTAG, e.toString());
}
}
return result;
}
}
connect.java
public class connect extends Activity{
WifiApManager wifiApManager;
TextView tv;
Button scan;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.connect);
tv =(TextView) findViewById(R.id.iptv);
new scan().execute();
}
public class scan extends AsyncTask<String, Integer, String> {
public Object WIFI_SERVICE;
#Override
protected void onProgressUpdate(Integer...integers) {
ArrayList<ClientScanResult> clients = wifiApManager.getClientList(false);
tv.setText("WifiApState: " + wifiApManager.getWifiApState() + "\n\n");
tv.append("Clients: \n");
for (ClientScanResult clientScanResult : clients) {
tv.append("####################\n");
tv.append("IpAddr: " + clientScanResult.getIpAddr() + "\n");
tv.append("Device: " + clientScanResult.getDevice() + "\n");
tv.append("HWAddr: " + clientScanResult.getHWAddr() + "\n");
tv.append("isReachable: " + clientScanResult.isReachable()+ "\n");
}
}
#Override
protected void onPostExecute(String result){
tv.setText(result);
}
#Override
protected String doInBackground(String... params) {
wifiApManager = new WifiApManager(this);
// the above line shows a Error
return null;
}
}
}
EDIT
I want to Display the processed text in a TextView
class scan extends AsyncTask<String, Void, Void> {
public Context context;
ArrayList<ClientScanResult> clients;
public scan(Context c) // constructor to take Context
{
context = c; // Initialize your Context variable
}
protected Void doInBackground(String... params) {
wifiApManager = new WifiApManager(context); // use the variable here
clients = wifiApManager.getClientList(false);
return null;
}
}
protected void onPostExecute(Void result){
ArrayList<ClientScanResult> clients;
tv.setText("WifiApState: " + wifiApManager.getWifiApState() + "\n\n");
tv.append("Clients: \n");
for (ClientScanResult clientScanResult : clients)//showin error in clients
{
tv.append("####################\n");
tv.append("IpAddr: " + clientScanResult.getIpAddr() + "\n");
tv.append("Device: " + clientScanResult.getDevice() + "\n");
tv.append("HWAddr: " + clientScanResult.getHWAddr() + "\n");
tv.append("isReachable: " + clientScanResult.isReachable()+ "\n");
}
}
}
I added the AsyncTask to offload network operations to a background thread.I need to make sure the UI operations are on the UI thread.So i want to Use runOnUiThread() in my Activity.
Ugh! No!!! Every method of AsyncTask runs on the UI Thread except for doInBackground(). So do your network operations in doInBackground() and update the UI in onPostExecute() or in onProgressUpdate() by calling publishProgress() from doInBackground().
Do not use runOnUiThread() with AsyncTask. There is no reason, at least known to me, to use that with AsyncTask since it has methods that already run on the UI Thread. I have never seen it do anything but cause trouble.
You can either call publishProgress() from your loop and update your TextView in onProgressUpdate() or add the values to an ArrayList and update in onProgressUpdate().
Please read the docs several times. AsyncTask is a bit tricky at first but once you learn what it does then it can be a beautiful thing.
Edit
Create an instance of your AsyncTask and pass your Activity Context to it
Scan myScan = new scan(this); // pass the context to the constructor
myScan.execute();
Then create a constructor in your AsyncTask and have it accept a Context.
public class scan extends AsyncTask<String, Integer, String>
{
public Object WIFI_SERVICE;
public Context context; // Context variable
public scan(Context c) // constructor to take Context
{
context = c; // intialize your Context variable
}
Now use that variable
#Override
protected String doInBackground(String... params)
{
wifiApManager = new WifiApManager(context); // use the variable here
return null;
}
Another Edit
class scan extends AsyncTask<String, Void, Void> {
ArrayList<ClientScanResult> clients;
Context context;
...
then initialize your `clients` in `doInBackground()`
clients = wifiApManager.getClientList(false);
change onPostExecute() to not accept anything
protected void onPostExecute(Void result){
and put your code that updates the TextView in there.
You should not be accessing any UI elements within doInBackground, This method runs in background thread. What you should do is override onPostExecute() method and access your TextView there. onPostExecute runs in UI thread, so you don't need to call runOnUiThread()
This code is causing ANR force close any idea how to improve this code? i try with asynctask and i cant make it work in this code :
What i try to do here is updater activity will check for latest version and if got new version it will pop up alertdialog to ask user to update in the market
public class Updater extends Activity {
private int newVerCode = 0;
private String newVerName = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (getServerVerCode()) {
int vercode = Config.getVerCode(this);
if (newVerCode > vercode) {
doNewVersionUpdate();
} else {
notNewVersionShow();
}
}
}
//check version using json
private boolean getServerVerCode() {
try {
String verjson = NetworkTool.getContent(Config.UPDATE_SERVER
+ Config.UPDATE_VERJSON);
JSONArray array = new JSONArray(verjson);
if (array.length() > 0) {
JSONObject obj = array.getJSONObject(0);
try {
newVerCode = Integer.parseInt(obj.getString("verCode"));
newVerName = obj.getString("verName");
} catch (Exception e) {
newVerCode = -1;
newVerName = "";
return false;
}
}
} catch (Exception e) {
return false;
}
return true;
}
//Found No new version
private void notNewVersionShow() {
Updater.this.finish(); // End updater activity
}
//Found New version
private void doNewVersionUpdate() {
//Display alertdialog
}
}
You can use an AsyncTask - yes. In doInBackground you can add the code from getServerVerCode() and in onPostExecute everything in the if (getServerVerCode()).
doInBackground can return boolean so you know in onPostExecute what the result is.
Something like this:
private class GetServerVerCode extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
try {
String verjson = NetworkTool.getContent(Config.UPDATE_SERVER
+ Config.UPDATE_VERJSON);
JSONArray array = new JSONArray(verjson);
if (array.length() > 0) {
JSONObject obj = array.getJSONObject(0);
try {
newVerCode = Integer.parseInt(obj.getString("verCode"));
newVerName = obj.getString("verName");
} catch (Exception e) {
newVerCode = -1;
newVerName = "";
return false;
}
}
} catch (Exception e) {
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
int vercode = Config.getVerCode(this);
if (newVerCode > vercode) {
doNewVersionUpdate();
} else {
notNewVersionShow();
}
}
}
}