I have fragmentActivity class which implements OnTabChangeListener and acts as a host for other fragment classes. Every fragment classes is defined in different XML layout files for their own Layout.
I want to get the View from that fragment class inside the fragmentActivity class.
I have tried :
View view = myFragment.getView();
Button myButton = (Button) view.findViewById(R.id.my_button);
myButton.setOnClickListener(new MyClickListener());
But doesn't seem to work.
So does anyone know?
If you want you can use the BroadcastReciver to send event notification to your activity from your fragment.
To register a broadcast reciver in your FragmentActivity do something like this :
public class MyActivity extends FragmentActivity {
private BroadcastReceiver myBroadcastReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(...) {
//YOU WILL RECEIVE YOUR BROADCAST HERE. WRITE YOUR CODE HERE TO ADD NEW TAB
}
});
...
public void onResume() {
super.onResume();
....
registerReceiver(myBroadcastReceiver, intentFilter);
}
public void onPause() {
super.onPause();
...
unregisterReceiver(myBroadcastReceiver);
}
...
}
Now to send Broadcast from your fragment do like this :
Intent intent=new Intent();
intent.setAction("ANY_UNIQUE_NAME");
intent.putExtra("data",EXTRA_DATA_IF_YOU_WANT);
sendBroadcast(intent);
You will receive this broadcast on your activity's on Receive Event. Do whatever you want to do there.
If you want to acces your component and set some data, I suggest you to make a method inside the fragment like this:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class DetailFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.details, container, false);
return view;
}
public void setSettings(){
Button button = (Button) getView().findViewById(R.id.my_button);
button.setOnClickListener(new MyClickListener());
}
}
Related
I'm facing some problems in Android development. Environment is set to run in min API 23.
This is what I try to achieve :
I have a MainActivity with a BottomNavigationView. When an item in the BottomNavigationView is clicked it launches a Fragment. This works very well,I can send data to a fragment and have an interface to dialog with my activity.
The problem is :
On my Last fragment (ProgramFragment), I would like to make a Form Wizard. So, I would like to launch other fragments from the ProgramFragment. I used the same method I used in the MainActivity and I can launch the first fragment (RecStartFragment) where there is a button in the Layout. I want that when the button is clicked, the next fragment (RecDataPatientFragment) is shown. I get an error when I click on the button, saying that :
java.lang.NullPointerException: Attempt to invoke interface method
'void x.RecStartFragment$OnRecStartFragmentListener.startRecProg()'
on a null object reference at
x.RecStartFragment$1.onClick(RecStartFragment.java:30)
Is there a way to achieve that ? Why is that working from an activity but not from a fragment ?
Here is the code of the fragment RecStartFragment
package x;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class RecStartFragment extends Fragment {
private static final String TAG = RecStartFragment.class.getName();
private View v;
OnRecStartFragmentListener onRecStartFragmentListener;
private Button btnStartRec;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
if(v != null) {
return v;
}
v = inflater.inflate(R.layout.fragment_rec_start, null);
btnStartRec = v.findViewById(R.id.btn_start_rec);
btnStartRec.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onRecStartFragmentListener.startRecProg();
}
});
return v;
}
public interface OnRecStartFragmentListener
{
public void startRecProg();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onRecStartFragmentListener = (OnRecStartFragmentListener) context;
} catch (Exception e)
{
}
}
Thank you in advance !
You have a Null Pointer Exception (NPE) indicating that the field OnRecStartFragmentListener onRecStartFragmentListener has not been initialised.
From your code, you are trying to initialise the field in onAttach() and catching exceptions, but not doing anything with them:
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onRecStartFragmentListener = (OnRecStartFragmentListener) context;
} catch (Exception e)
{
}
}
Try printing the stacktrace of any exceptions:
e.printStackTrace()
The context passed in onAttach is your MainActivity ? If so, is it implementing OnRecStartFragmentListener ?
You should implement the interface in your activity:
Activity implementation:
public class MainActivity extends AppCompatActivity implements RecStartFragment.OnRecStartFragmentListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment();
}
#Override
public void startRecProg() {
//Do whatever you need do here.
Log.e("Calback:","Interface is working");
}
}
I created a ListDialog extending a DialogFragment class and I have a problem with understanding of this code in the DijalogX class
((MainActivity)getActivity()).setTextField(selectedItem);
I understand that with this code above I put selected String variable to the setTextField method as an argument and after that this variable is showed in TextView on MainActivity class.
My questions:
Why I need a cast from getActivity() to the MainActivity and how I get access from DijalogX(fragment) to the method setTextField in MainActivity? Please explain a little about this process.
I also tried instead of ((MainActivity)getActivity()).setTextField(selectedItem)
use an Interface and everything works nice and I got the same resoult but I am wondering what is better solution here Interface or ((MainActivity)getActivity()).setTextField(selectedItem)?
MainActivity
package com.example.dezox.dijaloglist;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity{
private Button btnStartDialog;
private TextView tvSelectedOption;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidgets();
setupListener();
}
private void initWidgets() {
btnStartDialog = findViewById(R.id.btnDialog);
tvSelectedOption = findViewById(R.id.tvselectedOption);
}
private void setupListener() {
btnStartDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DijalogX dijalogX = new DijalogX();
dijalogX.show(getSupportFragmentManager(), "dx");
tvSelectedOption.setText("");
}
});
}
public void setTextField(String odabrano){
tvSelectedOption.setText(odabrano);
}
public String getTextField(){
return tvSelectedOption.getText().toString();
}
}
DijalogX
package com.example.dezox.dijaloglist;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
public class DijalogX extends DialogFragment {
private String[] languageList;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initListResource();
}
private void initListResource() {
languageList = getResources().getStringArray(R.array.language_list);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
android.R.style.Theme_Material_Dialog_Alert)
.setTitle("Select Language: ")
.setItems(languageList, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String selectedItem = languageList[which];
//THIS PART OF THE CODE I DONT UNDERSTAND:
((MainActivity)getActivity()).setTextField(selectedItem);
}
});
return builder.create();
}
}
You have declared a method in MainActivity called setTextField. If you called
Activity a = getActivity();
you would not be able to call your custom method (it is on your derived class, not the base Activity class).
a.setTextField(selectedIte); // WON'T WORK - NO SUCH METHOD
If instead you call
MainActivity ma = (MainActivity)getActivity();
it is now cast as your derived class and you can then call
ma.setTextField(selectedItem);
Doing it in two lines like this is the same as calling the one-liner in your code
((MainActivity)getActivity()).setTextField(selectedItem);
As far as casting vs. an interface, an interface is a bit more flexible of an approach. If you tried to use this fragment in a different activity (not MainActivity) the casting approach would fail. If you are only ever going to use the fragment in this Activity then either would work.
I have a BroadcastReceiver which receives broadcast sent to a Fragment.
I'm getting the broadcast but how can I call a method from the Fragment itself?
I basically need to update a List once the broadcast arrives, the List & update method are part of the Fragment.
public class FragmentReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action != null && action.equals("AllTasksFragmentUpdate"))
{
//
}
}
}
Registering the receiver:
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getActivity().registerReceiver(new FragmentReceiver(), new IntentFilter("AllTasksFragmentUpdate"));
}
How can I call the method from the Fragment?
You can implement your broadcast reciever in the following way:
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.adobe.libs.connectors.R;
public class YourFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
//Start listening for refresh local file list LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mYourBroadcastReceiver,
new IntentFilter(<YOUR INTENT FILTER>));
return inflater.inflate(R.layout.your_fragment_layout, null, true);
}
#Override
public void onDestroyView() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mYourBroadcastReceiver);
}
private final BroadcastReceiver mYourBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Now you can call all your fragments method here
}
};
}
In your onReceive() method, you can find your fragment by its tag name (the name using which you instantiated your fragment) and call its public method.
SampleFragment fragment = (SampleFragment) getSupportFragmentManager().findFragmentByTag(<fragment_tag_name>);
if (fragment != null && fragment.isAdded()) {
fragment.method(); //Call any public method
}
Hope this helps !
Supposing that you have an Activity named MyActivity and at some point in your code, you want to make a broadcast to be received by a Fragment named MyFragment. You can do it like this:
In MyActivity, use LocalBroadcastManager to make the broadcast with a filter:
String filter = "thisIsForMyFragment";
Intent intent = new Intent(filter); //If you need extra, add: intent.putExtra("extra","something");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
In MyFragment, inside onCreateView() add this to register the receiver:
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(myBroadcastReceiver,
new IntentFilter("thisIsForMyFragment"));
Following, In MyFragment (outside onCreateView()) create the receiver method to receive the broadcast:
private final BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, android.content.Intent intent) {
Toast.makeText(getActivity(), "Broadcast received!", Toast.LENGTH_SHORT).show();//Do what you want when the broadcast is received...
}
};
Finally, in MyFragment add this to unregister the receiver onDestroyView:
#Override
public void onDestroyView()
{
super.onDestroyView();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(myBroadcastReceiver);
}
activity!!.registerReceiver(receiver, IntentFilter(DataKeys.STATUS))
I am very new to android so please excuse me if my question is an obvious one. I have to split the screen in 2 parts and give action to each of the fragments. One part will plot the data and the other part will display the data. I have used fragments to split the screen but I want to know how to give the action to each of the fragments so that it starts together.
I don't want to initiate any fragment with a click of button or else. I want that as soon as the app starts, then both the fragments starts to display their respective plots and data.
Your help in this regard will be highly appreciated.
EDIT
I have attached the codes
PlotFragment.java (the file which I want to run in one of the fragment as the app is launched)
package com.tempsensor;
import android.app.Fragment;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
public class PlotFragment extends FragmentActivity {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstancesState){
Toast.makeText(this, "Plot Comes Here", Toast.LENGTH_LONG).show();
return null;
}
}
SecondActivity.java (the java file which contains the Activity within which I have created the two fragments)
package com.tempsensor;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.support.v4.app.FragmentActivity;
public class SecondActivity extends Activity implements OnClickListener {
Button buttonexit;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
buttonexit = (Button) findViewById(R.id.button1);
buttonexit.setOnClickListener(this);
getFragmentManager().beginTransaction().add(R.id.plot_fragment, new PlotFragment()).commit();
getFragmentManager().beginTransaction().add(R.id.data_fragment, new DataFragment()).commit();
}
public void onClick(View arg0) {
if (arg0==buttonexit)
{
System.exit(0);
}
}
}
Where am I making a mistake, the desired result is that when the app launches these two fragments should start their task automatically, here I am just trying to print a text using Toast.
If I'm understanding your question correctly, you want the app to open and show both fragments with all their info already loaded, a plot on one and data in the other?
In the activity that is launched, you are creating a fragment and committing a transaction that adds it to a container, correct? All you should have to do do the same for the other fragment: create it and commit a transaction adding it to the other container.
Here's some simple code demonstrating what I mean:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction()
.add(R.id.plot_container, new PlotFragment()).commit();
getFragmentManager().beginTransaction()
.add(R.id.data_container, new DataFragment()).commit();
}
So, you can create method in second fragment. This method will return needed data.
For example: you must to get instanse of fragment in current activity and call this method like this:
for (Fragment f : getActivity().getFragmentManager().getFragments()) {
if (f instanceof SecondFragment) {
int data = ((SecondFragment) f).returnData();
}
First, i suggest you to change the way you add the fragments to the layout, something like this:
public class SecondActivity extends Activity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
buttonexit = (Button) findViewById(R.id.button1);
buttonexit.setOnClickListener(this);
PlotFragment plotFrag = new PlotFragment();
DataFragment dataFrag = new DataFragment();
addData(plotFrag);
addData(dataFrag);
getFragmentManager().beginTransaction().add(R.id.plot_fragment, plotFrag).commit();
getFragmentManager().beginTransaction().add(R.id.data_fragment, dataFrag).commit();
}
protected void addData(DataFragment dataFrag) {
Bundle args = new Bundle();
// Load data to args variable
dataFrag.setArguments(args);
}
protected void addData(PlotFragment plotFrag) {
Bundle args = new Bundle();
// Load plot data to args variable
plotFrag.setArguments(args);
}
}
In the Fragments classes:
public class DataFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstancesState){
Bundle args = getArguments() == null ? savedInstanceState : getArguments();
// Use args to setup Fragment content
Toast.makeText(this, "Data Comes Here", Toast.LENGTH_LONG).show();
return null;
}
public class PlotFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstancesState){
Bundle args = getArguments() == null ? savedInstanceState : getArguments();
// Use args to setup Fragment content
Toast.makeText(this, "Plot Comes Here", Toast.LENGTH_LONG).show();
return null;
}
Good day. I'm having some issues with my android project specifically listview. I tried searching for other information here in this site, and implemented some of the answers. However, it is still not working.
The error specifically is
NullPointerException at line 76 at MainActivity
Here is the code of my MainActivity
import java.util.ArrayList;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
public class MainActivity extends Activity {
final ArrayList<String> studentName = new ArrayList<String>();
ArrayAdapter<String> aa;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView myList = (ListView) findViewById(R.id.listName);
aa = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, studentName);
myList.setAdapter(aa);
//droid.R.id.list;
//add
Button bAdd = (Button) findViewById(R.id.addstudent);
bAdd.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
startActivity(new Intent("android.intent.action.ADDSTUDENTS"));
}
});
//edit
Button bEdit = (Button) findViewById(R.id.editstudent);
bEdit.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View x) {
startActivity(new Intent("android.intent.action.EDITSTUDENTS"));
}
});
//edit
Button bDelete = (Button) findViewById(R.id.deletestudent);
bDelete.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View x) {
startActivity(new Intent("android.intent.action.DELETESTUDENTS"));
}
});
}
public ArrayList<String> getArray(){
return studentName;
}
public void notifyArray(){
aa.notifyDataSetChanged();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
and line 76 by the way is
aa.notifyDataSetChanged();
Here is my code for the AddStudents class
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class AddStudents extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.add_student);
Button bAddStudents = (Button) findViewById(R.id.add);
final EditText et = (EditText) findViewById(R.id.student_name);
bAddStudents.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
MainActivity as = new MainActivity();
as.getArray().add(et.getText().toString());
as.notifyArray();
finish();
}
});
Button bBack = (Button) findViewById(R.id.backadd);
bBack.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
finish();
}
});
}
}
and the xml part with the list view is
<ListView
android:id="#+id/listName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
</ListView>
I hope you can help me cause I want to also learn what my mistakes are. I can add other information if you want.
In your AddStudents class, you're calling notifyArray() right after you instantiated MainActivity. MainActivity.onCreate() will not be called just by instantiating it.
Instantiating your MainActivity there is probably not what you want anyway (because that object will be disposed directly after the onClick handler is done).
What you want instead is to access the existing instance of MainActivity. For that, add a reference to the current instance to a static member of your MainActivity class, e.g.
public class MainActivity extends Activity {
public static MainActivity activity;
#Override
protected void onCreate(Bundle savedInstanceState) {
activity = this;
}
}
Then in your AddStudent class access it via
MainActivity.activity.notifyArray()
This is not the most beautiful way to solve your issue, but it works as long as you can be sure to only have one MainActivity instance. (If not, you could make the array itself static; or create a Singleton wrapper class for it.)
notifyArray() is being called before onCreate.
Try calling getArray().add(et.getText().toString()); and notifyArray(); inside onResume() of MainActivity and NOT from AddStudentActivity( not recommended!)
So onResume() you would ideally want to add a new student to the list, so in your case, you can retrieve the student name using a common sharable object like a hashtable or somethiing similar, make it a singleton, and use it from anywhere in the applciation
The common class may go something like:
class CommonHashtable{
private static Hashtable<String, Object> commonHashtable = null;
public static getInstance(){
if(commonHashtable == null)
commonHashtable = new Hashtable<String, Object>();
return commonHashtable;
}
on getInstance(), it returns a commonHashtable which can be used to store values temporarily!
so, add this on addbutton click event
Hashtable hash = CommonHashtable.getInstance();
hash.put("NEW_STUDENT_NAME", et.getText().toString());
and add this in you onResume() of MainActivity
Hashtable hash = CommonHashtable.getInstance();
Object studentName = (String) hash.get("NEW_STUDENT_NAME");
if(studentName != null){
notifyArray();
}