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.
Related
I have my code defined the way below. There are two crucial activities. Activity (1) shows some images in a ViewFlipper. It uses methods to load desired image directly. The onOptionsItemSelected() method fetches data from a menu defined within linked XML layout R.layout.browse. The other method, displaySelectedFlag(), gets a tag parameter passed from a different activity, let's call it activity (2).
Activity (1):
public class BrowserActivity extends AppCompatActivity implements SimpleGestureListener, View.OnClickListener {
public ViewFlipper vFlipper;
(...)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browse);
vFlipper = (ViewFlipper) findViewById(R.id.viewFlipperBrowser);
(...)
} // onCreate() ends here
// this method below works fine:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
vFlipper.setDisplayedChild(item.getOrder());
return true;
}
// and this one doesn't:
public void displaySelectedFlag(int orderTag) {
vFlipper.setDisplayedChild(orderTag); // crashes here
}
}
Activity (2):
public class ListActivity extends Activity implements View.OnClickListener {
private BrowserActivity browserActivity = new BrowserActivity();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
ImageButton imageA = (ImageButton) findViewById(R.id.img_a);
imageA.setOnClickListener(this);
ImageButton imageB = (ImageButton) findViewById(R.id.img_b);
imageB.setOnClickListener(this);
}
public void displayImageInfo(View view) {
String tagValue = (String) view.getTag();
int tagId = Integer.parseInt(tagValue);
Intent intent = new Intent(this, BrowserActivity.class);
startActivity(intent);
browserActivity.displaySelectedImage(imageId);
}
#Override
public void onClick(View view) {
displayImageInfo(view);
}
}
As I checked, the method onClick() called in activity (2) fetches an ID of an ImageButton and passes it to activity (1). Unfortunately, I get a NullPointerException when calling the ViewFlipper (the line is marked in the code above, activity (1)).
Any idea why it happens?
You cannot reference one Activity from another activity. You must let the Android OS create the Activity object via the call to "startActivity". Allocating a local variable as an instance of an Activity doesn't actually mean anything (like your instantiation of the BrowserActivity). Apoorv's comment links to a decent article on the subject.
If you want to pass data from one Activity to another, you need to pass extras within the Intent's bundle. This post goes into detail: https://stackoverflow.com/a/819427/504252
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
I'm using android annotations, I'm trying to annotate this class so that I can save a value into my shared preferences (annotated) class using #pref. I've managed to find a work around with an intent and a broadcast receiver however this is not ideal and now that I want to fetch a value from the shared preferences in this class to show as the default item selected in the spinner it's starting to leave a smell on my code.
Is there any way to annotate this class?
public class SelectNewsFeedDialog extends Dialog {
private Context context;
private Button confirmButton;
private Spinner spinnerTeams;
public SelectNewsFeedDialog(final Context context, ArrayList<Team> listTeams) {
super(context,R.style.cust_dialog);
this.context = context;
setContentView(R.layout.dialog_choose_news_feed);
spinnerTeams = (Spinner) findViewById(R.id.dialog_news_feed_spinner_teams);
confirmButton = (Button) findViewById(R.id.dialog_news_feed_button_confirm);
confirmButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Team team = (Team)spinnerTeams.getSelectedItem();
Intent intent = new Intent(context, IntentCenter_.class);
intent.putExtra(context.getString(R.string.extra_update_team_news_feed), team.url.toString());
intent.setAction(context.getString(R.string.action_update_team_news_feed));
context.sendBroadcast(intent);
dismiss();
}
});
SpinnerTeamsAdapter adapter = new SpinnerTeamsAdapter(context, listTeams);
spinnerTeams.setAdapter(adapter);
}
}
Currently, we haven't any annotation for Dialog classes. You may want to uses #EBean on this but the compiler is yelling on missing constructors.
The solution is to uses a DialogFragment instead of a Dialog and annotate this class with #EFragment. The following code should works :
#EFragment(R.layout.dialog_choose_news_feed)
public class SelectNewsFeedDialog extends DialogFragment {
#ViewById
Button confirmButton;
#ViewById
Spinner spinnerTeams;
#Extra
List<Team> listTeams;
#Click
public void confirmButtonClicked() {
Team team = (Team) spinnerTeams.getSelectedItem();
Intent intent = new Intent(context, IntentCenter_.class);
intent.putExtra(context.getString(R.string.extra_update_team_news_feed), team.url.toString());
intent.setAction(context.getString(R.string.action_update_team_news_feed));
context.sendBroadcast(intent);
dismiss();
}
#AfterViews
public void init() {
SpinnerTeamsAdapter adapter = new SpinnerTeamsAdapter(getActivity(), listTeams);
spinnerTeams.setAdapter(adapter);
}
}
However, using #Extra on a list is not a good idea. You should :
* use a list of ids annotated with #Extra
* or, uses a setter and passes this list to your adapter after the dialog was been initialized.
Hope this helps
I stuck at this issue many times and I passed the problem in different ways and I'm not sure that I made it in the right way.
I simplified the problem in a the following example. I know that I can pass only the data to the class but I do want to pass the editText cause I have this problem with more difficult UI controls.
mainactivity.java
public class mainactivity extends Activity {
public EditText clickEditText;
int count =0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
newTxt();
}
public void newTxt() {
txt = new MyText(context);
txt.updateTextEdit("Main Activity");
}
}
myText.java
public class MyText
{
private Context _context;
// constructor
public MyText(Context context)
{
_context = context;
}
public void updateTextEdit(String str)
{
private EditText strEditText;
strEditText= (EditText)findViewById(_context.R.id.editTextClick); // ????
strEditText.setText(str + " and myTxt");
}
}
if you could explain me how to fix the updateTextEdit function. i passed the context of the main activity. How can I change the editText? Thank you very much!!!
If you really want to do this this way, you need to save a reference to Activity, not Context. Like this:
public class MyText
{
private Activity _activity;
// constructor
public MyText(Activity activity)
{
_activity= activity;
}
public void updateTextEdit(String str)
{
private EditText strEditText;
strEditText= (EditText)activity.findViewById(R.id.editTextClick);
strEditText.setText(str + " and myTxt");
}
}
and in newTxt() you will need to change:
txt = new MyText(context);
to:
txt = new MyText(this);
But wouldn't it be easier to just put this method inside your activity? Why do you want it in another class? If it really needs to be in another class, you could make that class an inner class of your activity and you would still have access to the activity's methods and member variables.
There's a similar question here
How to access Activity UI from my class?
You didn't say how you obtained the context, you should use this and get the mainactivity in the other class. not context.
then you can call runOnUIThread to perform UI updates.
I want to use a button click to pass selection parameters to another class that will build a map screen using the passed parameters. I am focused on getting my button action working. I a using onCLickListener and onCLickView as follows
Class1:
public class Class1 extends Activity implements OnClickListener {
Class2 class2;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
..........
Button button = (Button)findViewById(R.id.btn_configup1);
button.setOnClickListener(this);
}
public void onClick(View v) {
Class2 class2 = new Class2();
//Save state.. selections and params and use bundle
//to pass into class2
class2.execMapBuild();
}
}
Class2:
public class Class2 extends MapActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.drawable.navup);
}
public void execMapBuild() {
finish(); //just in case we return.
Intent intent = new Intent(CLass2.this, Class2.class);
startActivity(intent);
}
I have everything working except the desired button action. I want the button click in Class1.onVlickView to call Class2.execMapBuild using the button click action. I have the button click capturing the action and calling the execMapBuild method on Class2. But I get a NullPointerException as it moves from startActivity(intent) into onCreate.
I have tried several other ways of nailing this down, but this seems the best and I seem close to figuring it out. I would really appreciate an explanation of what I may be missing.
Added code that was initially not copied in.
To expand on #Heiko Rupp's answer, if you want Class2 to display a map, it needs to extend something like Activity. As such, you can't just call it with a normal method. You need to register the Activity in your manifest and then call it using an Intent. Here is a sample of the kind of thing you should be doing:
public class Class1 extends Activity implements OnClickListener {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Button button = (Button)findViewById(R.id.btn_configup1);
button.setOnClickListener(this);
}
public void onClick(View v) {
Intent intent = new Intent(Class1.this,Class2.class);
intent.putExtra("key","data");
...
startActivity(intent);
}
}
public class Class2 extends MapActivity {
String mData;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Bundle extras = getIntent().getExtras();
if (extras != null) {
mData = extras.getString("key");
...
}
...
}
}
Can I also suggest that you use more descriptive class names than Class1 and Class2.
Class2 is no activity, so the callbacks of an Activity will not be called by the system.
And if it were an Activity, you could not just call into it via new Class2(), as still the callbacks are not executed.
Try to clean this up and then start Class2 activity from Class1 with an Intent as you are doing within execMapBuild().