Whenever user press back button While fetching xml data from web using AsyncTask my app goes to force close state. How can i solve this. Thanks in advance.
public class InboxActivity extends Activity {
public static ExpandableListView mailList;
List<HashMap<String,String>> list;
MailList asyncTaskMailList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inbox_layout);
ConstantValues.footerCurrentActivity=InboxActivity.this;
mailList=(ExpandableListView)findViewById(R.id.expandableListView1);
HomePageActivity.homePageTabHost.getTabWidget().getChildTabViewAt(ConstantValues.CURRENT_POSITION)
.setBackgroundDrawable(getResources().getDrawable(R.drawable.tab_widget_normal));
asyncTaskMailList=new MailList();
asyncTaskMailList.execute();
}
private OnChildClickListener childClickListener=new ExpandableListView.OnChildClickListener() {
public boolean onChildClick(ExpandableListView parent, View v,int groupPosition, int childPosition, long id) {
ConstantValues.STATION_NAME=ConstantValues.inboxStations.get(groupPosition);
ConstantValues.CURRENT_POSITION=1;
startActivity(new Intent(InboxActivity.this, HomePageActivity.class));
return false;
}
};
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_BACK){
this.getParent().onBackPressed();
asyncTaskMailList.cancel(true);
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
protected void onStop() {
super.onStop();
asyncTaskMailList.cancel(true);
}
#Override
protected void onDestroy() {
asyncTaskMailList.cancel(true);
super.onDestroy();
}
class MailList extends AsyncTask<String, String, String>
{
#Override
protected void onPreExecute() {
super.onPreExecute();
NetworkExceptionPopUp.showProgressBar();
}
#Override
protected String doInBackground(String... params) {
list=new ArrayList<HashMap<String,String>>();
WebServerCall.getInboxMail(InboxActivity.this);
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
mailList.setAdapter(new InboxAdapter(InboxActivity.this));
NetworkExceptionPopUp.dismissProgressBar();
mailList.setOnGroupClickListener(null);
mailList.setOnChildClickListener(childClickListener);
mailList.setClickable(true);
}
}
}
Above code is my updated code. This also sometime shows exception. Here, I had used onStop() and OnDestroy() to cancel AsyncTask while other activity comes top.
#Override
protected void onPreExecute() {
super.onPreExecute();
NetworkExceptionPopUp.showProgressBar();
/** add this line to your progressDialog so that diaolg as well your background operation wont stop in intermediate state. */
// pd.setCancelable(false);
}
So now when you will click back button Dialog will not dismiss.
Hope this help for you.
private MailList task;
#Override
public void onCreate(Bundle savedInstanceState) {
...
task = new MailList().execute();
...
}
#Override
public void onBackPressed() {
if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) {
task.cancel(true);
}
...
}
...
Related
I have a progress dialog that shows how many files are left for uploading in my Async Task and the user can dismiss this dialog if he wants to. However I want to have a button that will be able to show again that progress dialog at its current stage and I don't know how to do that since you I can't just create a function in the Async Task and call it from a different activity. Any thoughts?
You can make a singleton class to handle the Async Task progress which holds only one listener (the Activity who wants to listen for the progress of your AsyncTask).
Your Singleton class can be like below:
public class ProgressDialogUtil {
public interface ProgressDialogUtilListener{
void showProgressDialog();
void dismissProgressDialog();
void updateProgressDialog(int value);
void setProgressDialogMessage(String message);
}
private ProgressDialogUtilListener listener;
private static ProgressDialogUtil mInstance;
public static ProgressDialogUtil getInstance() {
if (mInstance == null) {
synchronized (ProgressDialogUtil.class) {
if (mInstance == null) {
mInstance = new ProgressDialogUtil();
}
}
}
return mInstance;
}
public void setListener(ProgressDialogUtilListener listener) {
this.listener = listener;
}
public void showProgressDialog(){
if(listener!=null)
listener.showProgressDialog();
}
public void dismissProgressDialog(){
if(listener!=null)
listener.dismissProgressDialog();
}
public void updateProgressDialog(int value){
setProgressDialogMessage("Files Downloaded: "+ value);
if(listener!=null)
listener.updateProgressDialog(value);
}
public void setProgressDialogMessage(String message){
if(listener!=null)
listener.setProgressDialogMessage(message);
}
}
Then you can use this Singleton class (ProgressDialogUtil) in your AsyncTask like below to inform for any update occurred:
public class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
public final ProgressDialogUtil progressDialogUtil;
public MyAsyncTask(ProgressDialogUtil progressDialogUtil){
this.progressDialogUtil = progressDialogUtil;
}
#MainThread
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialogUtil.setProgressDialogMessage("Start Download files..");
progressDialogUtil.showProgressDialog();
}
#WorkerThread
#Override
protected Boolean doInBackground(Void... params) {
//download your files here in the Background Thread...
//below is a sample loop
for (int i=0; i <= 50; i++) {
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
return true;
}
#MainThread
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressDialogUtil.updateProgressDialog(values[0]);
}
#MainThread
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progressDialogUtil.setProgressDialogMessage("Finished Download!");
progressDialogUtil.dismissProgressDialog();
}
}
Then in your first Activity where you start the AsyncTask you can create a new instance of your Progress Dialog and set a listener ProgressDialogUtilListener to listen for any AsyncTask progress to show/hide/update the Progress Dialog like below:
ProgressDialog pd = new ProgressDialog(this);
ProgressDialogUtil progressDialogUtil = ProgressDialogUtil.getInstance();
progressDialogUtil.setListener(new ProgressDialogUtil.ProgressDialogUtilListener()
{
#Override
public void showProgressDialog() {
if (!pd.isShowing())
pd.show();
}
#Override
public void dismissProgressDialog() {
if (pd.isShowing())
pd.dismiss();
}
#Override
public void updateProgressDialog(int value) {
pd.setProgress(value);
}
#Override
public void setProgressDialogMessage(String message) {
pd.setMessage(message);
}
});
new MyAsyncTask(progressDialogUtil).execute();
Finally when you navigate to a new Activity you can use the same Singleton Instance ProgressDialogUtil and change the listener to the new Activity now all AsyncTask events will be handled to the new Activity and the dialog can be opened/closed via a button through this singleton class like below:
ProgressDialog pd = new ProgressDialog(this);
ProgressDialogUtil progressDialogUtil = ProgressDialogUtil.getInstance();
progressDialogUtil.setListener(new ProgressDialogUtil.ProgressDialogUtilListener()
{
#Override
public void showProgressDialog() {
if (!pd.isShowing())
pd.show();
}
#Override
public void dismissProgressDialog() {
if (pd.isShowing())
pd.dismiss();
}
#Override
public void updateProgressDialog(int value) {
pd.setProgress(value);
}
#Override
public void setProgressDialogMessage(String message) {
pd.setMessage(message);
}
});
//Show Progress Dialog from a Button Click
showButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressDialogUtil.showProgressDialog();
}
});
//Dismiss Progress Dialog from a Button Click
dismissButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressDialogUtil.dismissProgressDialog();
}
});
You can have a Live data in any singleton class like below to share the progress between activities.
object ProgressHelper {
val progress = MutableLiveData<Int>()
}
Then update the progress values from the AsyncTask like below:
override fun onProgressUpdate(vararg values: Int?) {
super.onProgressUpdate(*values)
ProgressHelper.progress.value = 100
}
In your activity you can observe the progress like below:
ProgressHelper.progress.observe(this, Observer {
val progress = it
})
Hello i am trying to implement a log in screen showing a progress dialog and allowing the phone to rotate.
I want to ask what is the best way to do that (IntentService, AsyncTask,Service) and allowing the phone to rotate?
I read a lot answers saying different things using an empty fragment with AsyncTask etc.
You can do something like that in manifest to allow rotation:
<application
android:allowBackup="true"
android:configChanges="orientation|keyboardHidden|screenSize"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name=".activities.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name"/>
Then you can catch the rotation with this snipet inside your activity:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.v(this.getClass().getName(), "onConfigurationChanged()");
}
To do an asynctask with progress dialog, this snipet should give you a ligth:
private ProgressDialog pDialog;
private class MyAsync extends AsyncTask<String, Void, String> {
Activity context;
public MyAsync (Activity context) {
this.context = context;
}
#Override
protected void onPreExecute(){
super.onPreExecute();
pdia = new ProgressDialog(context);
pdia.setMessage("Loading...");
pdia.show();
}
#Override
protected String doInBackground(String... urls) {
...
//do your login scheme
...
//context.methods()
return "ok";
}
#Override
protected void onPostExecute(String result) {
pDialog.dismiss();
if(result!=null && result.equals("ok")){
//login was successfully done
} else {
//login has failed
}
}
}
And to use this asynctask you shoud call:
new MyAsync(this).execute(null, null , null);
By the way this is your activity/fragment.
Try adding this attribute android:configChanges="orientation" to your Activity element in the AndroidManifest.xml file.
show a ProgressDialog in the onPreExecute method of an AsyncTask object and canceling the ProgressDialog in the onPostExecute method. doInBackground method is running When change the orientation.
Refer to http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html for a detailed answer.
Basically, you can use fragment with setRetainInstance set to true inside your LoginActivity so that it doesn't get destroyed when activity is recreated during orientation change.
Sample Code :
public class AsyncFragment extends Fragment {
private LoginTask mTask;
private AsyncTaskListener mListener;
private static final String TAG = "AsyncFragment";
private boolean isTaskRunning = false;
private ProgressDialog mProgressDialog;
FrameLayout mLayout;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mTask = new LoginTask();
mTask.execute();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mLayout = new FrameLayout(getActivity());
mLayout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
if(isTaskRunning) {
mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.show();
}
return mLayout;
}
#Override
public void onDestroyView() {
if(mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
super.onDestroyView();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mListener = (AsyncTaskListener) context;
} catch (ClassCastException e) {
Log.d(TAG, "Class not instance of AsyncTaskListener");
}
}
#Override
public void onDetach() {
mListener = null;
super.onDetach();
}
private class LoginTask extends AsyncTask<Void,Integer,Void> {
#Override
protected Void doInBackground(Void... params) {
if(mListener != null) {
mListener.onBackground();
}
SystemClock.sleep(10000);
return null;
}
#Override
protected void onPreExecute() {
isTaskRunning = true;
mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.show();
if(mListener != null) {
mListener.onPreExecute();
}
super.onPreExecute();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(mListener != null) {
mListener.onPostExecute();
}
isTaskRunning = false;
if(mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if(mListener != null) {
mListener.onProgressUpdate(values[0]);
}
}
#Override
protected void onCancelled() {
super.onCancelled();
if(mListener != null) {
mListener.onCancelled();
}
}
}
//Listener to notify for async task callbacks
public interface AsyncTaskListener{
void onPreExecute();
void onPostExecute();
void onCancelled();
void onBackground();
void onProgressUpdate(int progress);
}
}
LoginActivity
public class MainActivity extends AppCompatActivity implements AsyncFragment.AsyncTaskListener{
private static final String FRAGMENT_TAG = "asyncFragment";
private static final String TAG = "MainActivity";
private AsyncFragment mAsyncFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
mAsyncFragment = (AsyncFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (mAsyncFragment == null) { //fragment was retained during orientation change
mAsyncFragment = new AsyncFragment();
fm.beginTransaction().add(mAsyncFragment, FRAGMENT_TAG).commit();
}
}
#Override
public void onPreExecute() {
Log.d(TAG, "onPreExecute: ");
}
#Override
public void onPostExecute() {
Log.d(TAG, "onPostExecute: ");
}
#Override
public void onCancelled() {
Log.d(TAG, "onCancelled: ");
}
#Override
public void onBackground() {
Log.d(TAG, "onBackground: ");
}
#Override
public void onProgressUpdate(int progress) {
Log.d(TAG, "onProgressUpdate: ");
}
Have you tried this?
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize">
</activity>
This way the activity will not be recreated. but you can detect the screen orientation using onConfigurationChanged()
I have an android project and I want to handle the back button in the fragment when I use the webview. When I use the webView and click on more than one link and then I click on back. It closes the application. How can I make it go to the back page. So far, I have done the followings :
public class NewsFragment extends Fragment {
private ProgressDialog progressDialog;
private WebView myWebView ;
public NewsFragment()
{
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_news, container, false);
myWebView = (WebView) rootView.findViewById(R.id.mwl_Website);
myWebView.setWebViewClient(new WebViewClient());
myWebView.getSettings().setBuiltInZoomControls(true);
myWebView.requestFocusFromTouch();
myWebView.setVerticalScrollBarEnabled(true);
myWebView.setHorizontalScrollBarEnabled(true);
myWebView.setVerticalScrollBarEnabled(true);
myWebView.setHorizontalScrollBarEnabled(true);
myWebView.requestFocusFromTouch();
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setUseWideViewPort(true);
myWebView.getSettings().setLoadWithOverviewMode(true);
myWebView.addJavascriptInterface(new WebAppInterface(getActivity()), "Android");
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.loadUrl(getResources().getString(R.string.WEBSITE));
new LoadViewTask().execute();
rootView.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == android.view.KeyEvent.ACTION_DOWN) {
if ((keyCode == android.view.KeyEvent.KEYCODE_BACK)) {
if(myWebView!=null)
{
if(myWebView.canGoBack())
{
myWebView.goBack();
}
}
}
}
return true;
}
});
return rootView;
}
private class LoadViewTask extends AsyncTask<Void, Integer, Void>
{
//Before running code in separate thread
#Override
protected void onPreExecute()
{
progressDialog = ProgressDialog.show(getActivity(),"Loading...",
"Loading please wait...", false, false);
}
//The code to be executed in a background thread.
#Override
protected Void doInBackground(Void... params)
{
/* This is just a code that delays the thread execution 4 times,
* during 850 milliseconds and updates the current progress. This
* is where the code that is going to be executed on a background
* thread must be placed.
*/
try
{
//Get the current thread's token
synchronized (this)
{
//Initialize an integer (that will act as a counter) to zero
int counter = 0;
//While the counter is smaller than four
while(counter <= 4)
{
//Wait 850 milliseconds
this.wait(1000);
//Increment the counter
counter++;
//Set the current progress.
//This value is going to be passed to the onProgressUpdate() method.
publishProgress(counter*25);
}
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
//Update the progress
#Override
protected void onProgressUpdate(Integer... values)
{
//set the current progress of the progress dialog
progressDialog.setProgress(values[0]);
}
//after executing the code in the thread
#Override
protected void onPostExecute(Void result)
{
//close the progress dialog
progressDialog.dismiss();
}
}
Problem you are facing is that your onBackPressed() is getting called, and you need to override that -
like this -
#Override
public void onBackPressed() {
if(myWebView!=null) {
if (webView.canGoBack()) {
webView.goBack();
}
}
super.onBackPressed();
}
Ref
I have some tabpages and fragments. And these fragments contain a GridView element. My program is going to webservice and reading JSON data, after getting images caching and populating gridviews custom grid.
Now, how can show ProgressDialog only not completed fragments? And how can I dismiss progressDialog GridView populating will complete?
My Fragment OnCreate Method;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_b, container, false);
context = getActivity();
final ProgressDialog dialog = ProgressDialog.show(context, "", "Please wait, Loading Page...", true);
GridView gridView = (GridView) v.findViewById(R.id.gridview);
if (isConnected()) {
try {
new ProgressTask(context).execute();
gridView.setAdapter(new AdapterB(context, WallPaperList));
} catch (NullPointerException e) {
e.printStackTrace();
return v;
}
} else {
Toast.makeText(v.getContext(), "Please check your internet connection..!", Toast.LENGTH_LONG).show();
}
return v;
}
its the short example for showing progress may this help you
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(DownloadImageActivity.this, "Wait", "Downloading...");
}
#Override
protected Bitmap doInBackground(String... params) {
//your downloading code
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(Bitmap bitmap) {
progressDialog.dismiss();
}
}
Check this...........
public interface AsyncTaskListener<Boolean> {
public void onCompletingTask(Boolean result);
}
public class AsyncTaskGetApiKey extends AsyncTask<Void, Void, Boolean>{
ArrayList<AsyncTaskListener<Boolean>> listeners;
public AsyncTaskLoadingInSplash() {
listeners = new ArrayList<AsyncTaskListener<Boolean>>();
}
public void addListener(AsyncTaskListener<Boolean> listener){
listeners.add(listener);
}
public void removeListener(AsyncTaskListener<Boolean> listener){
listeners.remove(listener);
}
#Override
protected Boolean doInBackground(Void... params) {
//do your activities here
return true; // If everything is fine
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
for (AsyncTaskListener<Boolean> listener:listeners) {
listener.onReceivingApiKey(result);
}
}
}
public class MyFagemnt extends Fragment
implements AsyncTaskListener<Boolean>{
AsyncTaskGetApiKey task;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//......
task = new AsyncTaskGetApiKey();
task.addListener(this);
//........
}
#Override
public void onCompletingTask(Boolean result) {
// your asyntask finished
// now close the progress bar
}
}
In AsyncTask, create progress dialog in onPreExecute() and dismiss that progress dialog in onPostExecute().
updated:
add this code in your viewpager activity.
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//You can get Call back to show the progress dialog when swipping.
boolean isLoading = true;//Check if the fragment is still loading or not at given position.
if (isLoading) {
//Show progress dialog.
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
I have a button on 6 different Activities. Clicking on that button does almost the same task with different params depending on the Activity.
This will be done using an AsyncTask and in onPostExecute() the button state will be changed.
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Task().execute("param1", "param2");
}
}
private class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
//change the someButton state
}else{
//show an error message
}
}
Instead of having the same AsyncTask in all the 6 Activities, how can I use a single Asynctask from all the Activities and change the respective view?
You should create Task, with methods onSuccess, onFailure and override them.
public class Task extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
onSuccess(result);
}else{
onFailure(result);
}
}
protected void onSuccess(String result) {};
protected void onFailure(String result) {};
}
and then in activity use it like this:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Task(){
#Override
protected void onSuccess(String result){
// do what you want
}
#Override
protected void onFailure(String result){
// do what you want
}
}.execute("param1", "param2");
}
}
Put your Task in its own file and make it public.
Create a callback interface:
public interface TaskCallback {
public void onSuccess(String result);
public void onFailure(String errorMessage);
}
Give such a callback to your Task:
public class Task extends AsyncTask<String, Void, String> {
private TaskCallback callback;
public Task(TaskCallback callback) {
this.callback = callback;
}
#Override
protected String doInBackground(String... params) {
//background task using params[0], params[1]
return "success" or "error";
}
#Override
protected void onPostExecute(String result) {
if (result == "success") {
callback.onSuccess(result);
} else{
callback.onFailure(errorMessage);
}
}
}
And then implement the callback when creating the Task instance in your activity:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
private TaskCallback callback = new TaskCallback() {
#Override
public void onSuccess(String result) {
//change the someButton state
}
#Override
public void onFailure(String errorMessage) {
//show an error message
}
}
new Task(callback).execute("param1", "param2");
}
}