I have a splash screen Activity appear for 10 second while waiting this time the Activity check if tables are created and all data are loaded form server
if not it creates tables and load data to DB. every thing is OK but the problem is when loading data take more than 10 seconds the Splash Activity is finished and start another Activity
how i can keep splash activity wait until all data are loaded
here is my code
if(! (checkTables()&&checkData())){
progressDialog.show();
fillSamples();
fillExams();
fillQuestions();
fillSubQuestions();
createProfile();
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
Intent studentAccess = new Intent(SplashScreen.this,Samples.class);
startActivity(studentAccess);
finish();
}
},10000);
i am using volley StringRequest and ImageRequest to download data and images from remote server
You can use AsyncTask ,it is better for network calls by creating this inner class
private class Operation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//do what ever operations you want
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return "result";
}
#Override
protected void onPostExecute(String result) {
Intent i = new Intent(SplashScreen.this, MainActivity.class);
i.putExtra("data", result);
startActivity(i);
finish();
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
and execute the process using private method in splash activity like this
new Operation().execute("");
Network calls should be always called from not main thread.
What you do is that you are making your main thread sleep . Never sleep you main thread. Android will kill your app. Use AsyncTask for network calls (doInBackground) and onPostExectute() do all other things.
Related
I'm trying to check existence of 2000 files in Asynctask.
In the initial execution, it works well.
But if I restart app about 10 times , loading speed slows down.
As I am a beginner developer, I lack understanding of Asynctask.
Please give me some advices.
This is my splash activity
public class SplashActivity extends AppCompatActivity {
getFirstData gfd;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
gfd = new getFirstData(this, (TextView) findViewById(R.id.textView18));
gfd.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, this);
}
#Override
protected void onDestroy() {
try
{
if (gfd.getStatus() == AsyncTask.Status.RUNNING)
{
gfd.cancel(true);
}
else
{
}
}
catch (Exception e)
{
}
super.onDestroy();
}
}
And this is my asynctask code
public class getFirstData extends AsyncTask<Context,Integer,Void> {
private PowerManager.WakeLock mWakeLock;
private Context context;
private TextView textview;
getFirstData(Context context,TextView tv){
this.context=context;
this.textview=tv;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
PowerManager pm = (PowerManager) this.context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
mWakeLock.acquire();
}
#Override
protected Void doInBackground(Context...contexts) {
Database.addDB();
for (int i = 0; i < Database.db_list.size(); i++) {
File filetemp = Database.getFilename(i, ".pdf", Database.db_list);
if (filetemp.exists()) {
Database.db_list.get(i).isDownloaded = true;
}
publishProgress(Database.db_list.size(),i);
}
return null;
}
#Override
protected void onProgressUpdate(Integer... params) {
super.onProgressUpdate(params);
textview.setText("Load("+params[1]*100/params[0]+"%)");
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Intent intent = new Intent(this.context, MainActivity.class);
this.context.startActivity(intent);
((Activity)this.context).finish();
}
}
AsyncTask cancel method doesn't immediately stop your AsyncTask, instead it'll only 'cancel' after doInBackground completes. (Reference)
Calling this method will result in onCancelled(java.lang.Object) being invoked on the UI thread after doInBackground(java.lang.Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never subsequently invoked, even if cancel returns false, but onPostExecute(Result) has not yet run. To finish the task as early as possible, check isCancelled() periodically from doInBackground(java.lang.Object[]).
If you want your AsyncTask to end as quickly as possible, just make a check every 10 (or whatever value you deem suitable) iterations. Something along the following lines should work.
#Override
protected Void doInBackground(Context...contexts) {
Database.addDB();
for (int i = 0; i < Database.db_list.size(); i++) {
File filetemp = Database.getFilename(i, ".pdf", Database.db_list);
if (filetemp.exists()) {
Database.db_list.get(i).isDownloaded = true;
}
publishProgress(Database.db_list.size(),i);
if (i%10==0 && isCancelled()) {
break;
}
}
return null;
}
I see you actually read the manual! Good work!
While its a good effort, unfortunately, the basic approach really just won't work.
I'm not completely clear on what is making the app slow down. If by "restart" you mean back-arrow and then start from the Desktop, then in is probably because you have many downloads running at once. Note that there is no way to stop your AsyncTask once you start it: cancel doesn't actually do anything, unless you implement it.
Your AsyncTask has all the typical problems with leaking a context (Studio is probably yelling at you about this already: pay attention). There is no reason to believe that the Activity that starts the task is still there when the task completes.
My suggestion is that you separate the state of the app from the Activity that views that state. This approach has lots of names but usually something like ViewModel. The View model is some kind of singleton that only allows users to see the Splash page until its state changes (it has the files downloaded). Then it shows the MainActivity.
Good luck!
I have a .lrc file and I need to go over every line with a CountDownTimer. I have tried using AsyncTask to do so but I get the error:
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
On line new CountDownTimer... I tried doing it with runnable but I still get the same error. My goal is to get it to go over every line in .lrc file which looks like this:
[00:04.15]Help me, it's like the walls are caving in
[00:10.46]Sometimes I feel like giving up
[00:13.63]But I just can't
...
I am not sure how efficient it is to do it the way I am trying to do. I am thinking of going through every line in the doInBackground(). If there is a better way to do it then let me know. But to begin with, why am I getting the EXCEPTION ?
Just to note.. I have simplified the code as much as I could so it would be easier to understand what I am trying to do.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyView myView = new
myView.play();
}
}
public class MyView{
public void play() {
new CustomAsync().execute();
}
}
class CustomAsync extends AsyncTask<Lyric, Void, Void> {
protected Void doInBackground(Lyric... param) {
startLyricCountDownTimer(param);
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
private void startLyricCountDownTimer(Lyric lyric){
new CountDownTimer(30000, 10) { //This is where it throws the error
public void onTick(long millisUntilFinished) {
//Do the thing
}
public void onFinish() {
}
}.start();
}
}
EDIT
Is it better to go with the AsyncTask and do like Son Truong suggested or to use the following code for each and every lrc line?
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
new CountDownTimer(millisInFuture,countDownInterval) {
#Override
public void onTick(
CountDownTimer uses a Handler to post messages to a Message Queue of a Thread which has a Looper. onTick and onFinish will be called on which thread based on where you create CountDownTimer instance.
In your case because you create CountDownTimer instance in doInBackground method of AsyncTask so these two methods will be call on AsyncTask thread.
In constructor of CountDownTimer, it will create Handler instance as well. The Handler will check whether or not current thread has a Looper, if not it will throw a RuntimeException with message.
Can't create handler inside thread that has not called
Looper.prepare()
Because AsyncTask uses a thread which has no Looper, that why your app crashes.
My suggestion is in doInBackground method you open a connection to .lrc file and read each line, for each line read, use runOnUIThread to send the line to UI thread (then you can process the line read there by display a Toast on screen, etc).
Update: I will demo how to read line by line from a file then display it on a text view each 3 seconds.
First write a class which read from an inputstream line by line
static class ReadLyricTask extends AsyncTask<InputStream, String, Void> {
WeakReference<MainActivity> mMainActivity;
ReadLyricTask(MainActivity activity) {
mMainActivity = new WeakReference<>(activity);
}
#Override
protected Void doInBackground(InputStream... inputStreams) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStreams[0]));
String line;
try {
while ((line = reader.readLine()) != null) {
publishProgress(line);
}
} catch (IOException e) {
// Do nothing.
} finally {
try {
inputStreams[0].close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
MainActivity activity = mMainActivity.get();
if (activity != null) {
activity.displayLyricLineOnTextView(values[0]);
}
}
}
Then just use it in MainActivity
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_LYRIC_TEXT_INTERVAL = 3000; // Change lyric text each 3 seconds.
private int mCurrentInterval = 0;
private TextView mLyricTextView;
private Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLyricTextView = findViewById(R.id.lyricText);
// I put a file named lyric.lrc in raw folder, for your case just open an input stream from a file.
InputStream inputStream = getResources().openRawResource(R.raw.lyric);
new ReadLyricTask(this).execute(inputStream);
}
private void displayLyricLineOnTextView(final String lyricLine) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mLyricTextView.setText(lyricLine);
}
}, mCurrentInterval);
mCurrentInterval += UPDATE_LYRIC_TEXT_INTERVAL;
}
}
CountDownTimer runs in separate thread and no need of asynctask to run a timer.Best solution would be create a service and make service to trigger a timer.
As timer run on non ui thread, while updating ui make sure you update from UI thread.You could use UI handler or runOnUithread method to update view.
I am quite new to Android/Java, and my first app is using MetaIO SDK.
I am trying to implement "Loading" progress bar, while app (MetaIO SDK) is loading.
Overlay background is shown
Loading dialog is appeared and "loading image" starts spinning
Overlay background disappears and loading image stops spinning <- the problem
After 2-3 seconds it unfreezes and ARELViewActivity is executed.
The code:
public void onScanButtonClick(View v)
{
new ScanLoadingDialog().execute(0);
}
private class ScanLoadingDialog extends AsyncTask<Integer, Integer, Boolean>
{
//Before running code in separate thread
#Override
protected void onPreExecute()
{
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Loading");
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(false);
progressDialog.show();
}
#Override
protected Boolean doInBackground(Integer... params)
{
try
{
synchronized (this) {
AssetsManager.extractAllAssets(getApplicationContext(), true);
startActivity( new Intent(getApplicationContext(), ARELViewActivity.class));
}
}
catch (IOException e)
{
MetaioDebug.log(Log.ERROR, "Error extracting assets: "+e.getMessage());
MetaioDebug.printStackTrace(Log.ERROR, e);
return false;
}
return true;
}
#Override
protected void onPostExecute(Boolean result)
{
progressDialog.dismiss();
finish();
}
}
Am I doing something wrong?
P.S. Full source code can be found here: link text
P.S.S. Related to this question, but I am using technique suggested there, and it still doesn't want to work
I had a similar problem and i solved it by running the UI handling code on the UI thread like so
runOnUiThread(new Runnable() {
#Override
public void run() {
if (imgvExampleOverlay != null)
imgvExampleOverlay.setVisibility(View.VISIBLE);
}
});
imgvExampleOverlay is an image like the one the user has to capture.
Hope this helps
I have a thread that needs to be receiving data all the time from the network and I want this data to be displayed to an EditText object.
Obviously, I can't access the UI EditText from within my receiving thread; what I read is that I can use AsyncTask but reading the example in Painless Threading it seems to me that I have to be done with receiving the data before I can be able to post the results to the UI component.
I can't use post or postDelayed as both will be run over the UI thread and I can't block the UI to receive the data; I need to keep receiving the data all the time.
What other options do I have?
Use LocalBroadcastManager, your Activity containing TextView will start listening for broadcast:
public class MyActivity extends Activity {
private TextView mTextView;
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getStringExtra("actionType");
if(action.equals("updateTextView")){
mTextView.setText("whatever you want to set");
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Start listening, you can put it on onResume too
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter(MyActivity.class.getSimpleName()));
mTextView = (TextView) findViewById(R.id.something);
}
}
So whenever your Thread receive something that needs to update the screen, call this:
Intent intent = new Intent(MyActivity.class.getSimpleName());
intent.putExtra("actionType", "updateTextView");
// Once this is called, your broadcast receiver in MyActivity should receive it and start processing
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Also remember to unregister it in onDestroy or onPause.
*side note: you need to import android support v4 library, and you can pass simple String or object over by intent using Intent.putExtra("","") and Inteng.getExtra("");
Another way is to implement a data listener interface.
public interface DataListener{
void onUpdateData(MyData data);
}
You activities that contain the UI components that need to be updated will implement this interface. It will specify what need to do with updated data.
You may want to keep all instances these data listener interface somewhere in your app.
I assume that you have a different thread to handle network sending/receiving actions. On receiving data, you just call:
dataListenerInstance.onUpdateData(data)
Then it will activate the handler that you have implemented in your activity.
In MainActivity call AsyncTask but make #Override method onPostExecute(..)
public class MainActivity extends ActionBarActivity{
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(Utils.isNetworkAvailable(this)) {
DownloadFileFromURL downloader = new DownloadFileFromURL(){
#Override
protected void onPostExecute(Integer file_content) {
onCompleteLoad();
}
};
downloader.execute(new String[]{file_url, fileName});
...
onCompleteLoad(); - will be call in UI thread of MainActivity. You don't need even implements Interface!
Secon way more suitable for server solutions, but can also be used on the client it is Callable
public class DoGetSize implements Callable<Integer> {
private final String file_url;
private int lenghtOfFile = -1;
public DoGetSize(String file_url) {
this.file_url = file_url;
}
public Integer call() {
try {
URL url = new URL(file_url);
URLConnection connection = url.openConnection();
connection.connect();
lenghtOfFile = connection.getContentLength();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return lenghtOfFile;
}
}
And call this like:
FutureTask<Integer> task = new FutureTask(new DoGetSize(file_url));
ExecutorService es = Executors.newSingleThreadExecutor();
es.submit (task);
try {
Integer result = task.get();
File file = new File(fileName);
if(file.length() != result.intValue()) {
// Do something
...
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
You can send and receive any object in such a way
Full example see on github: https://github.com/app-z/OffLineShop/blob/master/app/src/main/java/net/appz/offlineshop/offlineshop/MainActivity.java
You can do this using a simple delegation.
class NonUIThread {
private NonUIThreadDelegate delegate; //NonUIThreadDelegate can be an interface or an object that has access to your UI thread like an Activity
public void setDelegate(NonUIThreadDelegate delegate) {
this.delegate = delegate;
}
private void doSomthing() {
//do something and at the end:
delegate.someMethodThatUpdatesThatComponent();
}
}
class TheUIThread implements NonUIThreadDelegate /*assuming you've decided to make NonUIThreadDelegate an interface*/ { // the "delegator"
/*
your code
*/
private void initiateNonUIThread() {
NonUIThread nonUIThread;
/*do whatever needed*/
nonUIThread.setDelegate(this);
nonUIThread.start();
}
public void someMethodThatUpdatesThatComponent() { //will be called by the non ui thread
//update the UI
}
}
It's explained a little better (of course using AsincTask) in here: Simple Delegation Pattern in Android
I am very frustrated as I've been trying to implement a super simple loading wheel while waiting on a network call. I have searched and read dozens of SO questions and I just feel like I must be missing something, unless nobody really does what I'm trying to do. I have tried going down the AsyncTask route, but that's not what I want.
Let me also say that right now my app works perfectly, it's just that the transition from screen to screen appears to hang as it waits on the network. I just want a loading wheel so that in the 1-2 seconds the user knows the app is working and didn't freeze.
Here's what my current network call looks like:
private static String sendDataToServer(String arg1, String arg2)
{
Thread dbThread = new Thread()
{
public void run()
{
// do the call that takes a long time
}
};
dbThread.start();
try {
// I do this so that my program doesn't continue until
// the network call is done and I have received the information
// I need to render my next screen
dbThread.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Now, why can't I just add the ProgressDialog like this? If I do this, the progressDialog never appears.
private static String sendDataToServer(String arg1, String arg2)
{
final ProgressDialog progress = new ProgressDialog(BaseActivity.getInstance());
progress.setIndeterminate(true);
progress.setMessage("Loading...");
progress.show();
Thread dbThread = new Thread()
{
public void run()
{
// do the call that takes a long time
}
};
dbThread.start();
try {
dbThread.join();
progress.dismiss();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
I think I'm stuck because the network call needs to be on a separate thread from the UI thread, yet I don't want to continue in my application because I need the results of that call to continue. But if I do thread.join() I hold up everything. I thought I needed AsyncTask but that went downhill quickly. Here's my question on that if you're curious.
Android's AsyncTask: multiple params, returning values, waiting
How the heck to I just show a loading dialog while this call happens without proceeding through the rest of my application?
EDIT
Here's my AsyncTask attempt.
private class PostToFile extends AsyncTask<PostToFile, Void, Void>{
private String functionName;
private ArrayList<NameValuePair> postKeyValuePairs;
private String result = "";
public PostToFile(String function, ArrayList<NameValuePair> keyValuePairs){
functionName= function;
postKeyValuePairs = keyValuePairs;
}
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(BaseActivity.getInstance(), "Loading", "Please wait...", true, false);
}
#Override
protected Void doInBackground(PostToFile... params) {
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair(FUNCTION_KEYWORD, functionName));
for (int i = 0; i < postKeyValuePairs.size(); i++) {
nameValuePairs.add(postKeyValuePairs.get(i));
}
try{
// ***do the POST magic.***
result = response.toString();
}
catch (Exception e){
// clean up my mess
}
return null;
}
private String getResult(){
return result; // can I use this somehow???
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
}
}
And when I use it:
new PostToPHP(FUNCTION_NAME, postPairings){
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try
{
if (result != null && !result.startsWith("null"))
{
JSONArray jArray = new JSONArray(result);
parseData(jArray);
}
}
catch (JSONException e)
{
Log.e(Constants.LOG_TAG, e.toString());
}
};
}.execute()
The problem is, I have a couple of these calls back to back, and they're each dependent on each other. So the first one starts, and the second one starts immediately after the first one starts, but before the first one is finished. So I get erroneous behavior. How can I start the second call only after the first is completely done?
Maybe this will work, I haven't tested, but you can try:
public class MyTask extends AsyncTask<String, Void, String> {
private int flag;
public MyTask(int flag) {
this.flag = flag;
}
#Override
protected String doInBackground(String... params) {
switch (flag) {
case 1:
return doNetworking1();
break;
case 2:
return doNetworking2();
break;
case 3:
return doNetworking3();
break;
default:
return doNetworking1();
}
}
#Override
protected void onPreExecute() {
//show progress dialog
}
#Override
protected void onPostExecute(String s) {
//hide progress dialog
switch (flag) {
case 1: //do something with result
new MyTask(2).execute();
break;
case 2: //do other stuff
new MyTask(3).execute();
break;
case 3: //do event more stuff
break;
default:
//do something
}
}
}
and usage:
new MyTask(1).execute();
In cases of network connections I would use IntentService instead of AsyncTask.
For example create IntentServices for network connection:
public class NetworkCallIntentService extends IntentService {
public static final String BROADCAST_ACTION = "com.yourpackage:NETWORK_CALL_BROADCAST";
public static final String RESULT = "com.yourpackage:NETWORK_CALL_RESULT";
public NetworkCallIntentService() {
super(NetworkCallIntentService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
// get data from intent if needed
// do the call that takes long time
// send broadcast when done
Intent intent = new Intent(BROADCAST_ACTION);
intent.putExtra(RESULT, "some_result");//and more results
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
Next, start that service from activity, show progress dialog and move code responsible for showing next screen to BroadcastReceiver#onReceive() method:
public class SomeActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//start service
Intent serviceIntent = new Intent(this, NetworkCallIntentService.class);
//put extras into intent if needed
//serviceIntent.putExtra("some_key", "some_string_value");
startService(serviceIntent);
//here just show progress bar/progress dialog
}
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mNetworkCallReceiver,
new IntentFilter(NetworkCallIntentService.BROADCAST_ACTION));
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mNetworkCallReceiver);
}
private BroadcastReceiver mNetworkCallReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//hide progress bar/progress dialog
//here get results from intent extras
String result = intent.getStringExtra(NetworkCallIntentService.RESULT);
//process results and continue program(go to next screen, show error message etc.)
}
}
}
Declare service in manifest file:
<service
android:name="com.yourpackage.DownloadSvtValuesIntentService"
android:exported="false" >
</service>