Activity freezing on startup while another thread is doing work - android

Edit: As pointed out by Mike M. and Vladyslav Matviienko and Vivek Mishra
new Runnable().run();
is not a seperate Thread. Thank you guys :)
Edit End.
When I start a new Activity that uses a separate Thread to communicate with a Server it freezes.
I start a new Activity with
Intent i = new Intent(this, AcmActivity.class);
startActivityForResult(i, acm_ui);
then I run an asynchronous call to my client class in onCreate()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.acm);
//get the client implementation
ClientImpl client = ServiceManager.getService(ClientImpl.class);
client.getData(new PrivateClientCallback())
}
private class PrivateClientCallback implements GeneralCallback {
#Override
public void ok(final String response) {
runOnUiThread(new Runnable() {
#Override
public void run() {
updateSomeView(response);
}
});
}
}
The ClientImpl.getData() looks like this:
public synchronized void getData(GeneralCallback cb) {
new Runnable() {
#Override
public void run() {
//allow networking within this Thread
//read more here: https://stackoverflow.com/questions/25093546/android-os-networkonmainthreadexception-at-android-os-strictmodeandroidblockgua
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
//send some stuff to server and use the Callback
String stuff = someStuff();
cb.ok(stuff);
}.run();
}
Unfortunately my Activity freezes until the Call from the Server returned.
I would expect the Activity to start and when the server answers to update its views, unfortunately that is not what happens. I have no idea why.

new Runnable() is just a normal object. You need to create a new Thread with a runnable object. Then it'll run on a separate thread.
Check the code below
public synchronized void getData(GeneralCallback cb) {
new Thread(new Runnable() {
#Override
public void run() {
//allow networking within this Thread
//read more here: https://stackoverflow.com/questions/25093546/android-os-networkonmainthreadexception-at-android-os-strictmodeandroidblockgua
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
//send some stuff to server and use the Callback
String stuff = someStuff();
cb.ok(stuff);
}).start();
}

Related

Thread runs After activity life cycle?

I have network operation inside a thread which in oncreate() based on network response I need to process the next step but the thread is running after the activity life cycle.
I called networkRequest() in oncreate() in activity
private void networkRequest() {
final String[] resp = new String[1];
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
resp[0] = AttemptingUploadCheckList.getJsonObj(url);
JSONObject response = new JSONObject(resp[0]);
if (response != null) {
version_code = response.getInt("version_code");
recommended_update = response.getBoolean("recommended_update");
forced_update = response.getBoolean("forced_update");
}
if (recommended_update) {
recomendUpadate();
} else if (forced_update)
onUpdateNeeded(url);
else {
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Thread is not bound with the activity. It's not running with the main thread.
Android said if you want to perform any long running tasks like api call, data from database then you need to use the AsyncTask or the Service.
In your case, you can use the AsycnTask for the fetching data.
class MyAsync extends AsyncTask<Void, Void, Void>{
final String[] resp = new String[1];
JSONObject response;
#Override
protected void onPreExecute() {
super.onPreExecute();
// Show Progress Dialog
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// Hide Progress Dialog
if (response != null) {
version_code = response.getInt("version_code");
recommended_update = response.getBoolean("recommended_update");
forced_update = response.getBoolean("forced_update");
}
if (recommended_update) {
recomendUpadate();
} else if (forced_update)
onUpdateNeeded(url);
else {
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}
#Override
protected Void doInBackground(Void... voids) {
try {
resp[0] = AttemptingUploadCheckList.getJsonObj(url);
response = new JSONObject(resp[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
For executing the above AsynTask
private void networkRequest() {
new MyAsync().execute();
}
Thread does not care about Activity or any other Component's lifecycle Except the Process in which it is Running.
You need to check for state of component yourself.
I can provide some example code but i really do not understand what exactly you are trying to do .
Considering you are making a network request there. Java thread individually is hard to handle in such cases considering the fact that after response we need to move on to Main thread to update the UI. So i highly recommend you should use a Network API Library probably RetroFit .
You can check state of the Component like isFinishing() in Activity .

How to load new values of JSON after every 10 seconds

Hi people I am getting problem in getting my latest JSON value after every 10 seconds. I have developed this code and now I am stucked in this. When I run this code it shows the value after second and did not get updated the second time. I have implemented the handler but it is also not working here.
public class MainActivity extends AppCompatActivity {
TextView a,b,c,d,e,f,g,h;
String result = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
a=(TextView) findViewById(R.id.a);
b=(TextView) findViewById(R.id.b);
c=(TextView) findViewById(R.id.c);
DownloadTask task = new DownloadTask();
task.execute("https://api.thingspeak.com/channels/12345/feeds.json?results=1");
}
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(final String result) {
super.onPostExecute(result);
new Handler().postDelayed(new Runnable() {
public void run() {
search(result);
}
}, 10000);
}
public void search(String result){
try {
JSONObject jsonObject = new JSONObject(result);
JSONArray weatherInfo = jsonObject.getJSONArray("feeds");
JSONObject legsobject = weatherInfo.getJSONObject(0);
a.setText(legsobject.getString("field1"));
b.setText(legsobject.getString("field2"));
c.setText(legsobject.getString("field3"));
}catch (JSONException e) {
e.printStackTrace();
}
}
}
}
I want to get my value refreshed after every 10 seconds and it is not doing it.
Can any one guide me that how can I make it possible.
Try this code ..
private final int INTERVAL_MILLI = 60000; // define your time..
Handler mHandler;
#Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(SyncData);
}
Runnable SyncData = new Runnable() {
#Override
public void run() {
// call your code here..
Log.e(TAG, "SyncData1: " + new java.sql.Date(System.currentTimeMillis()).toString());
final String Token = AppSetting.getStringSharedPref(mContext, Constants.USER_KEY_TOKEN, "");
if (!TextUtils.isEmpty(Token) && !CommonUtils.isServiceRunning(mContext)) {
Log.e(TAG, "SyncData2: " + new java.sql.Date(System.currentTimeMillis()).toString());
startService(new Intent(mContext, SyncService.class));
}
callSyncData();
}
};
public void callSyncData()
{
mHandler.postDelayed(SyncData, INTERVAL_MILLI);
}
and callSyncData() method called in activity onCreate method and run method.
To begin with, I don't like the idea of hammering the server with a request every 10s even nothing changes really. If you can move to a solution with notification from the server it will be better.
If you still need to do that you can use three common solutions to fire a repeating task with a period:
1- Use Timer & TimerTask
For this solution you need to declare your timer task to run:
final TimerTask repeatedTask = new TimerTask() {
#Override
public void run() {
//you stuff here
}
};
Then you need to schedule your task using a timer like below:
final Timer timer = new Timer();
timer.scheduleAtFixedRate(repeatedTask,0, 10 * 1000);
==> Don't forget to call timer.cancel(); when your are done (or activity pause, stop, ...)
2- Use ScheduledThreadPoolExecutor
This is basically a replacing for Timer task starting android 5.0. The setup is more easy and straightforward like below:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
//you stuff here
}
}, 0, 10, TimeUnit.SECONDS);
==> don't forget to shutdown your executor when you are done by calling : executor.shutdown();
3- Use Handler
The tip here is to repost the runnable after downloading your json like mentionned in the previous answer.
You can use TimerTask and Timer. If you need to update UI components you should run it on UI thread.
final TimerTask yourRepeatedTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
//your code here
}
});
}
};
And the Timer which schedules your task in a given interval. In your case, it is 10s. Make sure to give the interval in milliseconds.
final Timer timer = new Timer();
timer.scheduleAtFixedRate(yourRepeatedTask ,0, 10 * 1000);
At last call timer.cancel() to stop the timer.
#Override
protected void onPause() {
if (timer != null) {
timer.cancel();
}
super.onPause();
}

Android Create an activity with no buttons

I am very confused as to why I cannot get this to work. I want to have a screen with no buttons run for 5 seconds while I do some things in the background, then navigate back to another screen. Is this not possible?
I have tried to put the code to run the background items in onCreate, onStart, and onResume, and all of these methods are fired before the screen actually displays. Is there another way to do this?
Edit The most recent version of my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sync);
}
protected void onResume(){
super.onResume();
commitSync();
}
private void commitSync(){
TextView monthDayYear = (TextView)findViewById(R.id.month_day_year);
TextView hourMinuteSecond = (TextView)findViewById(R.id.hour_minute_second);
_application = (App)getApplicationContext();
try {
CountDownLatch latch = new CountDownLatch(1);
latch.await(5, TimeUnit.SECONDS);
//Ensure that we have flash
if(getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
Camera androidCamera = Camera.open();
Camera.Parameters p = androidCamera.getParameters();
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
androidCamera.setParameters(p);
//Flash and then turn off
androidCamera.startPreview();
latch.await(50, TimeUnit.MILLISECONDS);
androidCamera.stopPreview();
//Flash screen white
//Get date and time
Module syncModule = _application.getModule();
syncModule.start();
Calendar syncTime = syncModule.getDateAndTime();
//http://stackoverflow.com/questions/21988004/get-time-in-hhmmss-from-seconds-in-java
monthDayYear.setText(new SimpleDateFormat("MM/dd/yyyy").format(syncTime.getTime()));
hourMinuteSecond.setText(new SimpleDateFormat("HH:mm:ss:00").format(syncTime.getTime()));
//Navigate back to MainActivity
Intent mainActivityIntent = new Intent(SyncActivity.this, MainActivity.class);
startActivityForResult(mainActivityIntent, 1);
} else {
throw new Exception("Cannot access Android Flash");
}
} catch (Exception ex) {
Util.appendLog("Exception occured in Sync: " + ex.getMessage());
}
}
Maybe this help you:
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run() {
// Do some work like:
finish();
}
}, 500);
This run a code after some delay and you can put this code in your desired screen.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//The code you want to execute
}
}, timeUntilExecution);
This code should execute that run() method after the timeUntilExecution variable (in milliseconds) you could use this to execute what you want to do after the delay. Hope this helps.

Update UI from running thread

I want to write a download manager app, in the activity I add a progress bar which show the current progress to the user, now if user touch the back button and re-open the activity again this ProgressBar won't be updated.
To avoid from this problem I create a single thread with unique name for each download that keep progress runnable and check if that thread is running in onResume function, if it is then clone it to the current thread and re-run the new thread again but it won't update my UI either, Any ideas !?
#Override
public void onResume()
{
super.onResume();
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for (int i = 0; i < threadArray.length; i++)
if (threadArray[i].getName().equals(APPLICATION_ID))
{
mBackground = new Thread(threadArray[i]);
mBackground.start();
downloadProgressBar.setVisibility(View.VISIBLE);
Toast.makeText(showcaseActivity.this
, "Find that thread - okay", Toast.LENGTH_LONG).show();
}
}
private void updateProgressBar()
{
Runnable runnable = new updateProgress();
mBackground = new Thread(runnable);
mBackground.setName(APPLICATION_ID);
mBackground.start();
}
private class updateProgress implements Runnable
{
public void run()
{
while (Thread.currentThread() == mBackground)
try
{
Thread.sleep(1000);
Message setMessage = new Message();
setMessage.what = mDownloadReceiver.getProgressPercentage();
mHandler.sendMessage(setMessage);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
catch (Exception e)
{/* Do Nothing */}
}
}
private Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message getMessage)
{
downloadProgressBar.setIndeterminate(false);
downloadProgressBar.setProgress(getMessage.what);
if (getMessage.what == 100)
downloadProgressBar.setVisibility(View.GONE);
}
};
Download button code:
downloadBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
downloadProgressBar.setVisibility(View.VISIBLE);
downloadProgressBar.setIndeterminate(true);
downloadProgressBar.setMax(100);
Intent intent = new Intent(showcaseActivity.this, downloadManagers.class);
intent.putExtra("url", "http://test.com/t.zip");
intent.putExtra("receiver", mDownloadReceiver);
startService(intent);
updateProgressBar();
}
});
I'd strongly recommend reading the Android Developer blog post on Painless Threading. As it states, the easiest way to update your UI from another thread is using Activity.runOnUiThread.

null pointer exception on handler for utility class being called from main class. sockets program Android

I made two classes, the first is Server class that runs a thread to wait for and accept a socket connection from the client.
the second class is the EchoThread class that starts a new thread that gets the text message passed by the socket connection. the reason for this is becase it is requied to do this so I can connect more than one client at a time to the server. so I created this class. It is called in the while(true) loop in the Server class to start a new thread when a connection is made.
the problem is that the logcat for this app is a nullPointer exception for the EchoThread class, at this line:
handler.post(new Runnable() {
why am I getting this error message and what to do about it?
Server class:
public class ServerThread implements Runnable {
public void run() {
try {
if (SERVERIP != null) {
handler.post(new Runnable() {
#Override
public void run() {
serverStatus = "Listening on IP: " + SERVERIP;
}
});
serverSocket = new ServerSocket(SERVERPORT);
while (true) {
// listen for incoming clients
Socket client = serverSocket.accept();
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent();
intent.setAction("com.example.diceRolled");
intent.putExtra("serverStatus","Connected");
sendBroadcast(intent);
}
});
new EchoThread(Server.this, client).start();
} // end while(true) method
} else { // the rest of the code for Server class....
EchoThread class:
public class EchoThread extends Thread {
protected Socket socket;
private String line;
private Handler handler;
private Context context;
private Socket client;
public EchoThread(Context c, Socket clientSocket) {
this.socket = clientSocket;
this.context = c;
}
public void run(){
try {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
while ((line = in.readLine()) != null) {
// Log.d("ServerActivity", line);
handler.post(new Runnable() {
private String receivedCommand;
#Override
public void run() {
receivedCommand = line;
Intent intent = new Intent();
intent.setAction("com.example.diceRolled");
intent.putExtra("serverStatus", line.trim());
context.sendBroadcast(intent);
Toast.makeText(context, "sent message " + receivedCommand, Toast.LENGTH_SHORT).show();
// the rest of the code for EchoThread class....
Your handler stays null, since you make it as a class variable
private Handler handler;
but then you never actually give it anything to hold.
When you come across
handler.post()
An NPE is thrown.
Therefore, you must instantiate handler, or give it a non-null reference to hold.
If you want more info about Handlers and Loopers, this and this may be of value (same links as this SO answer.

Categories

Resources