Activity to SherlockFragment - android

I want to change my app ( extends Activity ) to Fragment ( extends SherlockFragment )
If I change it I have much errors;
public class AlarmClock extends SherlockFragment implements OnClickListener {
This is my onCreateView:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// sanity check -- no database, no clock
if (getContentResolver() == null) {
new AlertDialog.Builder(this)
.setTitle(getString(R.string.error))
.setMessage(getString(R.string.dberror))
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
finish();
}
})
.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
}).setIcon(android.R.drawable.ic_dialog_alert)
.create().show();
return;
}
View view = inflater.inflate(R.layout.alarm_clock, container, false);
// menu buttons
add = (ImageButton) findViewById(R.id.ibAdd);
snooze = (ImageButton) findViewById(R.id.ibSnooze);
add.setOnClickListener(this);
snooze.setOnClickListener(this);
mFactory = LayoutInflater.from(this);
mPrefs = getSharedPreferences(PREFERENCES, 0);
mCursor = Alarms.getAlarmsCursor(getContentResolver());
mAlarmsList = (ListView) findViewById(R.id.alarms_list);
mAlarmsList.setAdapter(new AlarmTimeAdapter(this, mCursor));
mAlarmsList.setVerticalScrollBarEnabled(true);
mAlarmsList.setItemsCanFocus(true);
mClockLayout = (ViewGroup) findViewById(R.id.clock);
mQuickAlarm = findViewById(R.id.ibSnooze);
mQuickAlarm.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showQuickAlarmDialog();
}
});
setVolumeControlStream(android.media.AudioManager.STREAM_ALARM);
setQuickAlarmVisibility(mPrefs.getBoolean(PREF_SHOW_QUICK_ALARM, true));
return view;
}
There are a lot of errors because there is no Activity.
If is Activity it works.
I use "extends SherlockFragment" because I want to add it to the table.
How fix this problem ? Please help me.

If am right, Fragments must definitely be used in an Activity.
So instead of using this use getActivity(); to get the Activity(which uses this fragment) Context.
something like:
getActivity.finish();
and in case of findViewById(//some Id);
use it like this:
inflatedView.findViewById(//Id);

A Fragment is not a Context (unlike Activity or Application). So quite a few methods are not available to it.
It however has access to the context it is attached to. Usually, you can call getActivity() within the fragment to get it. You should check if the Fragment is part of the activity by using the isAdded() method.
You should do some reading about Fragments, porting existing activities to use Fragments, ... tutorials are available using Google.

Related

Dialog pops up very slow

In my app I have implemented this custom dialog (which has a fairly complex layout) by extending DialogFragment. I expect this dialog to pop up when I click a button in my layout. (Which I have successfully achieved). But the problem is that the dialog shows up in a janky manner.
My custom dialog class:
public class CustomizeDialog extends DialogFragment implements AdapterView.OnItemSelectedListener {
// field declarations go here
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.customize_dialog, null);
builder.setView(view)
.setTitle("Customize")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Let's go!", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction("fromDialog");
intent.putExtra("ratio",getRatio(paperSizeSpinner.getSelectedItem().toString()));
if(isOrientationSpinnerVisible){
intent.putExtra("isCustom",false);
intent.putExtra("orientation",orientationSpinner.getSelectedItem().toString());
} else {
intent.putExtra("isCustom",true);
}
intentProvider.getIntent(intent);
}
});
widthEditText = view.findViewById(R.id.width_et);
heightEditText = view.findViewById(R.id.height_et);
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
paperSizeSpinner = view.findViewById(R.id.paper_size_spinner);
orientationSpinner = view.findViewById(R.id.orientation_spinner);
// ArrayList for populating paperSize spinner via paperSizeAdapter
ArrayList<String> paperSizes = new ArrayList<>();
paperSizes.add("A0");
paperSizes.add("A1");
paperSizes.add("A2");
paperSizes.add("A3");
paperSizes.add("A4");
paperSizes.add("A5");
paperSizes.add("Custom");
// ArrayList for populating orientation spinner via orientationAdapter
ArrayList<String> orientation = new ArrayList<>();
orientation.add("Portrait");
orientation.add("Landscape");
// arrayAdapters containing arraylists to populate spinners
ArrayAdapter paperSizeAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, paperSizes);
ArrayAdapter orientationAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, orientation);
paperSizeSpinner.setAdapter(paperSizeAdapter);
orientationSpinner.setAdapter(orientationAdapter);
paperSizeSpinner.setSelection(4);
paperSizeSpinner.setOnItemSelectedListener(this);
orientationSpinner.setOnItemSelectedListener(this);
return builder.create();
}
// These are some important complex ui functionalities
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.paper_size_spinner) {
if (position == 6) {
widthEditText.setEnabled(true);
heightEditText.setEnabled(true);
orientationSpinner.setEnabled(false);
isOrientationSpinnerVisible = false;
} else {
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
orientationSpinner.setEnabled(true);
isOrientationSpinnerVisible = true;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
// interface used to communicate with the parent activity
public interface IntentProvider {
// this method is used to provide the intent to the parent activity
void getIntent(Intent intent);
}
// instantiating the interface object and throwing error if parent activity does not implement this interface
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
intentProvider = (IntentProvider) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement IntentProvider");
}
}
}
MainActivity class:
public class MainActivity extends AppCompatActivity implements CustomizeDialog.IntentProvider {
// field declarations go here
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.image);
// instantiating the dialog
final CustomizeDialog dialog = new CustomizeDialog();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// showing the dialog on click
dialog.show(getSupportFragmentManager(),"");
}
});
}
// via this method I receive the intent from the dialog
// I know intent might not be the best option for this function but let's let it be here for now
#Override
public void getIntent(Intent intent) {
ratio = intent.getFloatExtra("ratio",3);
isCustom = intent.getBooleanExtra("isCustom",false);
orientation = intent.getStringExtra("orientation");
launchChooser();
}
}
Let me know in the comments if you want the layout code for the dialog.
What I tried:
Implementing threading so that my dialog is ready in a background thread and show it onButtonClick. But this is not allowed in general as any other thread except UI thread aren't supposed to touch UI related events.
Using onCreateView instead of onCreateDialog to inflate the layout directly.
Making the dialog a global variable, initialized it in onCreate and then show the dialog onButtonClick.
Switched to CONSTRAINT LAYOUT
Using an activity as a dialog by setting the dialog theme to the activity in the manifest file.
Launched my app in a device with better hardware than mine.
BUT NOTHING WORKED
What I want:
Why is my dialog janky? and what I need to do to make the dialog pop up faster?
In case anybody wants here's the link to my app repo on github.
AlertDialog and DialogFragment frameworks are slow because they need to some time to do calculations and fragment stuffs. So a solution to this problem is, using the Dialog framework straight away.
Use the Dialog framework's constructor to initialize a Dialog object like this:
Dialog dialog = new Dialog(context, R.style.Theme_AppCompat_Dialog);
// the second parameter is not compulsory and you can use other themes as well
Define the layout and then use dialog.setContentView(R.layout.name_of_layout).
Use dialog.findViewById(R.id.name_of_view) to reference views from the dialog's layout file
And then implement the logic just like anyone would do in an activity class. Find out the best implementation for your use case by reading the official documentation.

DialogFragment's weird behavior

I spent all day trying to make this up, but I can't..
This is the problem: I want an yes/no AlertDialog that doesn't disappear on orientation change, so I decided to use DialogFragment.
So I prepared the code and for the first use, everything with it is just perfect, but if I hit the button (that should show the dialog) once more (second, third and further times) the dialog doesn't show up! Though I can see from logs it actually makes instances and I have no errors, it's there, I just can't see it!
If I fold the app, or turn off / on the screen (I believe it's about calling onResume() method) the dialogs shows up, all of them (depending how much time I hit the button), it seems like a some displaying issue or refreshing problem maybe.. I don't know, so I came here hoping to get some help.
About my code:
I have a ListView with custom adapter, and in that adapter I have the code to show the an AlertDialog (DialogFragment) - as part of an ImageButton onClickListener.
The code for DialogFragment that I use:
public static class cMyDialogFragment extends DialogFragment {
public static cMyDialogFragment newInstance(int title) {
cMyDialogFragment frag = new cMyDialogFragment();
Bundle args = new Bundle();
args.putInt("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int title = getArguments().getInt("title");
this.setCancelable(true);
setRetainInstance(true);
return new AlertDialog.Builder(getActivity())
// .setIcon(R.drawable.alert_dialog_icon)
.setTitle(title)
.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((ActAudiorecords) getActivity()).doPositiveClick();
}
}
)
.setNegativeButton(R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((ActAudiorecords) getActivity()).doNegativeClick();
}
}
)
.create();
}
}
The code for calling the dialog to show up (within the custom ListView adapter):
public View getView(final int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (vi == null)
vi = inflater.inflate(R.layout.recordings_row, null);
TextView tvDate = (TextView) vi.findViewById(R.id.tv_Recordings_r_date);
tvDate.setText(ainfo.get(position).getDate());
ImageButton ibtn_play = (ImageButton) vi.findViewById(R.id.ibtnPlay);
final String localPath = dPath + File.separator + ainfo.get(position).getFName();
ImageButton ibtn_remove = (ImageButton) vi.findViewById(R.id.ibtnRecordings_r_remove);
ibtn_remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
curFName = ainfo.get(position).getFName();
curID = ainfo.get(position).getID();
showDialog();
}
});
ibtn_play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
play(localPath);
}
});
return vi;
}
The additional functions:
void showDialog() {
DialogFragment newFragment = cMyDialogFragment.newInstance(
R.string.do_you_want_to_remove_the_file);
newFragment.show(getFragmentManager(), "dialog");
}
public void doPositiveClick() {
// Do stuff here.
ps_db.delete(const_audiorecords_tname, "id = " + curID, null);
new File(dPath + File.separator + curFName).delete();
Toast.makeText(ActAudiorecords.this, getString(R.string.audiorecord_has_been_removed), Toast.LENGTH_LONG).show();
ActAudiorecords.this.onCreate(null); //Restarting the Activity to refresh the LV
Log.i("FragmentAlertDialog", "Positive click!");
}
public void doNegativeClick() {
// Do stuff here.
Toast.makeText(ActAudiorecords.this, getString(R.string.the_operation_has_been_cancelled), Toast.LENGTH_LONG).show();
Log.i("FragmentAlertDialog", "Negative click!");
}
I have no onResume() in my code.
I tried to use different codes for DialogFragment but it doesn't matter.
It was all due to the line:
ActAudiorecords.this.onCreate(null);
So after calling onCreate() with null as savedInstance it have been removing link to the DialogFragment (as I can understand), it was the line for refreshing the Activity, I solved the problem by splitting the code in onCreate() to which should be called only once (at a start of Activity) and the part that should be called in every refreshing point (such as GUI settings and etc).
I believe I could also save the current Bundle and pass it to onCreate() instead of null and it would work as good as now, but I thought that calling an function is much better for data updating than calling onCreate() over and over, so that's it, thank you all who wanted to help.

Exception when showing a dialog after orientation change

I have an activity and a fragment inside it.inside fragment, there is a button, and on click of button a dialog shows.
Everything works, until user do a orientation change and click button after it.
IllegalStateException(cannot perform this action after onsaveinstancestate) occurs when user clicks button after orientation change. I'm using android support framework.
Anybody have any idea regarfing this?
Activity Code
public void openMoreDialog(String shareData, String link) {
DialogFragment dialog = new MoreDialog(shareData, link);
dialog.show(getSupportFragmentManager(), "MoreDialog");
}
Fragment Code
public void onAttach(Activity activity) {
super.onAttach(activity);
mControl = (ActivityControl)activity;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
ImageButton moreButton = (ImageButton)v.findViewById(R.id.moreButton);
moreButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mControl.openMoreDialog(shareData, link);
}
});
return rootView;
}
FragmentDialog code
public class MoreDialog extends DialogFragment {
private String mShareData;
private String mLink;
public MoreDialog(String shareData, String link){
mShareData = shareData;
mLink = link;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.more_dialog, null);
Button openBtn = (Button)dialogView.findViewById(R.id.openBtn);
openBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openLink(mLink);
}
});
Button shareBtn = (Button)dialogView.findViewById(R.id.shareBtn);
shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shareNews(mShareData);
}
});
builder.setView(dialogView);
return builder.create();
}
private void openLink(String link){
}
private void shareNews(String data){
}
}
Helpful link & solution how to:
https://stackoverflow.com/a/17413324/619673 and btw, constructor in fragment must be empty! Documentation:
http://developer.android.com/reference/android/app/Fragment.html
public Fragment ()
Added in API level 11
Default constructor.
Every fragment must have an empty constructor, so
it can be instantiated when restoring its activity's state. It is
strongly recommended that subclasses do not have other constructors
with parameters, since these constructors will not be called when the
fragment is re-instantiated; instead, arguments can be supplied by the
caller with setArguments(Bundle) and later retrieved by the Fragment
with getArguments().
Applications should generally not implement a constructor. The first
place application code an run where the fragment is ready to be used
is in onAttach(Activity), the point where the fragment is actually
associated with its activity. Some applications may also want to
implement onInflate(Activity, AttributeSet, Bundle) to retrieve
attributes from a layout resource, though should take care here
because this happens for the fragment is attached to its activity.

How to fix The method startActivity(Intent) is undefined for the type new View.OnClickListener() syntax error

I have a syntax errors with my code , in the "getView" I want to make a listener for the button "update" to move to another activity :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater l = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
View rowView = l.inflate(R.layout.temp, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.textView1);
ImageView imageView = (ImageView) rowView.findViewById(R.id.imageView1);
Button update = (Button) rowView.findViewById(R.id.button1);
// update.setOnClickListener(new View.OnClickListener() {
//
// #Override
// public void onClick(View v) {
//
// Intent redirect = new Intent(getApplicationContext(),Update.class);
// startActivity(redirect);
//
// }
// });
textView.setText(sa.get(position));
return rowView;
}
I've tried to fix these errors about "Intent" but I failed :(
The method startActivity(Intent) is undefined for the type new View.OnClickListener()
The method getApplicationContext() is undefined for the type new View.OnClickListener()
and even whene I moved these statements from "onClick" method the problem didn't change !!
I imported "Intent" library , how to solve that ????
If your adapter is in a different file you will need activity context.
You need to pass the activity context from your activity class to your adapter constructor.
http://developer.android.com/reference/android/content/Context.html#startActivity(android.content.Intent)
startActivity is a method of your activity class. So you need activity context to start the activity.
Also instead of getApplicationContext use activity context.
When to call activity context OR application context?
Check the answer by commonsware.
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent redirect = new Intent(context,Update.class);
context.startActivity(redirect);
}
});
Try
final Activity thisActivity = this;
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent redirect = new Intent(thisActivity,Update.class);
thisActivity.startActivity(redirect);
}
});
for similar problem for me just this helped me :
#Override
public void onClick(View v) {
Intent intent = new Intent(G.context, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
G.context.startActivity(intent);
}
});
add context in G Class :
public class G extends Activity {
public static Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = getApplicationContext();
}
}
You just need to call context.startActivity instead, can follow below steps
Three simple steps
1) Declare local Variable Context mCtx
2) intialize it with Activity context either by passing a parameter to constructor/method, or in the onCreate method if you are using above code in activity.
3) call mCtx.startActivity(intent);
or
you can call ActivityName.this.startActivity()
Edit:- As par dmon comment, You simply can use your local context instance
The root of your problem is that you cannot start an Activity from an application Context (only from an activity context you have the right to do that). The reason for that is that android bundles all activities of your application as a group (task) in order to allow multitasking between different apps. When you launch a new app, or press the home button for example, you are application (together with its activities backstack) is going to the background and leaves the scene to a new task (with a different activity backstack and so on and so forth). For more info on this mechanism you can take a look here (http://developer.android.com/guide/components/tasks-and-back-stack.html).
In order to gain a context that is ok to lauch a new activity from, you can always get the context of the parent of the view you are inflating, by calling viewgroup.getContext() - eventhough you will have to declare the viewgroup as final, which is ok since you shouldn't be touching the parent.
a draft of your getView:
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
LayoutInflater l = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE);
View rowView = l.inflate(R.layout.temp, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.textView1);
ImageView imageView = (ImageView) rowView.findViewById(R.id.imageView1);
Button update = (Button) rowView.findViewById(R.id.button1);
update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent redirect = new Intent(parent.getContext(),Update.class);
startActivity(redirect);
}
});
textView.setText(sa.get(position));
return rowView;
}

Android: Can i show multiple Dialogs one over another? Is there something like Dialog Z-Level?

Is it possible to show multiple Dialogs one over another? Is there something like Dialog Z-Level?
I am using DialogFragment where user chooses elements, when he comfirms his choice, it is saved to database and sent on server. if the save action fails I would like to inform user with ... another dialog is it possible? And will it not clear off my first dialog?
Thanks in advance.
Indeed, it's possible to show multiple dialog Fragments one inside another one. The z-order depends on the order they are created.
In the code below there is an example of a FragmentActivity with the behavior that you require.
public class MyActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
//...
}
public void onSave(View view) {
Intent intent = getIntent();
this.setResult(RESULT_OK, intent);
finish();
}
public void onCancel(View view) {
finish();
}
public void SelectWeekDay(View view) {
DialogFragment selectWeekDayFragment = new SelectWeekDayFragment();
selectWeekDayFragment.show(getSupportFragmentManager(), "WeekDayDialog");
}
public class SelectWeekDayFragment extends DialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.week_day_dialog, container, true);
Button saveButton = (Button) view.findViewById(R.id.button_save);
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CheckBox checkboxMonday = (CheckBox) getDialog().findViewById(R.id.checkBox_monday);
if (!checkboxMonday.isChecked()) {
DialogFragment saveErrorFragment = new SaveErrorFragment();
saveErrorFragment.show(getSupportFragmentManager(), "SaveErrorFragment");
}
else {
SaveToDb(); //Perform actions to store on db or what you wish
dismiss();
}
}
});
Button cancelButton = (Button) view.findViewById(R.id.button_cancel);
cancelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
}
});
return view;
}
}
public class SaveErrorFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage("You must select Monday").setPositiveButton("Ok", null).create();
}
}
}
My advice is to use a custom layout with a ViewFlipper inside your dialog so you can easily switch between a progress-bar or whatever different layouts you want to show. If you want to show multiple Dialogs my guess is that the z-order depends on the order they were created the latest beeing shown on top.
You usually can, however, just be a little careful. Use the dialog's lifecycle to your advantage to avoid side-effects. For example: you can do a check on a function like onStop() to see if the child dialog is open, and if so, close it.
Ideally, cutting down on the amount of layers of dialogs you have is ideal, as long as it's sane (for example: doing it ends up being hundreds of lines of code more)

Categories

Resources