What to pass into LinearLayout constructor - java

Hi guys :) I am storing products for my android app in a Parse database and trying to load them up at run-time.
I want to create a LinearLayout in the 'done' method below but I am not sure how to pass the Context in the LinearLayout constructor. What do I put in the contructor's parameter?
Thank you!
public class BrowseActivity extends Activity {
//do stuff here
#Override
protected void onCreate(Bundle savedInstanceState) {
/*Get all services and packages from parse database*/
ParseQuery<ParseObject> query = ParseQuery.getQuery("InAppProducts");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> parseObjects, ParseException e)
{
if(e == null)
{
/*Add products to page*/
//What do I put where "this" is?
LinearLayout layout = new LinearLayout(this);
}
else{
}
}
});
}

Try using getApplicationContext() or BrowseActivity.this

You could use BrowseActivity.this or getBaseContext() here. But please don't use getApplicationContext() as other answers suggests. View's should be created with Activity context, then only it will get destroyed and garbage collected along with Activity.

Krishnabhadra is correct, passing an application context won't let the view garbage collected even if the activity gets destroyed. So use instead BrowseActivity.this or getBaseContext() to get Activity context.

Related

Dynamically Add and Save buttons in Android studio

Currently i managed to create the buttons dynamically on a view
Here is the my code to create the buttons;
public void Add_on(View v) {
AlertDialog.Builder mbuilder = new AlertDialog.Builder(Mb.this);
View mview = getLayoutInflater().inflate(R.layout.activity_mb1, null);
EditText number = (EditText) mview.findViewById(R.id.etnum);
Button Create = (Button) mview.findViewById(R.id.etcreate);
Button Cancel = (Button) mview.findViewById(R.id.etcancel);
Create.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
if (!number.getText().toString().isEmpty())
{
Toast.makeText(Mb.this, "Number can be NULL",Toast.LENGTH_SHORT).show();
LinearLayout yenilayout = new LinearLayout(Mb.this);
int n =1;
for(int i=0; i<n; i++)
{
Button yeniButton = new Button(Mb.this);
yenilayout.addView(yeniButton);
yeniButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(Mb.this, "Button is working",Toast.LENGTH_SHORT).show();
}
});
}
altlayout.addView(yenilayout);
} else {
Toast.makeText(Mb.this, "Number cannot be NULL",Toast.LENGTH_SHORT).show();
}
}
});
But whenever i recall the activity, the buttons are no longer exist. So May i know can i place the button there permanently?
Thank you for suggestions
You can use Bundle to save an activity's state and recreate it in the onCreate() method. This works for a particular instance of Activity, so can be used to save data concerning selection, or user input etc., but not data that you need to be persistent across application launches.
To use the Bundle, override the onSaveInstanceState(Bundle) and onRestoreInstanceState(Bundle) methods in the Activity class. You can use methods from Bundle to save whatever data you like in a map, and get it back in onRestoreInstanceState(Bundle), which is called in onStart().
The default implementations already handle most UI stuff though, and I would have thought this would keep track of your buttons for you, so it may be that your question is actually about associating some persistent data with your application. (this also means that if you do override the above methods, you should make sure to call the super methods in the first line of your implementation).
If you need persistent data across application launches, then the quickest and easiest way would be to use SharedPreferences, see this answer for an example.

Sharing objects through the app using the Application class

I am trying to define global objects using the application class.
I therefore define the following class.
public class MyApplication extends Application {
private MyObject myObject=new MyObject();
public MyObject getMyObject(){
return this.myObject;
}
}
Then, I use it in an activity, but I get an error (Cannot resolve method getApplication()):
public class AnActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mood);
Button buttonMusic=(Button) findViewById(R.id.button5);
buttonMusic.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)this.getApplication());
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
});
}
}
I have no clue why I get this error, as it for example works when calling the getApplication() in another activity.
I'm pretty new to Android and Java, so please excuse the ingenuity of the question.
UPDATE
Then I do MyObject myObject=myApplication.getMyObject(); and I don't get any compilation issue but the app dies as soon as I get in that activity.
As I understand it is not advised to use the Application class for such use, what would be a good alternative?
You're getting this error because you call this.getApplication() inside the View.OnClickListener. Because of this, this now references the listener and not the activity.
To do what you need, just create a Context object outside of the listener in your activity's onCreate method and assign this to it. And, inside the listener, use context instead of this. Something like this :-
public class AnActivity extends Activity {
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mood);
context = this;
Button buttonMusic=(Button) findViewById(R.id.button5);
buttonMusic.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)context.getApplication());//Changed "the" to "context"
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
});
}
}
Edit after question update :-
Instead of using the application class, use static objects to achieve global variables. static objects are independent of objects and can be referenced using the class that they belong to. For example, if you define a static variable in your MainActivity.class and name it testObject, then it can be accessed using the following code regardless of your current activity :-
YourObject object = MainActivity.testObject;
Unless you have a specific reason for extending the Application class in Android you probably shouldn't. For reference, look at the note in the documentation for this: https://developer.android.com/reference/android/app/Application.html .
If you are trying to create an object that you can use in your Android app, simply do that as you would in Java:
public class MyObject {
//Your stuff here
}
If there is a reason that you're specifically wanting to extend the Application class then perhaps there's more that people can do to help you if you explain what you're trying to do. I just don't necessarily see a need to go through all that complexity based on your example :)
Change this to AnActivity.this.
Inside the code below the meaning of this changes from AnActivity to View.onClickListener as it is another object and inside those braces you are in the scope of the click listener class
new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)this.getApplication());
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
}
So the code above should become
new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)AnActivity.this.getApplication());
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
}
You can read a bit more about it here

How can I let another class know that a button was clicked (Android Studio)

Below is the code which I'm using to return a number which should be 1 when the button is clicked. However when I try to get that number from another class, it always stays 0.
As you might recognize, I tried to change the number in the onClickListener and returned it below.
I also tried to use the onPause command so that it will return the number onPause but it still doesn't work.
public class MainActivity extends Activity {
public int number;
Button btnAngled;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
btnAngled = (Button) findViewById(R.id.btnAngled);
final Intent intent = new Intent(this, angledForeheadActivity.class);
btnAngled.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
number = 1;
startActivity(intent);
}
});
}
#Override
protected void onPause() {
super.onPause();
}
public int getNumber() {
return number;
}
}
I try to get the code in another class with:
MainActivity a = new MainActivity();
int number = a.getNumber();
Sorry for the noob question..
declare the variable as static variable. Then you can simply obtain the result you want since there is only one copy of that variable. If you want to pass the value using intent, you can call putExtra() of intent to carry information to another activity.
Intent reference page
What you actually want is getting the number from another Class. Don't mix the job with button click together. You should setup the concept of model to store data and seperate UI and data, UI just change/get the data.
I suggest you either of the two ways
Store the number in some global model, then you can get the number from another Class.
User Android Broadcast to transfer the data
Use static variable in Activity is not a good idea, it may cause memroy leak, though it can solve your problem.

Returning a thread result to the Fragment using interface implementation

I have an application that shows News articles in a listview inside a fragment.
When the fragment is first created, I start a thread that will fetch the list of articles (Stories) through an API call
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mContext = getActivity();
new GetStoriesThread(mContext,this).start();
Both the Fragment and the Thread implement the same Interface for passing the data from the thread to the Fragment
public interface GetStoriesThreadInterface {
public void onGetStoriesThreadResult(final ArrayList<Story> result);
}
After the Thread is done processing, it will call the interface method and pass the data back to the calling Fragment.
The problem
Now when I get the result in the fragment, through this code:
#Override
public void onGetStoriesThreadResult(final ArrayList<Story> result)
{
if(result!=null)
{
mStoriesList.clear(); //mStoriesList is the list that i supply to the adapter of the ListView
mStoriesList.addAll(result);
adapter.notifyDataSetChanged(); //Exception here
}
}
I get the following exception:
04-28 18:03:58.432: E/ViewRootImpl(21513): com.says.news.Stories : Only the original thread that created a view hierarchy can touch its views.
I know that using getActivity().runOnUiThread(new Runnable... solves the issue, but I dont understand why. And sometimes getActivity() returns null and that`s a whole different issue.
Thanks in advance !!
Are you calling onGetStoriesThreadResult() from within the working thread? You shouldn't. Consider using AsyncTask<> instead of bare Thread , override the onPostExecute() method and call your events from there.

LoaderCallbacks.onLoadFinished is not called when loader is resused and contains data

I have 1 activity and 2 fragments. Both fragments use a custom AsyncTaskLoader to get some data from a webservice and as i'm using a Loader it should keep the data across activity and fragment re-creations. Both fragments override the onActivityCreated method and calls getLoaderManager().initLoader(0, null, this) which either creates a new or reuses an existing loader.
When the activity is first created, it adds Fragment #1 in a FrameLayout by default, loads the data, internally calls LoaderCallbacks.onLoadFinished() method and displays the result. I have a button which replaces Fragment #1 with Fragment #2 on click and Fragment #1 is pushed to the fragment-backstack. When the user hits the BACK key, it switches back to Fragment #1.
onActivityCreated gets called again on Fragment #1 and then obviously calls iniLoader() again. This time the data already exists in the loader and i expect it to automatically call the LoaderCallbacks.onLoadFinished method again, because it already has data available, as described here: http://goo.gl/EGFJk
Ensures a loader is initialized and active. If the loader doesn't already exist, one is created and (if the activity/fragment is currently started) starts the loader. Otherwise the last created loader is re-used.
In either case, the given callback is associated with the loader, and will be called as the loader state changes. If at the point of call the caller is in its started state, and the requested loader already exists and has generated its data, then callback onLoadFinished(Loader, D) will be called immediately (inside of this function), so you must be prepared for this to happen.
But the method is never called even if the loader exists and has generated data ready to deliver.
Edit #1
The problem from a users perspective:
User starts activity and sees fragment1 with some data
User clicks something which changes the first fragment to another, with different
data
User hits the BACK key
User is now looking at fragment1 again, but there's no data. (which means i need to get it from the webservice again - and i'd like to avoid that if possible)
Here is my activity:
public class FragmentTestsActivity extends Activity implements OnClickListener {
private Button btn1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(this);
Fragment newFragment = new Fragment1();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, newFragment).commit();
}
#Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.btn1) {
showNewFragment();
}
}
public void showNewFragment() {
// Instantiate a new fragment.
Fragment2 newFragment = new Fragment2();
// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragmentContainer, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
}
My Fragment #1:
public class Fragment1 extends Fragment implements LoaderCallbacks<String> {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LoaderManager.enableDebugLogging(true);
getLoaderManager().initLoader(0, null, this);
}
private static class TestLoader extends AsyncTaskLoader<String> {
String result;
public TestLoader(Context context) {
super(context);
}
#Override
public String loadInBackground() {
// Some long-running call to a webservice - replaced with a simple string to test with
return "FirstTimeData";
}
#Override
public void deliverResult(String data) {
result = data;
if (isStarted()) {
super.deliverResult(data);
}
}
#Override
protected void onStartLoading() {
if (result != null) {
deliverResult(result);
}
if (takeContentChanged() || result == null) {
forceLoad();
}
}
#Override
protected void onStopLoading() {
cancelLoad();
}
}
#Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new TestLoader(getActivity());
}
#Override
public void onLoadFinished(Loader<String> loader, String result) {
Log.d("Fragment1", "onLoadFinished: " + result);
}
#Override
public void onLoaderReset(Loader<String> loader) {
// TODO Auto-generated method stub
}
}
Anyone know a solution to this or what i'm doing wrong here? Any help is greatly appreciated.
The correct answer, for me at least, was to move the entire Loader initialisation from onViewCreated or onActivityCreated to onStart.
After that it works fine!
From my point of view the onLoadFinished will only be called the first time cause the load has already finished, it finishes just once for both fragments. What you could do is to store the result in a property in the activity and check for it in the second fragment creation.
Update: After further investigation I found my original answer to be wrong. restartLoader will also destroy the loader if it already exists.
Nevertheless I solved my own problem. I create a standard CursorLoader in onCreateLoader and swap the cursor of my CursorAdapter in onLoadFinished. I needed to call initLoader after initializing the CursorAdapter. Now the data is still there when the fragment is returned from the backstack.
Original answer: I found two possible ways to solve this issue.
Apparently when initLoader(int id, Bundle args, LoaderCallbacks<D> callback) is called for the second time in onActivityCreated(Bundle savedInstanceState) after the Fragment is returned from the backstack, the method onLoadFinished(Loader<String> loader, String result) is never called (as you described).
However, a call to restartLoader(int id, Bundle args, LoaderCallbacks<D> callback) after or instead of initLoader will finally cause onLoadFinished to be called. To improve performance, I use a boolean argument to determine whether the Fragment is a new instance or not. Then I call restartLoader only if the Fragment is returned from the backstack.
As far as I can tell, old data persists in the loader and is not reloaded, but I'm not sure. The second possibility (especially when not using the backstack but instead creating a new Fragment instance in a transaction) is to call destroyLoader(int id) before the Fragment goes away (e.g in onPause).
I already had that issue, I can't really explain why that bug but I know that line :
getLoaderManager().initLoader(0, null, this);
don't work in my code, So you can changed it for that :
LoaderManager lm = getLoaderManager();
lm.initLoader(LOADER_ID, null, this);
The code start the methods :
onCreateLoader
you can try...

Categories