how to do dynamic loading in android? - android

i have an rss feed that comes via an XML. There are several events that are returned with information about them. The events are returned with tags...for eg: ....info...
as soon as i encounter tag, i want to update the listview that i am using to show the events.
So the user does not see the loading progress dialog, rather he sees the events getting added to a list.
How do i do this.
thank you in advance.

Here's pseudo codeish example for one way of doing this using SAX parser;
// MyParserThread is assumed to be inner class of Activity here.
private class MyParserThread extends Thread implements MyParserObserver {
private MyParser mParser;
public MyParserThread() {
mParser = new MyParser();
mParser.setObserver(this);
}
public void run() {
try {
// load xml
mParser.parse(xml);
} catch (Exception ex) {
}
}
public void onMyParserEvent(final DataReceivedFromParsing data) {
runOnUiThread(new Runnable() {
public void run() {
// update data to your UI.
}
});
}
public void cancel() {
mParser.cancel();
}
}
And in your parser you're implementing ContentHandler
public void cancel() {
mCancelled = true;
}
public void startElement(....) {
if (mCancelled) {
// If you want to stop Thread from running, all you have to do
// is make parsing stop.
throw new SAXException("Cancelled");
}
....
}
And triggering parsing once your onCreate is called would be;
public void onCreate(...) {
...
mParserThread = new MyParserThread();
mParserThread.start();
...
}
Now this isn't perfect but hopefully gives some idea how to do Thread handling for this purpose. Fundamentally you just have start it, and adding 'cancel' functionality is somewhat more of a bonus - e.g. for cases in which Activity is destroyed while your Thread is running.

Related

How can I force a blocking redraw of a UI element?

I have a simple login page where the user enters a password, and that password is used to decrypt some data and create the main activity. The process of generating the key, calling the database and creating the main activity takes about 5 seconds so I want to show a progress wheel on the login screen immediately after the user clicks the login button.
Unfortunately since android handles UI refreshes in a non-blocking way the progress bar won't appear before the login function runs. I can't seem to find a way to force a blocking UI refresh for a view in Android. invalidate() and postInvalidate() both won't work since these simply notify Android that a redraw should happen at some point in the future.
Here is some sample code to explain what I'm trying to accomplish:
try {
progressBar.setVisibility(View.VISIBLE);
passwordEditText.setEnabled(false);
Key key = doLogin(passwordEditText.getText()); // Long operation
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.putExtra("Key", key);
startActivity(intent);
getActivity().finish();
} catch (Exception e) {
passwordEditText.setError(getString(R.string.login_error));
Log.e("Login", e.getMessage());
} finally {
progressBar.setVisibility(View.INVISIBLE);
passwordEditText.setEnabled(true);
}
If it's not possible to override the default behaviour and force an immediate blocking redraw, then how best can I best implement a progress wheel while the doLogin() method runs?
I can't seem to find a way to force a blocking UI refresh for a view in Android
Correct. That is not how the Android view system works.
then how best can I best implement a progress wheel while the doLogin() method runs?
Have doLogin() be performed on a background thread. Update the UI on the main application thread when the background work finishes. Take into account that your UI may no longer exist (e.g., user pressed BACK) or may be replaced (e.g., user rotated the device or otherwise triggered a configuration change) while that background work is going on.
In modern Android app development, the three main approaches for doing this are to use a ViewModel and LiveData along with:
RxJava
Coroutines (for app development in Kotlin)
Your own background thread
Fixed the issue. Here's my solution. It may be a little overdone, but I tried to make it easily expandable so it can be applied to other similar scenarios.
AsyncTask for login:
static class LoginTask extends AsyncTask<String, Void, LoginTask.LoginTaskResultBundle> {
private TaskActions mActions;
LoginTask(#NonNull TaskActions actions) {
this.mActions = actions;
}
#Override
protected void onPreExecute() {
mActions.onPreAction();
}
#Override
protected LoginTaskResultBundle doInBackground(String... args) {
try {
Key key = doLogin();
return new LoginTaskResultBundle(LoginTaskResultBundle.SUCCEEDED, key);
} catch (Exception e) {
return new LoginTaskResultBundle(LoginTaskResultBundle.FAILED, e);
}
}
#Override
protected void onPostExecute(LoginTaskResultBundle result) {
if (result.getStatus() == LoginTaskResultBundle.SUCCEEDED)
mActions.onPostSuccess(result);
else
mActions.onPostFailure(result);
}
// Result Bundle
class LoginTaskResultBundle {
static final int FAILED = 0;
static final int SUCCEEDED = 1;
private int mStatus;
private Exception mException;
private Key mKey;
LoginTaskResultBundle(int status, Key key) {
mStatus = status;
mKey = key;
mException = null;
}
LoginTaskResultBundle(int status, Exception exception) {
mStatus = status;
mException = exception;
}
int getStatus() {
return mStatus;
}
Exception getException() {
return mException;
}
Key getKey() {
return mKey;
}
}
// Interface
interface TaskActions {
void onPreAction();
void onPostSuccess(LoginTaskResultBundle bundle);
void onPostFailure(LoginTaskResultBundle bundle);
}
}
Sample call to the LoginAsyncTask:
new LoginTask(
new LoginTask.TaskActions() {
#Override
public void onPreAction() {
showProgressBar();
}
#Override
public void onPostSuccess(LoginTask.LoginTaskResultBundle bundle) {
launchMainActivity();
}
#Override
public void onPostFailure(LoginTask.LoginTaskResultBundle bundle) {
hideProgressBar();
passwordEditText.setError(bundle.getException().getMessage());
Log.e("Login", bundle.getException().getMessage());
}
} )
.execute(passwordEditText.getText().toString());

Android AsynchTask in Linear Layout - Method must be called from UI Thread

I'm using AsynchTask in my app to save a record to a server.
The method that I use in my doInBackground doesn't do anything at all with the UI but I'm getting the following error
Method tryThis must be called from the UI thread, currently inferred thread is worker
Like I said nothing was happening that involved the UI. So I've stripped back my code to try to identify the problem and it is now pretty much bare.. see below
You will notice that rather than the AsynchTask code being in an extension of Activity it is in an extension of LinearLayout as I am using this is for a custom view. I strongly suspect that this is where the root of the problem lies but I don't understand why and nor do I know how to get around it.
public class ExerciseView extends LinearLayout {
public ExerciseView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private class saveRecordTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
String returnString = "";
try {
returnString = tryThis();
//
} catch (Exception e) {
e.printStackTrace();
}
return returnString;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
//startProgress();
}
#Override
protected void onProgressUpdate(String... text) {
// Things to be done while execution of long running operation is in
// progress. For example updating ProgessDialog
}
}
public String tryThis() {
String hi = "hi";
return hi;
}
}
I guess I could use an interface in the custom view to give the data to the Activity at the right time and then do the AsynchTask in the Activity but I'd really like to keep everything together in the custom view to minimise the amount of code that needs to written each time I use it.
Try this. It would help.
If you want to call tryThis() inside UI thread call it as following
runOnUiThread(new Runnable() {
#Override
public void run() {
tryThis();
}
});

How can i know when the async task has returned

I have an async task that loads image urls from server.After loading urls than i load the images one by one through another asynctask.
On the click of a button i start the first asynctask
public void getit(View v)
{
new getdata().execute("http://10.0.2.2/geturls.php");
// line no 2
}
After i get the urls i use another async task to load images.
How can i find out when the image urls have been loaded and i can call the second async task at line no 2.
if i use a boolean variable which i toggle in the onpostexecute
#Override
protected void onPostExecute() {
urlgot=true;
}
then i shall have to use some repeating loop inside getit method at line no 2 to check the status of this variable urlgot. but it may take more time than allowed for ui thread.
Can there be a more cleaner method to do this check.
thanks
There are two solutions I can think of:
1) You create one AsyncTask that does everything (getting the urls, and downloading all images). Than you know exactly when to start downloading the images.
2) You start the next AsyncTask from the onPostExecute() of the first AsyncTask.
You won't be able to do your next piece of work in //line no 2 without defeating the purpose of AsyncTask. If you're doing network activity, you need to be doing it asynchronously, so that's not an option.
Instead, in onPostExecute() you can call another method in your activity that does what you would have done in //line no 2. This is safe to do, because onPostExecute() happens on the UI thread.
But depending on your design, it might make more sense to do all the //line no 2 stuff in your original AysncTask in onPostExecute, so you only have one task doing all of the work.
Use a Handler. In the method onPostExecute of your AsyncTask you can send a message informing the Handler to start another AsyncTask.
Something like this:
#Override
protected void onPostExecute(Void res) {
MyHandlerHandler handler = new MyHandlerHandler();
Message msg = new Message();
msg.what = MyHandler.TASK_FINISHED;
handler.sendMessage(msg);
}
And in your Handler class:
public class MyHandlerHandler extends Handler {
public static final int TASK_FINISHED = 2;
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TASK_FINISHED:
new MyAsyncTask().execute();
break;
}
}
}
instead of putting line 2 in getIt, put it in onPostExecute like below :
public void getit(View v)
{
new getdata().execute("http://10.0.2.2/geturls.php");
}
#Override
protected void onPostExecute() {
// line 2
}
I use a custom interface to do stuff after execution.
public Interface OnDataReceived
{
public void onReceive( Object result);
}
and on MyASyncTask
public class MyAsyncTask extends ASyncTask<Object,Object,Object>
{
OnDataReceived receiver;
public MyAsyncTask( OnDataReceived receiver )
{
this.receiver = receiver;
}
...
protected void onPostExecute( Object result)
{
receiver.onreceive( result );
}
}
and let my main class implement OnDataReceived
public class Main implements OnDataReceived
{
....
public void getit(View v)
{
new MyAsyncTask(this).execute("http://10.0.2.2/geturls.php");
}
#override
public void onReceive( Object result)
{
// do whatever
}
}
EDIT
Even for more control you can add onFailed and rename your interface to OnResponse
public Interface OnResponse
{
public void onReceive( Object result);
public void onFailed( Object errcode);
}

Why thread terminates before loading all the data?

I am using Thread for loading library (Native code ) have to call some functions from the android code to the native code. it's working fine after some time thread terminating, so those functions are not calling properly. present i am using this code for thread creation.
class aThread extends Thread {
public static boolean finished;
public void run() {
if ( a_app.initApp() != 0) {
return;
} else {
}
a_app.startPjsua(ApjsuaActivity.CFG_FNAME);
finished = true;
a_app.deinitApp();
}
}
Is it correct process or not.?
Can i use any service for solving this problem, if yes how to create communication between activity and Service.
My requirement is i have to call a function in the background continuous upto app closes fully.? what is the best way to do like this.
Are you looking for something like this?
boolean ok;
onCreate(Bundle a)
{
...
ok=true;
new aThread().start();
}
class aThread extends Thread {
public static boolean finished;
public void run() {
while(ok==true)
{
if ( a_app.initApp() != 0) {
ok=false;
} else {
a_app.startPjsua(ApjsuaActivity.CFG_FNAME);
finished = true;
a_app.deinitApp();
}
//If you want to execute after some interval..
//Thread.sleep(time_in_milliseconds);
}
}
}
This way it will run as long as ok=true. When you exit the app or if you want to stop the thread; set the value of ok=false.

How to run queries in the background

I have listed of products with different category. I have to sort them. Because of the queries, It is taking more time to load. Between two activities, the screen is coming black. I want to run the query in the background. How can I do that and how to use its result in main activity?
private class InsertTask extends AsyncTask {
String cat;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(String... params) {
Boolean success = false;
try {
category(cat);
success = true;
} catch (Exception e) {
if(e.getMessage()!=null)
e.printStackTrace();
}
return success;
}
#Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
}
private void category(String category) {
try{
Cursor1 = mDbHelper.fetchcategory(category);
}catch(Exception e){
Log.v("Excep", ""+e);
}
}
And when called
InsertTask task = new InsertTask();
task.execute();
I have listed the category in buttons. How can I get the values then?
You should use AsyncTask for that. And some more info.
Its good you have thought of AsyncTask. Firstly, you can declare this class as inner in you class activity (if you haven't previously did) and so you are able to access you view class members.
You can do this also by creating thread and one handler that will be used to update your UI components. Remember that if you use threads you'll need to lock/unlock your database object because of the thread safety(if any other thread is accessing the database for any reason). Read more about thread safety of dbs.
I was doing some searching myself, and I came across this read, its rather long but looks extremely helpful, with lots of code examples. (I bookmarked it for myself).
Threads, Async, and Handlers O MY!
But some form of threading is the ticket.
From Android dev.
(My favorite code snippet)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
//Do Work here
}
}).start();
}

Categories

Resources