NetworkOnMainThread Exception android studio [duplicate] - java

This question already has answers here:
How can I fix 'android.os.NetworkOnMainThreadException'?
(66 answers)
Closed 7 years ago.
I am getting NetworkOnMainThreadException while running my code. I have a Fragment where i am showing some ID from the webservices that gets called when i click on a button. Following is my code. I have used Asynctask as mentioned for this purpose but still i keep getting this error.
public class AboutMeFragView extends Fragment implements ObsrvIntModel {
private Button getConfButton;
private UsrDataCtrl m_UsrDataCtrl;
private UsrDataModel m_UsrDataModel;
private boolean m_bResUpdate;
private String retc;
public static AboutMeFragView newInstance() {
AboutMeFragView aboutMeFragment = new AboutMeFragView();
return aboutMeFragment;
}
public AboutMeFragView() {}
//inflate the data on this view from the relevant xml file fragment_about_me.xml
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_about_me, container, false);
getConfButton = (Button) rootView.findViewById(R.id.get_config_button);
getConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Toast.makeText(getActivity(), "Implement methods to get the configuration", Toast.LENGTH_LONG).show();
//call your model to get the data from the server and show it on the UI
enableStrictMode();
new GetCredsTask().execute();
}
});
return rootView;
}
//whenever fragment is associated with our main activity
//following method would get called
//also we make sure here that whatever navigation activity is selected
//our action bar shows up the same activity name
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((CpActivity)activity).onSectionAttached(1);
}
#Override
public void update(boolean result) {
m_bResUpdate = result;
}
public void enableStrictMode()
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
private class GetCredsTask extends AsyncTask<Void, Void, String> {
public GetCredsTask() {
super();
}
#Override
protected String doInBackground(Void... params) {
m_UsrDataModel = new UsrDataModel(AboutMeFragView.this);
m_UsrDataCtrl = new UsrDataCtrl(m_UsrDataModel);
m_UsrDataCtrl.execConfig();
retc = m_UsrDataModel.getM_authid();
if(m_bResUpdate != true) {
retc = "404";
}
Log.d("doInBackground", retc);
return retc;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
Log.d("onPostExecute", retc);
if (m_bResUpdate == true)
Toast.makeText(getActivity(), s, Toast.LENGTH_LONG).show();
else
Toast.makeText(getActivity(), retc, Toast.LENGTH_LONG).show();
super.onPostExecute(s);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
protected void execute() {
doInBackground();
}
}
}
Thanks

You are overriding execute(), which is causing the task to be posted on the main thread instead of executed in the background. The normal implementation posts the execution of the task to a background thread, i.e.
Edit:
public final AsyncTask<Params, Progress, Result> More ...execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}

Related

Multithreading with MVP & violation in Android

I want to convert my project according to MVP structure, & I had done it but it violate the MVP design, as it holds the activity instance in the presenter layer.
So, I just wanted to know how can I convert this project into pure MVP. Here Validation class is recursive and validate many fields & for here it is just for signup, and I had put the Validate method into separate thread.
This is my MVP interface
import android.app.Activity;
public class IMVP_Login {
/**
* View mandatory methods. Available to Presenter
* Presenter -> View
*/
public interface RequiredViewOps {
void showToast(String msg);
}
/**
* Operations offered from Presenter to View
* View -> Presenter
*/
public interface PresenterOps{
void submit(Activity activity);
}
}
This is my presenter with thread and containing the activity instance, which is against the design pattern of MVP, the code is as follows
import android.app.Activity;
import java.lang.ref.WeakReference;
import cp.utility.CustomException;
import cp.utility.Validation;
public class PresenterLogin implements Runnable,IMVP_Login.PresenterOps
{
private WeakReference<IMVP_Login.RequiredViewOps> mView;
// this is against the architectural law of MVP
private WeakReference<Activity> activity;
public PresenterLogin(IMVP_Login.RequiredViewOps mView) {
this.mView = new WeakReference<>(mView);
}
#Override
public void run() {
try
{
Validation.validate(activity.get());
}catch (CustomException e)
{
mView.get().showToast(e.getMessage());
}
}
//how should i do this with MVP PATTERN,as it is holding the activity instance
#Override
public void submit(Activity activity) {
this.activity=new WeakReference<>(activity);
Thread validationThread = new Thread(this,"Validation");
validationThread.start();
}
}
This is my activity,
public class Login extends AppCompatActivity implements View.OnClickListener,IMVP_Login.RequiredViewOps
{
private TextInputEditText edPhone,edCountrycode,edPassword;
private IMVP_Login.PresenterOps presenterLogin;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_signin);
initialize();
}
private void initialize()
{
presenterLogin= new PresenterLogin(this);
Button btSignIn=GeneralFunction.findViewByIdAndCast(this,R.id.btnSignIn);
btSignIn.setOnClickListener(this);
edCountrycode = GeneralFunction.findViewByIdAndCast(this, R.id.etCode);
edPhone = GeneralFunction.findViewByIdAndCast(this, R.id.etPhone);
edPassword = GeneralFunction.findViewByIdAndCast(this, R.id.etPassword);
edPassword.setTypeface(Typekit.getInstance().get(getString(R.string.str_regular)));
edPassword.setTransformationMethod(new PasswordTransformationMethod());
}
#Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.btnSignIn:
presenterLogin.submit(this);
break;
}
}
#Override
public void showToast(String msg) {
//show toast
}
}
This is the validation class depending on tag of editext,
public class Validation {
public static boolean validateFields(final ViewGroup parentView) throws CustomException
{
for (int i = 0; i < parentView.getChildCount(); i++)
{
if (parentView.getChildAt(i) instanceof ViewGroup) {
if ((parentView.getChildAt(i)).getVisibility() == View.VISIBLE)
validateFields((ViewGroup) parentView.getChildAt(i));
}
else if((parentView.getChildAt(i) instanceof TextView) && ((parentView.getChildAt(i)).getVisibility() == View.VISIBLE))
{
TextView editText = (TextView) parentView.getChildAt(i);
if(null!=editText.getTag())
{
String type = editText.getTag().toString().toLowerCase();
String text=GeneralFunction.getTextFromView(editText);
//validation depending on tag
}
}
}
return true;
}
public static boolean validate(Activity activity) {
final ViewGroup viewGroup = (ViewGroup) activity.findViewById(android.R.id.content);
return validateFields(viewGroup);
}
}
Let me start by saying that there are many different ways of doing MVP, each of them valid in their own right. The important things to keep in mind are:
The View should not know about the model, it doesn't care at all where its data is coming from.
The Presenter should not know about Android. You should be able to run your Presenter class entirely on the JVM.
Your Activity/Fragment/ViewGroup should implement the View interface which is how the Presenter communicates with them.
Why do we do this?
Separation of concerns.
You can change the network library you use in your Model and the View/Presenter should just work still. You could switch your View from a horizontal ViewPager to a vertical RecyclerView and the Presenter/Model equally wouldn't care.
Testing.
We can mock our Presenter and unit test the View or Model. Mock the View & Model and unit test the Presenter.
As long as the implementation of MVP that you are using allows the above then in my mind it is valid.
Onto your specific problem. I would set it up something like this:
View:
public interface LoginView {
Map<String,String> getLoginFields();
}
Activity:
public class LoginActivity extends AppCompatActivity implements LoginView {
private EditText emailView;
private EditText phoneView;
private EditText passwordView;
private Button loginView;
private LoginPresenter presenter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
presenter = new LoginPresenter();
presenter.bindView(this);
emailView = findViewById(R.id.login_email);
phoneView = findViewById(R.id.login_phone);
passwordView = findViewById(R.id.login_password);
loginView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
presenter.login();
}
});
}
#Override
protected void onDestroy() {
presenter.unbindView();
super.onDestroy();
}
#Override
public Map<String, String> getLoginFields() {
Map<String, String> fields = new HashMap<>();
fields.put(emailView.getTag().toString(), emailView.getText().toString());
fields.put(phoneView.getTag().toString(), phoneView.getText().toString());
fields.put(passwordView.getTag().toString(), passwordView.getText().toString());
return fields;
}
}
You may wish to do something fancy with the getLoginFields method and loop through your container. Even if you had 100 fields though it shouldn't require offloading onto another thread. I'd be a very upset user if I had to fill out 100 fields...
Presenter:
public class LoginPresenter {
private LoginView view;
private LoginValidator validator;
public void bindView(LoginView view) {
this.view = view;
}
public void unbindView() {
view = null;
}
public void login() {
validator = new LoginValidator();
Map<String, String> fields = view.getLoginFields();
boolean isValid = validator.validate(fields);
}
}
Validator:
public class LoginValidator {
public boolean validate(Map<String, String> fields) {
//validation depending on tag
return true;
}
}
Threading
If the need does arise to process something on another thread in the Activity then you have several approaches you could take:
Pass a listener to the getLoginFields() method which gets called when the work is done.
Expose another method in the Presenter, something like onLoginFieldsProcessed which would get called once the work is done.
Have getLoginFields() return Observable (RxJava) or Future.
I would personally probably use RxJava, especially if I was already using it in the app.
The main reason why there is separate presenter class added in this MVP framework ( especially in android ) is to remove the OutOfMemory or if by chance the activity fails the presenter calls is not affected i.e why there is MVP approach followed instead of MV framework.
Consider the below example that is from below link :-
public class MainActivity extends Activity {
public static final String DEFAULT_NAME = "Chuck Norris";
private ArrayAdapter<ServerAPI.Item> adapter;
private Subscription subscription;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(adapter = new ArrayAdapter<>(this, R.layout.item));
requestItems(DEFAULT_NAME);
}
#Override
protected void onDestroy() {
super.onDestroy();
unsubscribe();
}
public void requestItems(String name) {
unsubscribe();
subscription = App.getServerAPI()
.getItems(name.split("\\s+")[0], name.split("\\s+")[1])
.delay(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<ServerAPI.Response>() {
#Override
public void call(ServerAPI.Response response) {
onItemsNext(response.items);
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable error) {
onItemsError(error);
}
});
}
public void onItemsNext(ServerAPI.Item[] items) {
adapter.clear();
adapter.addAll(items);
}
public void onItemsError(Throwable throwable) {
Toast.makeText(this, throwable.getMessage(), Toast.LENGTH_LONG).show();
}
private void unsubscribe() {
if (subscription != null) {
subscription.unsubscribe();
subscription = null;
}
}
}
In the above example the activity failure causes the presenter layer to stop working .Similarly ,if there is any object associated with this activity class ( View ) will be affected .
Referencing by static will make the activity die out while there is a crash but the presenter class will not be affected.( Please refer to below code for MVP ).
public class MainPresenter {
public static final String DEFAULT_NAME = "Chuck Norris";
private ServerAPI.Item[] items;
private Throwable error;
private MainActivity view;
public MainPresenter() {
App.getServerAPI()
.getItems(DEFAULT_NAME.split("\\s+")[0], DEFAULT_NAME.split("\\s+")[1])
.delay(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<ServerAPI.Response>() {
#Override
public void call(ServerAPI.Response response) {
items = response.items;
publish();
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
error = throwable;
publish();
}
});
}
public void onTakeView(MainActivity view) {
this.view = view;
publish();
}
private void publish() {
if (view != null) {
if (items != null)
view.onItemsNext(items);
else if (error != null)
view.onItemsError(error);
}
}
}
public class MainActivity extends Activity {
private ArrayAdapter<ServerAPI.Item> adapter;
private static MainPresenter presenter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(adapter = new ArrayAdapter<>(this, R.layout.item));
if (presenter == null)
presenter = new MainPresenter();
presenter.onTakeView(this);
}
#Override
protected void onDestroy() {
super.onDestroy();
presenter.onTakeView(null);
if (!isChangingConfigurations())
presenter = null;
}
public void onItemsNext(ServerAPI.Item[] items) {
adapter.clear();
adapter.addAll(items);
}
public void onItemsError(Throwable throwable) {
Toast.makeText(this, throwable.getMessage(), Toast.LENGTH_LONG).show();
}
}
MainActivity creates MainPresenter and keeps it outside of reach of onCreate/onDestroy cycle. MainActivity uses a static variable to reference MainPresenter, so every time a process restarts due to out-of-memory event, MainActivity should check if the presenter is still here and create it if needed.( As stated in the doc ).
Hope this helps :)

How to allow the device rotation while onPostExecute (UI Blocking Task) running

I'm new to android but based on my understanding that onPostExecute has to run on the main UI thread to be able to access Views and so on which blocks the UI until it finishes. But the application looks ugly -as if it's crashing- when I try to rotate the device while onPostExecute is running (I know it should be a light weight task but I keep in mind slow phones so this might actually happen in my HBO)
Now, here's my code and I know I believe I should use interfaces for communication between my Task, Fragment, and Activity but it's just a proof of concept for now.
//MovieTask Class
public class MovieTask extends AsyncTask<Void, Void, String> {
private Activity activity;
public MovieTask(Activity activity) {
onAttach(activity);
}
//should be an interface
public void onAttach(Activity activit) {
this.activity = activit;
}
//should be an interface
public void onDetach() {
this.activity = null;
}
#Override
protected String doInBackground(Void... params) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
Log.e("ASYNC TASK", "DONE");
return "DONE: FROM DO TO POST";
}
#Override
protected void onPostExecute(String s) {
if(this.activity != null)
{
((MainActivity) activity).ShowResult(s);
Log.e("MovieTask", "Result Received");
}else
Log.e("MovieTask", "Activity is null (1)");
}
}
//My Non-UI Fragment to decouple the Task from the Activity
public class NonUIFragment extends Fragment {
private MovieTask myTask;
private Activity activity;
public NonUIFragment() {
// Required empty public constructor
}
public void BeginTask() {
if (activity != null) {
myTask = new MovieTask(activity);
myTask.execute();
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
//check that the passed context is an Activity first then,
if (context instanceof Activity) {
this.activity = (Activity) context;
if(myTask != null) {
myTask.onAttach((Activity) context);
}
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance
setRetainInstance(true);
}
#Override
public void onDetach() {
super.onDetach();
if(myTask != null) {
myTask.onDetach();
}
}
//Main Activity (Task Consumer)
public class MainActivity extends AppCompatActivity {
NonUIFragment nonUIFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
nonUIFragment = new NonUIFragment();
getSupportFragmentManager()
.beginTransaction()
.add(nonUIFragment, "nonUIFragment")
.commit();
}
else
{
nonUIFragment = (NonUIFragment) getSupportFragmentManager().findFragmentByTag("nonUIFragment");
}
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
nonUIFragment.BeginTask();
}
});
}
//should be the consumer interface
public void ShowResult(String result)
{
try {
Thread.sleep(5000);
TextView txtVw = (TextView) findViewById(R.id.txtVw);
txtVw.setText(result);
} catch (InterruptedException e) {
Log.e("MovieTask", "mCallbacks is null (2)");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
TextView txtVw = (TextView) findViewById(R.id.txtVw);
String result = txtVw.getText().toString();
outState.putString("result", result);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String result = savedInstanceState.getString("result");
TextView txtVw = (TextView) findViewById(R.id.txtVw);
txtVw.setText(result);
}
}
UPDATE 1
In the chat Jigs suggested trying 'runOnUiThread', however onPostExecute already runs on the UI Thread so unfortunately it's kind of irrelevant. I guess what I'm trying to do is not block the UI while the behaviour of onPostExecute is a UI-Blocking in nature which makes it kind of impossible. I'll leave the question around in case anybody has different thoughts!

Combine Activity with Fragment

Learning what I can from the internet and youtube, I'm sure I am not handling this in the appropriate way. I have an existing app which includes a slide out navigation drawer using fragments. I am now trying to get an activity to run within that fragment without any luck. It works when ran on it's own, but after trying to combine the two, I am not able to get "draftactivity" to run properly. The fragment operates as it should.
public class tapsfragment extends Fragment {
public static tapsfragment newInstance() {
tapsfragment fragment = new tapsfragment();
return fragment;
}
public tapsfragment(){}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(2);
}
public class DraftActivity extends Activity {
TextView draftfeed;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.draft_activity);
draftfeed = (TextView) findViewById(R.id.draftfeed);
new PostAsync().execute();
}
class PostAsync extends AsyncTask<Void, Void, Void> {
ProgressDialog pd;
XMLHelper helper;
#Override
protected void onPreExecute() {
pd = ProgressDialog.show(DraftActivity.this, "Taps", "Loading posts for ******.com ...", true, false);
}
#Override
protected Void doInBackground(Void... arg0) {
helper = new XMLHelper();
helper.get();
return null;
}
#Override
protected void onPostExecute(Void result) {
StringBuilder builder = new StringBuilder();
for (ItemValue post : helper.posts) {
builder.append("\nPost: " + post.getTitle());
builder.append("\n");
}
draftfeed.setText(builder.toString());
pd.dismiss();
}
}
Activity can't run in a fragment, it's the other way around.

Android Pull To Refresh onFresh method not being called

I am using Johan Nilsson Android Pull to Refresh library in my android application. The problem I am having is that the onRefresh method seems to not being called (since none of my logs are displayed) what is causing this and how do I fix it.
public class MyFragment extends RoboFragment implements ResponseListener<List<TimelineItem>>{
#InjectView (R.id.TwitterList) private PullToRefreshListView listView;
private List<TimelineItem> results;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_timeline, container,false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
listView.setOnRefreshListener(new OnRefreshListener() {
public void onRefresh() {
Log.v("onRefresh", "done");
new FetchNewData().execute("");
}
});
TimelineTask request = new TimelineTask(getActivity());
request.onResponseListener(this);
request.execute(new String());
}
/**
* Callback handler that is called
* after data is fetched from server.
* #author mario
*/
public void onComplete(List<TimelineItem> result)
{
if (result != null && !result.isEmpty())
{
this.results = result;
Collections.sort(results,Collections.reverseOrder());
TimelineAdapter adapter = new TimelineAdapter(getActivity(),R.layout.fragment_timeline_item, results);
listView.setAdapter(adapter);
}
else
Toast.makeText(getActivity(), "No Account! Available Please an Account", Toast.LENGTH_LONG).show();
}//end onComplete method
private class FetchNewData extends AsyncTask<String, Void,List<TimelineItem> >
{
#Override
protected void onPostExecute(List<TimelineItem> result)
{
results.addAll(result);
listView.onRefreshComplete();
Log.v("onPostExecuted", "done");
}
#Override
protected List<TimelineItem> doInBackground(String... params)
{
Log.v("doInBackground", "done");
Collections.sort(results);
return results;
}
}

How to use a ProgressDialog properly with an AsyncTask without causing window leaks?

I have an AsyncTask which shows a ProgressDialog. The AsyncTask is started when the activity is started:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
new MyTask().execute();
}
// ... other code
private class MyTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog dialog = new ProgressDialog(MyActivity.this);
#Override
protected void onPreExecute() {
dialog.show();
}
#Override
protected Void doInBackground(Void... voids) {
// get data from a server
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
// call to a method in MyActivity which updates the UI.
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
}
This code works perfectly, untill I rotate my screen. Which makes sense, because the context that was used to create the dialog doesn't exist anymore (because the activity is re-created when rotating), and a window leak is caused.
The only solution I could think of isn't a really nice one: create a static instance of the task and dialog, and simply dismiss the dialog when the activity is destroyed, and recreate the dialog in the oncreate method if the task is still running.
So how would I solve something like this without losing functionality (so the dialog must always be shown when the task is running, and rotating the device should be allowed)?
As Raghunandan suggested in his comment, I looked into Fragments and solved my problem.
I created a Fragment which starts my AsyncTask, as explained in the blogpost that Raghunandan provided.
And to make sure that my Dialog didn't get leaked, I created a DialogFragment, as described here (Basic Dialog).
Here's my working code:
My Activity:
public class MyActivity extends Activity implements MyTaskFragment.TaskCallbacks {
private MyTaskFragment task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
FragmentManager fm = getFragmentManager();
task = (MyTaskFragment) fm.findFragmentByTag("myTask");
if (task == null) {
task = new MyTaskFragment();
fm.beginTransaction().add(task, "myTask").commit();
}
}
#Override
public void onPreExecute() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("myDialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
StringProgressDialogFragment dialog = StringProgressDialogFragment.newInstance("My message");
dialog.show(ft, "myDialog");
}
#Override
public void onPostExecute() {
StringProgressDialogFragment dialog = (StringProgressDialogFragment) getFragmentManager().findFragmentByTag("myDialog");
if (dialog!=null) {
dialog.dismiss();
}
// update UI
}
// ... other code
}
My Task fragment:
public class MyTaskFragment extends Fragment {
private TaskCallbacks mCallbacks;
private Task mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (TaskCallbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
// Create and execute the background task.
mTask = new Task();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class Task extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
mCallbacks.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
// do stuff
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
mCallbacks.onPostExecute();
}
}
public static interface TaskCallbacks {
void onPreExecute();
void onPostExecute();
}
}
My Dialog fragment:
public class StringProgressDialogFragment extends DialogFragment {
private String message;
public static StringProgressDialogFragment newInstance(String message) {
StringProgressDialogFragment dialog = new StringProgressDialogFragment();
Bundle args = new Bundle();
args.putString("message", message);
dialog.setArguments(args);
return dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
message = getArguments().getString("message");
dialog.setMessage(message);
return dialog;
}
}
New Loaders API can help you (available via support package) - man. They will solve problem with rotation, but not a mem. leak. To solve mem. leaks write your own "AsyncTask" (with a "clearContext" routine) and clear it's context in activity's onDestroy (or onPause, depends on your architecture). It may looks like a bicycle, but the task takes max 1 day, and you will have a full control on all the resources you background worker use.
By the way: consider using dialogs through fragments, because it solves dialog kill on screen rotation.
try with sample. it will work. basically just restrict the oncreate call by handling the config change. this solution may help you.
public class MainActivity extends Activity {
LoadProgrssdata task = new LoadProgrssdata();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "oncreate called", Toast.LENGTH_SHORT).show();
task.execute();
}
public class LoadProgrssdata extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
//declare other objects as per your need
#Override
protected void onPreExecute()
{
progressDialog= ProgressDialog.show(MainActivity.this, "Progress Dialog Title Text","Process Description Text", true);
//do initialization of required objects objects here
};
#Override
protected Void doInBackground(Void... params)
{
//do loading operation here
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
progressDialog.dismiss();
};
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.e("orientation ", "landscape");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Log.e("orientation ", "portrait");
}
}
}
and in android manifest file:
<activity
android:name="com.example.MainActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden|screenSize" />
I managed to fix this problem by trying to catch any crash that, may occurs, in doInBackground.

Categories

Resources