Hey I am having trouble declaring, changing, and using a global variable. I tried the whole "make a class that extends your application and put variables there" thing but I'm not sure how to implement it. Here is my class with the variable in it.
public class MyApp extends Application {
public int listPos;
}
I then tried to access and change int listPos here.
public class Browse extends ListActivity{
MyApp app = ((MyApp)getApplicationContext());
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] coffeeTypes = getResources().getStringArray(R.array.coffeeTypes);
setListAdapter(new ArrayAdapter<String>(this, R.layout.listview, coffeeTypes));
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
app.listPos = position;
startActivity(new Intent(Browse.this, CoffeeTypes.class));
}
});
}
}
Then I tried to access the variable in the following activity to determine the outcome of an if else statement
public class CoffeeTypes extends Activity{
MyApp app = ((MyApp)getApplicationContext());
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(app.listPos == 0){
Toast.makeText(this, "WEEEEEEE!0", Toast.LENGTH_LONG).show();
}
else if(app.listPos == 1){
Toast.makeText(this, "RAWR!1", Toast.LENGTH_LONG).show();
Anyone have any idea what I am doing wrong?
You can use soorya's answer with some modifications. I would personally still use your myApp class but change listPos to static and access it that way. Doing it this way lets you use the Application class onCreate method to initialize values if needed (though it won't be needed in this example) or other Android methods.
public class MyApp extends Application {
public static int listPos;
}
//~~ Elsewhere:
MyApp.listPos = 5; //etc
But this isn't the best way to handle your type of problem.
You should be passing the list position information (or the id of the item clicked or however you are handling your data) via the Intent.
Instead of having a global variable to track this information, keep it local to just the Intent:
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//app.listPos = position;
Intent intent = new Intent(Browse.this, CoffeeTypes.class);
intent.putExtra("position", position);
startActivity(intent);
//startActivity(new Intent(Browse.this, CoffeeTypes.class));
}
This passes the position data to the new Activity via the intent. In your CoffeeTypes Activity you should start with something along the following:
//in onCreate...
int incomingPosition = getIntent().getIntExtra("position",-1));
if(incomingPosition != -1) { //do stuff }
This will read the "position" data from the incoming Intent so you can use it. The -1 above is the default value if nothing is added.
One final warning: you might want to be careful sending the list position back and forth, depending on how your application is set up if new items are added/items are deleted the list position might no longer refer to the item you thought it did. If these coffee types/whatever you are using have a separate unique ID that might be more appropriate to avoiding the above situation, consider using that instead.
I'm not sure if it's a visibility issue with the android OS, are you able to make an public functions that may be able to act as getters for the variable?
int getListPos(){ return this.listpos; }
I know that you can pass variables between contexts, you may have to do that.
Perhaps a temporary workaround to get you moving could be creating a static class of accessible variables too?
Create a class like this
class globalClass
{
static int lastPos;
}
You can set values using
globalClass.lastPos = value;
and get function is
int myVal = globalClass.lastPos;
i do Application variable classes by making the variables private, and then create public get() and set() methods to change the variables. you can try that, but it seems like you are doing it right, technically
one reason why it might be going wrong is because you are implementing the stuff in onCreate and not onStartCommand. if you are testing this function with the wrong assumptions/knowledge of the Activity cycle, it could go wrong
Related
Greetings from a greenhorn. This question is a bit long, sorry for that.
My android app loads xml to the listview, then after clicking any listview item I want to pass some information to second activity. With
piesneLVdata.getItemAtPosition(position).toString()
And here is my object:
public class Piesen {
private String nazov_piesne;
private String text_piesne;
}
+ some get and set methods and override of toString...
I can access the first property of the object and I can use it in my second activity. I guess it is because I have overriden the method inside my object definition:
#Override
public String toString() {
return nazov_piesne;
}
However I am not able to access the second property of my object. Tried this:
piesneLVdata.getItemAtPosition(position).getTextPiesne()
but getTextPiesne() seems not to be reachable - then why the "toString()" is reachable? The information is there, I can access it outside of the onClickListener with this formulation:
zoznamPiesni.get(position).getText_piesne().toString();
but when I try to use it in onClickListener I get the error:
Error:(64, 45) error: local variable zoznamPiesni is accessed from within inner class; needs to be declared final
But then, when I declare it final I cannot load a xml file into it. I feel officialy stucked in there. Maybe I should redesign the toString() method to contain an array of both properties of my object. Could you please point me to the correct direction? Thanks a lot in advance.
To be specific, here is my activity:
public class ListActivity extends AppCompatActivity {
ListView piesneLVdata;
Toolbar nadpis;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
nadpis = (Toolbar) findViewById(R.id.toolbar);
nadpis.setTitle(getResources().getString(R.string.nadpis));
piesneLVdata = (ListView) findViewById(R.id.piesneLVgui);
List<Piesen> zoznamPiesni = null;
try {
XMLPullParserHandler parser = new XMLPullParserHandler();
zoznamPiesni = parser.parse(getAssets().open("piesne.xml"));
//sort the collection piesne alphabetically a-z
Collections.sort(zoznamPiesni, new Comparator<Piesen>() {
#Override
public int compare(Piesen a1, Piesen a2) {
// String implements Comparable
return (a1.getNazov_piesne().toString()).compareTo(a2.getNazov_piesne().toString());
}
});
ArrayAdapter<Piesen> adapter = new ArrayAdapter<Piesen>(this,android.R.layout.simple_list_item_1,zoznamPiesni);
piesneLVdata.setAdapter(adapter);
}catch (IOException e) {
e.printStackTrace();
}
piesneLVdata.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent slovaIntent = new Intent(ListActivity.this, SongActivity.class);
Bundle balik = new Bundle();
balik.putString("NAZOV", piesneLVdata.getItemAtPosition(position).toString());
//balik.putString("TEXT", piesneLVdata.getItemAtPosition(position).getTextPiesne());
// balik.putString("TEXT", zoznamPiesni.get(position).getText_piesne().toString());
slovaIntent.putExtras(balik);
startActivity(slovaIntent);
}
});
}
The problem is that
piesneLVdata.getItemAtPosition(position)
return a Piesen treated as an Object. Object has toString method, so yo ucan call that method, that is overriden by the Piesen.class.
What you need is simply cast your object to a Piesed like follows:
((Piesen)piesneLVdata.getItemAtPosition(position)).getTextPiesne()
I'm implementing a list which needs to be displayed by an activity and modified (add items, remove items, sort) by the user. Currently I have two different classes - the activity class and the list class which has all the operations on the list. However, the activity class is going to need access to the list in order to adapt and display it, and it seems kind of clumsy to either duplicate the list for the activity or make the list public. I get the feeling I might not be understanding what activities are correctly - should my two classes really be one single class? I assumed activities were mostly for UI, not for modifying the underlying datastructure.
Activities are the main building blocks of Android, all the different screens that you see in your Application are Activities. You should understand that not all Java Classes used in your Android App are Activities (only those Java Classes that extends Activity are Activities).
The Java Classes that are not Activity (used in your code) can be simply plain Data Models, Custom Adapters, Custom Views, Database Handlers, Services, and so on.
All these Java files are used separately from the Activity Class to provide Modularity and to avoid creating a Mess and deficiency by implementing all the Functionality in a Single Activity Class.
You use the instances of these other Java Classes (or use them statically) in your Activity Class.
For Displaying a Simple List, you can use ListView widget, and you don't really need a separate class for it's implementation. Likewise, if you are preparing to implement a ListView with functionality such as Delete, Add, Update, etc. Then Custom ListView is the alternative option that you can use.
You cannot implement a Custom List View in a single Activity Class, you will be needing a Custom Adapter Class, a Custom Data Model Class and other related classes for it's implementation.
Here is a list of some useful tutorials for implementing Simple and Custom ListViews:
Vogella's ListView Tut
The Open Tutorials
Android Example 1
Android Example 2
I hope this helps.
I'm implementing a list which needs to be displayed by an activity and modified (add items, remove items, sort) by the user.
You can do the simple operations defined by the List<T> interface like add, remove, etc. You can write a custom Comparator<T> to perform sort operations. Then use the Collections.sort() method to do your work.
Currently I have two different classes - the activity class and the list class which has all the operations on the list.
It depends. I generally prefer to make a singleton instance of the list and let my activity modify it on callbacks from ListView. There is nothing clumsy about letting your Activity handle the addition or removal from list.
However, the activity class is going to need access to the list in order to adapt and display it, and it seems kind of clumsy to either duplicate the list for the activity or make the list public.
Like I said, look up what a Singleton Instance is. Share your list across multiple activities by creating a class that has the list in it. Declare the list public. That way, you share the list and do not duplicate it. Remember: if you duplicate the data multiple times. keeping them in sync is going to be a tough nut to crack.
Think about it like that. Your oncreate is called once. If you need things done on the list, they will most probably be on your onItemClick, onItemLongClick kinda events. And when that happens, you should call a AsyncTask, coded in your same activity, so that the onPostExecute can modify its UI elements and the list. Some example below.
Note, the code below has been reduced bigtime, so excuse syntax
package com.taxeetaregistration;
public class Bookings extends ListActivity implements OnClickListener, OnItemClickListener {
private static LayoutInflater inflater = null;
private LinkedList<BookingRecord> bookingRecord;
private ListView customerList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bookings);
Log.d("Taxeeta", "Entered BookingExperience");
bookingRecord = new LinkedList<BookingRecord>();
customerList = (ListView) findViewById(android.R.id.list);
customerList.setAdapter(new CustomerList());
customerList.setOnItemClickListener(this);
getBookings = new GetBookings();
getBookings.execute();
}
public class CustomerList extends BaseAdapter implements OnClickListener {
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null || convertView.getTag() == null) {
convertView = inflater.inflate(R.layout.bookingresponse_row, null);
final CustomerViewHolder viewHolder = new CustomerViewHolder();
viewHolder.customerRow = (LinearLayout) convertView.findViewById(R.id.customerRow);
viewHolder.customerName = (TextView) convertView.findViewById(R.id.customerName);
viewHolder.customerPhoneNumber = (TextView) convertView
.findViewById(R.id.customerPhoneNumber);
convertView.setTag(viewHolder);
}
// Setting all values in listview
String temp = bookingRecord.get(position).customer.getFullName();
((CustomerViewHolder) (convertView.getTag())).customerName.setText(temp);
temp = bookingRecord.get(position).customer.getPhoneNumber();
((CustomerViewHolder) (convertView.getTag())).customerPhoneNumber.setText(temp);
return convertView;
}
public class GetBookings extends AsyncTask<Object, Integer, Object> {
#Override
protected Object doInBackground(Object... params) {
connectToServer();
//Do all network related work here, and update
publishProgress(j);
}
}
return null;
}
#Override
public void onPostExecute(Object result) {
super.onPostExecute(result);
if (bookingRecord != null && bookingRecord.size() > 0) {
busy.setVisibility(View.GONE);
((BaseAdapter) customerList.getAdapter()).notifyDataSetChanged();
} else {
progressBarUpper.setVisibility(View.GONE);
Log.d("Taxeeta", "No cabbies found");
}
}
#Override
protected void onProgressUpdate(Integer... i) {
super.onProgressUpdate(i);
boolean found = false;
customersFound.setText("" + totalCabbiesSubscribed);
BookingRecord newRecord = new BookingRecord();
newRecord.customerJourney = customerJourney;
newRecord.customer = customer;
bookingRecord.addLast(newRecord);
customersConfirmed.setText("" + bookingRecord.size());
}
}
private class CustomerViewHolder {
public LinearLayout customerRow;
public TextView customerName;
public TextView customerPhoneNumber;
public TextView customerFrom, customerTo;
public ListView cabbieList;
public float distanceFromCustomer = -1.0f;
}
public class BookingRecord {
public BookingRecord() {
cabbies = new ArrayList<CabbieDetails>();
}
public IJourneyDetails customerJourney;
public IUserDetails customer;
public SearchResultsConcrete cabbieList;
public ArrayList<CabbieDetails> cabbies;
}
}
I want to pass one or more variables between activities in android. One solution is to use global variables, and it is explained here:
Android global variable
which I repeat here:
You can extend the base android.app.Application class and add member variables like so:
public class MyApplication extends Application {
private String someVariable;
public String getSomeVariable() {
return someVariable;
}
public void setSomeVariable(String someVariable) {
this.someVariable = someVariable;
}
}
Then in your activities you can get and set the variable like so:
// set
((MyApplication) this.getApplication()).setSomeVariable("foo");
// get
String s = ((MyApplication) this.getApplication()).getSomeVariable();
I want to use this and set a global variable in one of my activities when an item on a ListView is pressed. So I have this code:
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
.
.
.
((MyApplication) this.getApplication()).setSomeVariable("foo");
}
});
However I get an error which says "The method getApplication() is undefined for the type new AdapterView.OnItemClickListener(){}".
I would like to know what is the reason I get this error and how to fix it, or a better way of passing a variable from one activity to the other.
Thanks,
TJ
Inside an Anonymous Class you cant say this. u have to specifi the Class around the inner class.
like MyApplication.this.get..
when using:
class MyApplication {
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
((MyApplication) MyApplication.this.getApplication()).setSomeVariable("foo");
}
}
}
the "this." inside an annoymous inner class refering to the inner class itself.
Any particular reason you are not using Intent's? http://developer.android.com/guide/topics/fundamentals/activities.html#StartingAnActivity
You have the use MyClass.this.getApplication() if you've define the anonymous OnItemClickListener in a member function of MyClass. OnItemClickListener does not know about the application.
I don't think you need to cast it... Application is already there.
MyApplication.getSomeVariable();
should work just like any other class.
I am trying to write an Activity that has some views, a fillView() method that sets the views (which is not static because it must utilize getContentResolver), and a static method that makes a random choice from a cursor and then runs the fillView() method.
I had problems with this due to fillView not being static and pickRandom being static, so I tried to initialzize an instance of the class, but now it crashes on the line instance.fillView();
Sample code below. Any help would be appreciated. Perhaps there is a much easier way to accomplish what I am trying to do.
Thanks,
Josh
public class myView extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.myView);
fillView();
}
public void fillView(){
//creates views, runs cursor and applies results to the view created
}
public static void pickRandom() {
// runs cursor, picks random entry, next I want to apply the result to
// view, so I run...
myView v = new myView();
v.fillView();
}
Make a static instance variable and set in in oncreate:
private static myView instance;
oncreate()
instance = this;
static pickrandom()
instance.fillView();
in your pickRandom you try to create new instance of your class. Instead of this you should do the following:
this.fillView();
I don't see any purpose you have your pickRandom static.
If, however, you need it for some reason you can pass a reference to your view like this:
public static void pickRandom(myView v) {
// runs cursor, picks random entry, next I want to apply the result to
// view, so I run...
v.fillView();
}
Having developed many desktop GUI apps (from Xt to Qt, Java Awt/Swt/Swing, etc) I really find it difficult to get used to Android.
Suppose I have the MainView Activity class which explicitly calls DetailedView via intent mechanism as shown next:
Since an Activity class is instantiated via onCreate() how do I
customize it? (No constructor, only
pass data through intent!)
Is there a way to get a reference for the DetailedView instance in
MainActivity?
Is there a way to get a reference for the MainActivity instance in
DetailedView?
How can I pass the reference to FrontEnd to the DetailedView class?
Intent.putExtras() allows only for
certain data types to pass to the
intent receiver class.
MainActivity {
...
FrontEnd fe;
...
public void onCreate(Bundle savedInstanceState) {
...
Intent myIntent = new Intent(this, DetailedView.class);
...
}
protected void onListItemClick(ListView l, View v, int position, long id) {
...
startActivityForResult(myIntent,..);
...
}
}
One way of passing simple data between activities/services of a specific app is to use the SharedPreferences functionality of android.
This may not be the most elegant code to get the job done, but I routinely create a static "utility" class in my Android projects to allow for 1 line get and set of simple data types via shared preferences
private static final String PREFERENCE_FILE_NAME = "com.snctln.util.test.SharedPreferencesFile";
private static final String BOOL_VALUE_ONE = "bValueOne";
public static boolean getBooleanValue1(Context context)
{
SharedPreferences prefs = context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);
return prefs.getBoolean(BOOL_VALUE_ONE, true); // return true if the value does not exist
}
public static void setBooleanValue1(Context context, int appWidgetId, boolean actualvalue)
{
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE).edit();
prefs.putBoolean(BOOL_VALUE_ONE, actualvalue);
prefs.commit();
}
I frequently cheat and use static 'getInstance' calls to communicate between Activities and views. This works as long as they're both in the same proc, and I've yet to have a data access failure...but I'm sure it's only a matter of time...IF you're looking for a hacky quick fix this could be it, otherwise you have to pass data through intents.