How to get context from fragment under this circumstance? - android

i've already implemented this thing in my application using activity,
refer image link below
"http://imgur.com/LuErJjY"
in the first part you can see the context=PerformanceActivity#4015
but in the 2nd part it is null
the code i've used is
IN ACTIVITY:
viewHolder.nextReview.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int d=v.getId();
((PerformanceActivity)context).performReview(v.getId());
}
});
IN FRAGMENT:
NOTE: PerformanceFragment pf;
viewHolder.nextReview.setId(resData.get(position).getTestID());
viewHolder.nextReview.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int d=v.getId();
((PerformanceFragment)pf).performReview_frag(v.getId());
}
});
Both the methods are methods present in the adapter of a listview. In Activity It just works fine, but not in fragment.
Links to both adapters:
https://pastee.org/28chw - Fragment's Adapter https://pastee.org/nw8rr
- Fragment
https://pastee.org/wxepy -Activity's Adapter

At last this worked for me -
PerformanceFragmentAdapter adapter = new PerformanceFragmentAdapter(context,rsuData,device,this);
and adding this to the adapter as
private PerformanceFragment pf;
public PerformanceFragmentAdapter(Context conte, ArrayList<ResultData> rData,
int device, PerformanceFragment pp) {
super();
context = conte;
resData = rData;
size = device;
pf=pp;
}
guess #ursgtm is right. still confusing between Context c=getActivity(); and this keyword

In PerformanceFragmentAdapter class :
PerformanceFragment pf;
You are just creating a object with no instance and you are using that object as context,and you are not assigning anything to pf .
Instead of remove pf, and pass the context which you got from constructor:
viewHolder.nextReview.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int d=v.getId();
//Replace ((PerformanceFragment)pf) with context
context.performReview_frag(v.getId()); //you obtained context from contractor.
}
});
Hope this helps you !

In second part use getActivity() method if your fragment PerformanceFragment is associated with your activity PerformanceActivity
viewHolder.nextReview.setId(resData.get(position).getTestID());
viewHolder.nextReview.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int d=v.getId();
/* (getActivity()). no need to use content if
performReview_frag() is present in PerformanceFragment fragment*/
// this will call performReview_frag() method
performReview_frag(v.getId());
}
});
Else,
You can use getBaseContext() method to get correct context

Related

How to get fragment tag or ID?

I have 2 fragments which are instantiated from the same class as the layouts are identical like so:
getSupportFragmentManager().beginTransaction().
add(R.id.leftContainer,new LeftFragmentClass(),"leftFrag").commit();
getSupportFragmentManager().beginTransaction().
add(R.id.rightFrag,new LeftFragmentClass(),"rightFrag").commit();
Within LeftFragmentClass there is a callback method which is called when the button within the fragment is pressed. After this some processing is done and data is displayed, however, right now the callback cannot distinguish which button was pressed. Is there a function which can return which fragment button was pressed?
For this type of condition i create a function inside fragment which will return me the instance of fragment and make the fragment constructor private something like:-
public class LeftFragmentClass extends Fragment{
private String fragmentTag = null;
public LeftFragmentClass(){}
public static LeftFragmentClass newInstance(String tag){
LeftFragmentClass mLeftFragmentClass = new LeftFragmentClass();
Bundle bundle = new Bundle();
bundle.putString ("tag",tag);
mLeftFragmentClass.setArgument(bundle);
return mLeftFragmentClass;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
tag = getArguments().getString("tag")
}
}
So i used newInstance function to create instance of LeftFragmentClass and pass the tag to it which i m setting to Fragment argument using bundle and inside onCreate get bundle using getArguments and from it the tag value. Pass this tag value as one of the parameter to your callback method to identify which button was clicked.
So from activity for getting instance of LeftFragmentClass you can write as
LeftFragmentClass mLeftFragmentClassLeft = LeftFragmentClass.newInstance("left")
LeftFragmentClass mLeftFragmentClassRight = LeftFragmentClass.newInstance("Right")
==== Edit ====
keep the fragment class constructors always public don't make it private as i suggested above in my sample code. Making it private will cause application to crash with exception
java.lang.RuntimeException: Unable to start activity
ComponentInfo{MainActivity}:
android.support.v4.app.Fragment$InstantiationException: Unable to
instantiate fragment com.thatswhy.AppAlertDialog: make sure class name
exists, is public, and has an empty constructor that is public
Fragment fragment = getFragmentManager().findFragmentByTag("Tag")
As per provided the info you can do something like this, in your callback method pass the button object and check accordingly,
Some code snippet to explain the same :
Suppose your callback method is onButtonClick() then you can pass button object like :
public void onButtonClick(Button button){
// check here with button id
if(button.getId() == R.id.button1) {
} else if(button.getId() == R.id.button1) {
}
}
Hope this makes things clear..
The cleanest way of doing this I've seen is to create two distinct View.OnClickListener(s) in the Activity.
Have a getter() for each. public View.OnClickListener getLeftButtonPressed(), public View.OnClickListener getRightButtonPressed()
Then when you instantiate your left and right instances of your fragment, just pass in the appropriate 'View.OnClickListener' to the constructor of the Fragment. This not only reduces the code in the Fragment(s), it also centralizes the 'logic' of what to do when buttons are pressed.
public class MyActivity extends Activity {
// create the two listeners
View.OnClickListener leftButtonListener = new View.OnClickListener() {
public void onClick(View v) {
leftButtonClicked(v);
}
});
View.OnClickListener rightButtonListener = new View.OnClickListener() {
public void onClick(View v) {
rightButtonClicked(v);
}
});
// 2 getters
public View.OnClickListener getLeftListener() { return this.leftButtonListener; }
public View.OnClickListener getRightListener() { return this.rightButtonListener; }
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.content_layout_id);
}
// actual logic of what to do when each button is pressed.
private void leftButtonClicked(View v){
// some logic here
}
private void rightButtonClicked(View v){
// some logic here
}
}
This removes you later having to keep track of which button was pressed by making use of strings and if/then/else blocks, etc.
Add a parameter to interface callback function in your fragment;
interface Interfacecallback{
public void callbackfunction(int fragid);
}
Interfacecallback interfacecallback;
//in your button click
//pass 1 for fragment right
//pass 2 for fragment left
interfacecallback.callbackfunction(1);
You can check the fragment tag using this line of code if it exists:-
Fragment mapFragment = getFragmentManager().findFragmentByTag("MapRestaurantFragment");

Deleting items in ListView using intent

my problem is that im trying to delete items from ListView and for that I have a button in CustomAdapter.
Im setting this button an onClickListener and try to pass item name to main activity using Intent.
In Main when intent named "deleteProduct" is received the method deleteProduct is called and in this method im trying to pass to database a product name which to delete.
my CustomAdapter:
private DbItemDeleteListener deleteListener;
CustomAdapter(Context context, ArrayList<Product> productNames,DbItemDeleteListener deleteListener) {
super(context,R.layout.custom_list_row ,productNames);
this.deleteListener = deleteListener;
}
final Product singleProduct=getItem(position);
final TextView productName=(TextView)customView.findViewById(R.id.ProductName);
final Button CheckButton = (Button)customView.findViewById(R.id.CheckButton);
final Button DeleteButton = (Button)customView.findViewById(R.id.DeleteButton);
DeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String product=singleProduct.get_productname();
deleteListener.delete(product);
}
});
MY Main:
DbItemDeleteListener deleteListener;
ArrayAdapter<Product> adapter;
ArrayList<Product> productnames=new ArrayList<>();
DBHandler dbhandler;
#Override
public void delete(String productId){
dbhandler.deleteProduct(productId);
}
And my DBHandler:
public void deleteProduct(String productname){
SQLiteDatabase db=getWritableDatabase();
db.execSQL("DELETE FROM " +TABLE_PRODUCTS+ " WHERE "+ COLUMN_PRODUCTNAME+ "=\" "+ productname +"\";");
}
Also im getting this message in logcat when i click delete button:
Process: com.example.olev.shoppinglist, PID: 1836
java.lang.NullPointerException: Attempt to invoke interface method 'void com.example.olev.shoppinglist.DbItemDeleteListener.delete(java.lang.String)' on a null object reference
at com.example.olev.shoppinglist.CustomAdapter$3.onClick(CustomAdapter.java:80)
at android.view.View.performClick(View.java:4756)
You shouldn't really need to use an intent just to delete a list item. Instead, use the observer pattern. First, create an interface:
public interface DbItemDeleteListener{
public void delete(String productId);
}
Implement the interface in your Activity (your activity is probably not the greatest place to implement, but since it's where you're already doing the deleting, I'll stick with that):
public class MyActivity extends Activity implements DbItemDeleteListener{
...
#Override
public void delete(String productId){
dbhandler.deleteProduct(productId);
}
}
Then, pass an instance of your class that implements the listener to your adapter's constructor:
public CustomAdapter extends WhateverAdapter{
private DbItemDeleteListener deleteListener;
public MyAdapter(DbItemDeleteListener deleteListener){
this.deleteListener = listener;
}
}
Make sure you use this version of the constructor when you create your adapter.
Then, instead of the onClickListener sending an intent:
DeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//get the product name and use the listener to delete
...
deleteListener.delete(productId);
notifyDataSetChanged();
}
}
But if you still plan on using intents for some reason:
http://developer.android.com/reference/android/app/Activity.html#onNewIntent(android.content.Intent)
This is called for activities that set launchMode to "singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent).
What I'm guessing is happening is that instead of getting the current instance of your Main activity, you're actually creating a new instance. Therefore, you should be doing the same check in onCreate() instead.
So you can either set your activity's launch mode to something that will call onNewIntent:
<activity
android:launchMode="singleTop"
...>
....
</activity>
and/or also add the flag to your intent:
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Or, maybe easier, you can move the delete call to onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
... //other onCreate() stuff
if(getIntent() != null && getIntent().hasExtra("deleteProduct")){
if (intent.getStringExtra("deleteProduct").equals("deleteProduct")) {
deleteProduct();
}
}
}
Also, you should be checking for
intent.getStringExtra("deleteProduct").equals("deleteProduct")
not ".equals("deleteProcust") as in your sample code, but I assume that's a typo.

Call a value from an OnClick method

I'm working on eclipse (android) and I want to call outside a variable that is in the OnClick method. How can I do that? I thought to use a return but OnClick is a void method. Here is my code
backgroundE2.setOnClickListener(new View.OnClickListener(){
public void onClick(View view){
int randomIntE = random2.nextInt(Deck.length());
int drawableIDE = Deck.getResourceId(randomIntE, -1);
backgroundE2.setBackgroundResource(drawableIDE);
}
});
I'm trying to call the variable randomIntE. How can I do that if everything is closed? I have to call also other 4 variables that are in different setOnClickListener.
You can use a global variable declared outside the function.
public class MainActivity extends Activity {
int fnsetFlag= 0;
backgroundE2.setOnClickListener(new View.OnClickListener(){
public void onClick(View view){
fnsetFlag= 1;
}
});
}
you should save it somewhere, like in an instance variable or in an object that can be called from the piece of code you want to use.
I hope to have understand the question properly.
Andrea.

How to get listener of a view

I write service that interacts with other apps. It registers listeners on views (buttons, textviews,...), that already have listeners. I need to replace them with my own listeners (works), do some stuff and then unregister my listeners and restore the old ones.
An App with a button with an onClickListener is running
My service registers an onClickListener inside the UI-Thread + do something
My service restores the old listener
It would be easy, if there was a view.getOnClickListener -method. Then I could save the old ones and replace the new listeners when I'm done.
Is there any way to get listeners from a view or have more that one listener of the same type bound to one view?
Button btn = (Button) findViewById(R.id.btn1);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//do something
}
});
// I need to do, but found no solution for that.
View.OnClickListener oldListener = btn.getOnClickListener();
If I register the new listeners to a view, the old ones are overridden, right? It would be also okay if both listeners ("new" and "old") exist at the same time. Only the old ones must not be gone.
edit: Unfortunately I have no possibility to save the listener on assignment. I need to get it backwards from the view component.
Thanks
Thanks to mihail's hint (thanks for that :)) )with the hidden API, I've found a solution to get a listener back after assignment:
The android.view.View class has a nested class static class ListenerInfo that stores all listeners on a View (API 14+). In older versions the listeners are private fields in the android.view.View.
The field can be accessed with reflection. In my case (API 14+),
// get the nested class `android.view.View$ListenerInfo`
Field listenerInfoField = null;
listenerInfoField = Class.forName("android.view.View").getDeclaredField("mListenerInfo");
if (listenerInfoField != null) {
listenerInfoField.setAccessible(true);
}
Object myLiObject = null;
myLiObject = listenerInfoField.get(myViewObj);
// get the field mOnClickListener, that holds the listener and cast it to a listener
Field listenerField = null;
listenerField = Class.forName("android.view.View$ListenerInfo").getDeclaredField("mOnClickListener")
if (listenerField != null && myLiObject != null) {
View.OnClickListener myListener = (View.OnClickListener) listenerField.get(myLiObject);
}
After that code (I missed a lot of try-catch-blocks), the myListener object holds the instance of the onClickListener, that has been anonymously declared to the view before. It also works with any other listener, just replace the "mOnClickListener parameter" with the one you need in the reflection and cast it correctly.
Note that code changes in upcoming versions can make that not working anymore.
Found the final tutorial here: http://andwise.net/?p=161
create classes that implements OnClickListener
public static class MyClickListener1 implements OnClickListener{
Activity mActivity;
MyClickListener1(Acivity activity){
mActivity=activity;
}
#Override
public void onClick(View v) {
//do something
}
}
public static class MyClickListener2 implements OnClickListener{
#Override
public void onClick(View v) {
//do something
}
}
and in your code you can easily use them:
btn.setOnClickListener(new MyClickListener1(this));
btn.setOnClickListener(new MyClickListener2());
or you can create instances and reuse them:
OnClickListener listener1 = new MyClickListener1(this);
OnClickListener listener2 = new MyClickListener2();
btn.setOnClickListener(listener1);
btn.setOnClickListener(listener2);
you can also define a constructor to pass whatever you need in these classes. I usually pass the activity like in MyClickListener1
EDIT: If you want to have the listener like object in the button, you can use the tag.
btn.setTag(listener1);
btn.setOnClickListener(listener1);
and then to get it use
OnClickListener old_listener = (OnClickListenr)btn.getTag();
Make two instances of OnCLickListener and assign first or second to button:
Button b = (Button) findViewById(R.id.Button1);
OnClickListener listener_new = new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("APP", "NEW CLICK LISTENER ACTIVE");
}
};
OnClickListener listener_old = new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("APP", "OLD CLICK LISTENER ACTIVE");
}
};
//setting listener
b.setOnClickListener(listener_old);
b.callOnClick();
//changing listener
b.setOnClickListener(listener_new);
b.callOnClick();
//return your old listener!
b.setOnClickListener(listener_old);
b.callOnClick();
ADDED:
OnClickListener is protected field of Button class, inherited from View class. Name of the field "mOnClickListener". I can't get it even through reflection.
void getListener(Button b) {
java.lang.reflect.Field field = getClass().getSuperclass().getSuperclass().getDeclaredField("mOnClickListener");
}
So You can't get existing listener of the Button if You don't have access to code where it created.
But if You have access to objects of Activity (and we know You have because setting new listener to button), You could add your button with your listener on that activity. Make existing button invisible. And than rollback when necessary.
public abstract class ReflectionUtils {
private static final String listenerInfoFieldName = "mListenerInfo";
private static final String onCLickListenerFieldName = "mOnClickListener";
public static OnClickListener getOnClickListener(View view){
Object listenerInfo = ReflectionUtils.getValueFromObject(view, listenerInfoFieldName, Object.class);
return ReflectionUtils.getValueFromObject(listenerInfo, onCLickListenerFieldName, View.OnClickListener.class);
}
public static <T> T getValueFromObject(Object object, String fieldName, Class<T> returnClazz){
return getValueFromObject(object, object.getClass(), fieldName, returnClazz);
}
private static <T> T getValueFromObject(Object object, Class<?> declaredFieldClass, String fieldName, Class<T> returnClazz){
try {
Field field = declaredFieldClass.getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(object);
return returnClazz.cast(value);
} catch (NoSuchFieldException e) {
Class<?> superClass = declaredFieldClass.getSuperclass();
if(superClass != null){
return getValueFromObject(object, superClass, fieldName, returnClazz);
}
} catch (IllegalAccessException e) {
}
return null;
}
}
Calling OnClickListener onClickListener = ReflectionUtils.getOnClickListener(myView); on myView will give you the myView's listener that you are looking for.

Call alertdialog in another .java file

I have one activity/java file (Browsefile.java) that would obtain the absolute path of the file. I want to pass this information to another java file for further processing (Sqlitefun.java). In the first stage, I just want to make sure the variable of file path is passed from Browsefile.java to Sqlitefun.java so I just create an alertdialog in the Sqlitefun.java file to test it. However, I have some issue on the context of the alertdialog object.
(As Sqlitefun.java would further perform i/o and Sqlite processing tasks, I prefer to put this in another file.)
Here are the codes for the files:
Browsefile.java
public class Browsefile extends ListActivity {
....
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browsefile);
findViews();
getDir(root);
}
....
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
File file = new File(path.get(position));
if (file.isDirectory())
{
if(file.canRead())
{
getDir(path.get(position));
}
else
{
selectpath = file.getAbsolutePath();
fpath.setText(selectpath);
}
}
else
{
selectpath = file.getAbsolutePath();
fpath.setText(selectpath);
}
}
private Button.OnClickListener importcsv = new Button.OnClickListener() {
public void onClick(View v) {
Sqlitefun firstClass = new Sqlitefun();
firstClass.getsAlertDialog(selectpath);
}
};
....
}
Sqlitefun.java
public class Sqlitefun {
private Context context;
public void getsAlertDialog(String filepath) {
new AlertDialog.Builder(context)
.setMessage(filepath)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
.show();
}
}
I have tried to use this, Sqlitefun.this to replace context in the line new AlertDialog.Builder(context) but none of this works. (Eclipse said The constructor AlertDialog.Builder(Sqlitefun) is undefined and did not allow me to compile. The above code did not have any error and allow me to compile, but there is a nullpointer exception for the Context.
I believe you need to show dialogs from the Activity you are currently in, so you would need to the put AlertDialog code in BrowserFile.
I'm not sure if this would work, but you could try passing the context from BrowserFile to SqliteFun and showing it there.
Additionally, if you're not set on using an AlertDialog, trying using a Toast notification instead. They generally do better when used outside of an Activity.
Edit: I don't think the following is the best way to implement what you are trying to do, but here is a code sample I wrote
In SqliteFun, modify your method as such:
public void getsAlertDialog(String filepath, Context mContext) {
new AlertDialog.Builder(mContext)
.setMessage(filepath)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
})
.show();
}
Then from your Activity, use this:
private Button.OnClickListener importcsv = new Button.OnClickListener() {
public void onClick(View v) {
Sqlitefun firstClass = new Sqlitefun();
firstClass.getsAlertDialog(selectpath, v.getContext());
}
};
Try this:
private Context context = getApplicationContext()
You need to give contex from activity you execute this method. So I suggest you to add constructor to Sqlitefun class and when you create object of this class add context to arguments.
There is something wrong in your app design.
You cannot really show a Dialog from another class than an activity class (well, you can, but it's very dangerous because the activity context can change anytime. For example when the device is rotated your app will crash because the activity context changed, since in Sqlitefun your reference still points to the old context).
So you should find another way to show your dialog. For example, you can create some getters to retrieve the values to show on your AlertDialog, and create it inside your activity.
First create a static variable in Sqlitefun.java.
Static String path;
After that you can access this variable from any class so you can directly store that path from Browse.class
Ex: You got the fullpath="XXXX" in browse.class. To store the fullpath variable in Sqlitefun.java use:
Sqlitefun.path=fullpath;

Categories

Resources