Error when working with the context in fragment - android

everything works. question - well I do? and how can otherwise call contexthow to call this method?
in MyActivity:
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
in my fragment I call the method:
public void setData(){
new MyAsincTask(getActivity()){
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(Document document) {
super.onPostExecute(document);
........
getActivity().setTitle("Сотрудники(city:" + city + ",holiday:" + holiday + ")");
}
}.execute(link);
}
it works. but if during the process to move to another part of the application crashes
but if you add
if (getActivity()!=null)
getActivity().setTitle("Сотрудники(city:" + city + ",holiday:" + holiday + ")");
everything works. question - well I do? and how can otherwise call context
12-24 05:18:28.805 460-460/com.managment.pavel.managmentgradle E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
at com.managment.pavel.managmentgradle.fragments.EmployeessList$1.onPostExecute(EmployeessList.java:114)
at com.managment.pavel.managmentgradle.fragments.EmployeessList$1.onPostExecute(EmployeessList.java:69)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)

The fragment had been detached when you navigated to another part of the app, so getActivity will return null. Since it is not meaningful to change the title of an activity that had been destroyed, it is probably OK to just put the null check in like you did.
However this can become a bigger problem if your async task must call back to the activity. I recommend using an event bus such as Otto to pass data from async task back up to the UI.
Here is my blog post on this topic: Event Bus Usage on Android

Related

onBackPressed to fragment(A, B, C)

I have main activity and three fragment (one, two, three).
And all this fragments extands BaseFragment:
public abstract class BaseFragment extends Fragment {
private Toolbar mToolbar;
private ActionBar mActionBar;
#Override
#CallSuper
public void onAttach(Activity context) {
super.onAttach(context);
mToolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
mActionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
//mActionBar.setTitle(setMyTitle());
//Log.i("BaseFragment", "onAttach = "+getBackStackCount());
resetToolbarNavigation(getBackStackCount()!=0);
}
//protected abstract String setMyTitle();
#Override
#CallSuper
public void onDetach() {
super.onDetach();
Log.i("BaseFragment", "onDetach = " + (getBackStackCount() - 1));
resetToolbarNavigation((getBackStackCount() - 1 )!= 0);
}
private int getBackStackCount() {
int b = getActivity().getSupportFragmentManager().getBackStackEntryCount();
Log.i("BaseFragment", "getBackStackCount = "+b);
return b;
}
private void resetToolbarNavigation(boolean backNavigationEnabled) {
mActionBar.setDisplayHomeAsUpEnabled(backNavigationEnabled);
Log.i("BaseFragment", "resetToolbarNavigation");
if (backNavigationEnabled) {
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("resetToolbarNavigation", "setNavigationOnClickListener");
getActivity().onBackPressed();
}
});
}
else {
((StartPageActivity) getActivity()).initToolbar();
((StartPageActivity) getActivity()).syncState();
}
}
}
But when i click back arrow i got Exeption
09-22 19:28:13.233 5643-5643/com.test.mylist E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
at com.test.exemple.BaseFragment$1.onClick(BaseFragment.java:56)
at android.view.View.performClick(View.java:2485)
at android.view.View$PerformClick.run(View.java:9080)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
onBackPressed inside main activity
#Override
public void onBackPressed() {
getSupportFragmentManager().popBackStack();
Log.d("StartPageActivity", "onBackPressed " + getSupportFragmentManager().getBackStackEntryCount());
}
Can you help me? Where is the error? What am I doing wrong?
Not sure why you're getting that exact exception, but your approach to use the fragment is not so good in the way it's designed and that could bring this type of problems. So here I leave you some advices that has been useful to me when implementing apps with fragments:
Separate responsibilities: Activity should take care of it's stuff and Fragment should only be responsible for Fragment's functionalities. To achieve this you could make your Fragment publish interfaces with the methods you need the Activity implements and then just use it in the Fragment. For example in your code you have strong relations in your fragment form your Activity. Method resetToolbarNavigation is interacting with Views that belong to the Activity, notice that method is not doing nothing that is Fragment responsibility, so that entire method should be implemented in the activity, then you can publish a interface in your BaseFragment for example:
//Get the instance of the activity implementation
private BaseFragmentActions baseFragmentActions;
//Publish your interface with the methods your Activity will implement
public interface BaseFragmentActions {
public void resetToolbarNavigation(boolean backNavigationEnabled);
}
//In your onAttach get the implementation from your activity
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
baseFragmentActions = (BaseFragmentActions)activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement interface BaseFragmentActions");
}
}
Then in your Activity just implement the method and use it in your fragment like baseFragmentActions.resetToolbarNavigation(true); Notice that this way BaseFragment doesn't care about the activity, just ask that the activity that contain it have to implement the methods it needs. To achieve this you can use EventBus too.
The transactions between fragments should be done always in the Activity that contain it. A Fragment should not know/cares about which Fragment should be loaded after.
Use the concept "Activity knows it's Fragments but Fragment don't know it's Activity"
You can do it this way and you can have information of your Activity in your Fragment but that could bring bigs headaches like this one.
Hope it helps you as concept for future design and sorry for my English
Here's what I think is happening based on your comments.
you open to fragment 1 and resetToolbarNavigation(boolean) gets called from onAttach
you navigate to fragment 2 and resetToolbarNavigation(boolean) gets called from onAttach
you navigate to fragment 3 and resetToolbarNavigation(boolean) gets called from onAttach
you click the navigation button and fragment 3 handles it properly popping the backstack and navigating you back to fragment 2
resetToolbarNavigation(boolean) is not called from onAttach on fragment 2 because the fragment/activity wasn't destroyed and the fragment was never detached.
you press the navigation button and it is handled by fragment 3 again which isn't started so getActivity() returns null
You should try setting the on navigation listener when the fragment displayed. If you are performing your fragment transactions correctly, you should be able to do this in onResume().

unable to start activity from onPostexecute() using interface

I need to start another activity from the onPosExecute method of the AsyncTask. The AsyncTask is a seperate class and not in any activity class.
I have used an interface to do so. The codes are:
This is the onPostExecute() method
#Override
protected void onPostExecute(String json) {
Log.v("JSON", json);
Log.v("updateUI",""+updateUI);
updateUI.changeActivity();
}
This is the interface
public interface UpdateUIListener {
public void changeActivity();
}
And this is the part of the activity class where the interface is implemented
#Override
public void changeActivity() {
Intent blah=new Intent(this,SplashActivity.class);
startActivity(blah);
finish();
}
When I run the code, a null pointer exception shows up, at the line
Intent blah=new Intent(this,SplashActivity.class);
My stacktrace is:
java.lang.NullPointerException
at android.content.ContextWrapper.getPackageName(ContextWrapper.java:135)
at android.content.ComponentName.<init>(ComponentName.java:75)
at android.content.Intent.<init>(Intent.java:3546)
at com.autofoyer.SignUpActivity.changeActivity(SignUpActivity.java:79)
at com.autofoyer.common.MyClientTask.onPostExecute(MyClientTask.java:73)
at com.autofoyer.common.MyClientTask.onPostExecute(MyClientTask.java:23)
at android.os.AsyncTask.finish(AsyncTask.java:631)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5099)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:803)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:570)
at dalvik.system.NativeStart.main(Native Method)
I need to know what is causing and How to solve the null point exception. I need to start and activity from the onPostExecute method. Thanks in advance!
You probably instantiate updateUI with new SplashActivity() or similar. You can't do that. Instead you have to pass a Context into your AsyncTask and use that to call startActivity() . You probably start the AsyncTask from some Activity, so just pass that Activity as a Context when instantiating the AsyncTask.

Can't create DialogFragment in onPostResume() - java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

I've got a DialogFragment that I try to create in the overridden onPostResume() method of my Activity, but I get this error message:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
I've read all the answers to similar questions (here, here, here, and the blog here), but none of them worked for me (the onPostResume fix or the Runnable fix), or aren't suitable - I don't want to use commitAllowingStateLoss because it's unsafe, and I don't want to override onSaveInstanceState without calling super().
Edit: I've narrowed down the issue to my use of Eventbus. When I create the dialog fragment directly in the onPostResume method, I don't get any errors. When I call the eventbus event to create the dialog fragment, I get the aforementioned error. I have tried changing the event handler's thread to both:
public void onEvent(DisplayOperatorDialogEvent event)
public void onEventMainThread(DisplayOperatorDialogEvent event)
but it doesn't seem to make a difference.
The code:
#Override
protected void onPostResume()
{
super.onPostResume();
Log.d("MainActivity","in onPostResume");
Intent receivedIntent = getIntent();
String receivedAction = receivedIntent.getAction();//null if started from the menu
try
{
String receivedText;
if(receivedAction!=null && receivedAction.equals("display_dialog"))
{
receivedText = receivedIntent.getStringExtra("dialog");
if(receivedText!=null && receivedText.equals("operator"))
{
String title = "hello";
String msg = "test";
DisplayOperatorDialogEvent dialogEvent = new DisplayOperatorDialogEvent(title, msg);
EventBus.getDefault().post(dialogEvent);
}
}
receivedIntent.setAction("");
receivedIntent.removeExtra("screen");
}
catch(Exception e)
{
Log.e("Error: parse the notification screen intent: ", "" + e);
}
}
public void onEvent(DisplayOperatorDialogEvent event)
{
{
android.support.v4.app.FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
android.support.v4.app.Fragment prev = getSupportFragmentManager().findFragmentByTag("operator");
if (prev != null)
{
ft.remove(prev);
}
ft.addToBackStack(null);
operatorDialog = new OperatorDialogFragment();
Bundle args = new Bundle();
args.putString("title", event.getTitle());
args.putString("message", event.getMsg());
operatorDialog.show(ft,"operator");
}
}
The traceback:
10-05 19:06:43.115 20803-20803/com.unifiapp E/Event﹕ Could not dispatch event: class com.unifiapp.events.Events$DisplayOperatorDialogEvent to subscribing class class com.unifiapp.MainActivity
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1360)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1378)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:155)
at com.unifiapp.MainActivity.onEvent(MainActivity.java:478)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at de.greenrobot.event.EventBus.invokeSubscriber(EventBus.java:569)
at de.greenrobot.event.EventBus.postToSubscription(EventBus.java:500)
at de.greenrobot.event.EventBus.postSingleEvent(EventBus.java:475)
at de.greenrobot.event.EventBus.post(EventBus.java:365)
at com.unifiapp.MainActivity.onPostResume(MainActivity.java:676)
at android.app.Activity.performResume(Activity.java:5323)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2764)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2803)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2238)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
This issue happens on both Android 4.0 and 4.4.

getTargetFragment() returns null -- works in one place but not another

I am having an odd problem. I am implementing the same code in two places (both in ListFragments), but one works and the other throws a NullPointerException.
Here's my code (all part of a subclass of ListFragment):
public static class DeleteDialogFragment extends DialogFragment {
static DeleteDialogFragment newInstance(int arg) {
return new DeleteDialogFragment();
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.confirm_delete)
.setMessage(R.string.teacher_confirm_delete_message)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
((TeachersFragment)getTargetFragment()).deleteTeacher();
}
})
.setNegativeButton(R.string.no, null)
.create();
}
}
public void deleteTeacher() {
DbUtils.deleteTeacher(context, selectedItem);
}
I have exactly the same thing in another ListFragment (except I'm casting it to an AssignmentListFragment instead of a TeachersFragment), and that one works flawlessly. In both cases the DeleteDialogFragment class is nested directly under the ListFragment.
The error message I'm getting is as follows:
E/AndroidRuntime(15282): FATAL EXCEPTION: main
E/AndroidRuntime(15282): java.lang.NullPointerException
E/AndroidRuntime(15282): at com.acedit.assignamo.setup.TeachersFragment.access$6(TeachersFragment.java:145)
E/AndroidRuntime(15282): at com.acedit.assignamo.setup.TeachersFragment$DeleteDialogFragment$1.onClick(TeachersFragment.java:137)
E/AndroidRuntime(15282): at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
E/AndroidRuntime(15282): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(15282): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(15282): at android.app.ActivityThread.main(ActivityThread.java:4575)
E/AndroidRuntime(15282): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(15282): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(15282): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
E/AndroidRuntime(15282): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
E/AndroidRuntime(15282): at dalvik.system.NativeStart.main(Native Method)
Given that getTargetFragment() returns null (I checked in debug mode by assigning the return value to a temporary variable and it is null), it seems odd that it makes it to the deleteTeacher() method before crashing (public void deleteTeacher() { is line 145).
Any ideas what the heck is wrong? If you need more code, just let me know.
EDIT: Here is the code where I call setTargetFragment (in my other instance of this code I was able to use this instead of getTargetFragment, so I think that is where the problem lies.
private class CustomOnClickListener implements OnClickListener {
public void onClick(View v) {
Toast.makeText(context, "Button pressed", Toast.LENGTH_SHORT).show();
if (v == viewHolder.editButton)
startActivity(new Intent(context, getEditClass()).putExtra(Values.KEY_ROWID, (Long)v.getTag()));
else { // Delete it
selectedItem = (Long) v.getTag();
DeleteDialogFragment frag = new DeleteDialogFragment();
frag.setTargetFragment(getTargetFragment(), 0);
frag.show(getFragmentManager(), "confirmDelete");
}
}
}
The problem is you don't have a reference to the TeacherFragment since getTargetFragment() is null, but you can fetch the Fragment other ways try using the FragmentManager's getFragmentById() or getFragmentByTag() methods.

service crashing on start

// PPS.java
package com.domain.Servicecrasher;
import android.app.Service;
import android.view.Gravity;
import android.widget.Toast;
public abstract class PPS extends Service
{
#Override
public void onCreate()
{
Toast toasty = Toast.makeText(PPS.this, "service created!", 500);
toasty.setGravity(Gravity.CENTER, 0, 200);
toasty.show();
};
public void onDestroy()
{
Toast toasted = Toast.makeText(PPS.this, "service destroyed!", 500);
toasted.setGravity(Gravity.CENTER, 0, -200);
toasted.show();
};
};
tried to call the service using two methods:
method 1.
{
{
{
startService(new Intent(MainMenu.this, PPS.class));
}
}
}
method 2
{
{
{
Intent startPPS = new Intent(MainMenu.this, PPS.class);
startPPS.putExtra("com.domain.Servicecrasher.PPS", false);
startService(startPPS);
}
}
}
these both return an error on the emulator saying the app quit unexpectedly and i click force close, but the main activity doesn't close, so i'm assuming it's the service that i am force closing. below is the DDMS output:
java.lang.RuntimeException: Unable to instantiate service com.domain.Servicecrasher.PPS
at android.app.ActivityThread.handleCreateService(ActivityThread.java:1929)
at android.app.ActivityThread.access$2500(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:985)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3683)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(Zygote.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
caused by: java.lang.InstantiationException: com.domain.Servicecrasher.PPS
at java.lang.Class.newInstaceImp1(Native Method)
at java.lang.Class.newInstaceI(Class.java:1409)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:1926)
... 10 more
just a couple simple questions.
what am i doing wrong?
what is the proper way to do this?
eventually i need the service to be capable of loading settings from a SQL base and continue recording audio to a file after the main activity loses focus or is closed.
for now i'd be happy if i could just launch a simple service.
Abstract classes, be they Services or other things, cannot be instantiated. Eclipse no doubt suggested that you add the abstract keyword to your class because you had not implemented all the necessary methods to make a concrete instance.
I don't know if Eclipse has an option like this (I assume it does), but IntelliJ IDEA has an option where you can select "implement methods" when you have an incomplete class and it'll add all the stubs you need to fill in. Try that, or consult the documentation for a full list.

Categories

Resources