I am working on an android project, where i have got a list view to be populated. It happens in a group activity where intent is passed to a controller and from that controller the activity starts using specified intent.
In identifying the issue through debugging, i got that the debugger gets stuck in the line specified:
**View view = activityManager.startActivity(intentId, intent).getDecorView();**
and the list view never gets populated, however the when i check the array from which i have to populate items, that shows me that it contains the items. One interesting thing is that, when i close the application, and restart it and then see the list view, it shows up fine. This is strange for me. Why does it not show up first time and show up second time. the whole function has the following code:
public void startGroupActivity(String intentId, Intent intent) {
contentViewLayout.removeAllViews();
Log.e("Start Group Actvity", intentId);
View view = activityManager.startActivity(intentId, intent).getDecorView();
contentViewLayout.addView(view, contentViewLayoutParams);
}
That behavior is simply un-understandable for me. Any help is appreciated.
Related
I have a fragment, inside which there is a TextView and some Buttons.
I show the fragment, user clicks on a button, I hide the fragment and show a loading icon, contact server, get a new text and:
loading.setVisibility(View.VISIBLE);
mainContent.setVisibility(View.GONE);
http.post("https://domain/service?parameters",
new ParameterizedRunnable() {
text.setText(newTextFromServer)
loading.setVisibility(View.GONE);
mainContent.setVisibility(View.VISIBLE);
});
However, when the the main content view becomes visible after service call, I still see the previous text for a very short time, and then the new text is shown.
Why is it so? It seems that the text.setText line gets called, but maybe the device is slow and UI is not updated properly before mainContent.setVisibility line.
Am I missing some concept about android views and how they get rendered?
I'm a beginner in Android, so I apologize for the mistakes and I'd appreciate any constructive criticism.
I'm writing a basic application with a ListView of images, and when the user clicks on an item in the list, I want to display that image in a ViewPager, where the user can swipe back and forth to browse the whole list of images. Afterwards when the user presses the back button, I want to switch back to the ListView.
I manage the business logic in the MainActivity, which uses MainActivityFragment for the ListView and ImageHolderFragment for ViewPager.
The simplified code so far is as follows:
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListItems = new ArrayList<>();
mListItemAdapter = new ListItemAdapter(this, R.layout.list_item, R.id.list_item_name, mListItems);
mListView = (ListView) findViewById(R.id.list_view_content);
mListView.setAdapter(mListItemAdapter);
mDeletedListItems = new ArrayList<>();
mViewPager = (ViewPager) getLayoutInflater().inflate(R.layout.image_display, null, true);
mImageAdapter = new ImageAdapter(getSupportFragmentManager(), mListItems);
mViewPager.setAdapter(mImageAdapter);
mViewPager.setOffscreenPageLimit(3);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mViewPager.setCurrentItem(position);
setContentView(mViewPager); // TODO: this is very wrong!
}
});
loadImages();
noContentText = (TextView) findViewById(R.id.no_content_text);
if (mListItems.isEmpty()) {
noContentText.setText(R.string.no_images);
} else {
mImageAdapter.notifyDataSetChanged();
}
}
Although this does work to some extent, meaning that it manages to display the ViewPager when an item in the list is clicked, there are two things about it ringing the alarm bells:
I've read that calling setContentView() for the second time in the same class is pretty much a sin. Nobody explained me why.
The back button doesn't work in this case. When it's pressed, the application is terminated instead of going back to the list view. I believe this is connected to the first point.
I would appreciate any help, explanations if my idea is completely wrong, and if my case is hopeless, I'd like to see a successful combination of ListView and ViewPager with transitions between each other.
Your activity already has R.layout.activity_main set as content view, which rightly displays the list view - that's what the responsibility of this activity is as you defined it. If we want to change what's shown on the screen, we should use a different instance of a building block (activity or fragment) to display the view pager images.
To say the least, imagine if you wanted to change the view to a third piece of functionality or UI, or a fourth... it would be a nightmare to maintain, extend and test as you're not separating functionality into manageable units. Fields that are needed in one view are mixed with those needed in another, your class file would grow larger and larger as each view brings its click listeners, callbacks, etc., you'd also have to override the back button so it does what you want - it's just not how the Android framework was designed to help you. And what if you wanted to re-use UI components in different contexts whilst tapping in to the framework's activity lifecycle callbacks? That's why fragments were introduced.
In your case, the list view could continue to run in your MainActivity and in your click listener, onItemClick you could start a new activity that will hold a viewPager:
Intent i = new Intent(MainActivity.this, MyLargePhotoActivityPager.class);
i.putExtra(KEY_POSITION, position);
// pass the data too
startActivityForResult(i, REQUEST_CODE);
Notice how you could pass the position to this activity as an int extra, in order for that second activity to nicely set the viewPager to the position that the user clicked on. I'll let you discover how to build the second activity and put the ViewPager there. You also get back button functionality assuming your launch modes are set accordingly, if needed. One thing to note is that when you do come back to the list View, you'd probably want to scroll to the position from the view pager, which is why you could supply that back as a result via a request code. The returned position can be supplied back to the list view.
Alternatively, you could use the same activity but have two fragments (see the link further above) and have an equivalent outcome. In fact, one of your fragments could store the list view, and the second fragment could be a fullscreen DialogFragment that stores a viewPager, like a photo gallery (some details here).
Hope this helps.
I've read that calling setContentView() for the second time in the
same class is pretty much a sin. Nobody explained me why.
Well, you kind of get an idea as to why.
When you use setContentView() to display another 'screen' you do no have a proper back stack.
You also keep references to Views (like mListView) that are not visible anymore and are therefore kind of 'useless' after you setContentView() for the second time.
Also keep in mind orientation changes or your app going to the background - you'll have to keep track of the state that your Activity was in which is way more complicated than it has to be if you have one Activity that does two different things.
You won't be arrested for doing things like you do right now, but it's just harder to debug and keep bug free.
I'd suggest using two different Activities for the two different things that you want to do, or use one Activity and two Fragments, swapping them back and forth.
If you insist on having it all in one Activity you need to override onBackPressed() (called when the user presses the back button) and restore the first state of your Activity (setContentView() again, pretty much starting all over).
I have a GridView where each cell is a thumbnail, a filename and a checkbox. To populate the grid I use a CustomCursorAdapter:
The CustomCursorAdapter extends CursorAdapter.
I have a floating button that launchs the system camera. If I take a picture, the grid updates correctly with the new cell.
In the action bar I have a delete button. If I check one or more checkboxes and press the delete button the cell is/are correctly deleted.
But then I have also a ShareActionProvider button so you can check multiple cells and share them. And that works. BUT, here comes the problem. Imagine we have 3 or 4 cells. You check a couple of them, share them, and when you come back from the sharing dialog you see all the cells and you can see how all of them fade and disappear but one, the upper leftmost one.
I checked and saw that after the sharing dialog is the onResume method the one executed. The only thing I'm interested to be done in that method is to reset the checkboxes (a selected.clear() of the variable and a cb.setChecked(false) of each Checkbox view). Also I set the intent of the ShareActionProvider button for a empty selection (this will trigger a Toast: "Select first the images to share" if the button is pressed now).
#Override
public void onResume() {
if (shared) { //we come from a share
uncheck(); //unchecks the Checkboxes views
selected.clear(); //reset the selected items list
//getShareIntent returns an intent with the items in
//selected (now empty) as extras
Intent intent = this.getShareIntent();
if (intent != null && mShareActionProvider != null) {
mShareActionProvider.setShareIntent(Intent.createChooser(intent,
getResources().getText(R.string.send_to)));
}
shared = false;
}
super.onResume();
}
Removing the unchecking, reset and new intent setting don't affect to that behaviour, the cells disappear anyway. In fact, if I comment the whole onResume function the problem remains.
I tried with things like:
grid.invalidateViews();
mAdapter.notifyDataSetChanged();
grid.setAdapter(mAdapter);
Also tried and put the super as the first line, but then checkboxes, intent and list variable aren't updated.
Another clue is that if I press the thumbnail of the unique cell left visible (this loads a new activity to see the picture big size), then the disappeared cells appear for a second while the new activity is loading. o_O
I tried to press the places where the thumbnails should appear after the share to check if it launches the big display activity anyway, but that doesn't happen.
I read about similar things when scrolling GridViews but I just have three elements, no need to scroll. What could be happening here?
EDIT: To check if the issue was related to the memory and the thumbnails, I commented them in the item views, letting just the textview and the checkbox. But the problem is still there. Absolutely desperate -I've been days trying to fix this-I tried to relaunch the grid activity in the onResume, to try to force the redraw (while mAdapter.notifyDataSetChanged() worked when adding a new cell, never worked after the sharing):
#Override
public void onResume() {
super.onResume();
if (shared) {
shared = false;
Intent intClearStack = new Intent(
getBaseContext(),
GridActivity.class);
intClearStack
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intClearStack);
finish();
}t
}
I'm not proud of this solution but is the nearest thing I found to fix this. Nearest because, while it works almost all the time, ocasionally it doesn't. I'd like to know why there's a difference when it comes back from a ShareActionProvider activity and any other activity, to try to find out why this is acting like that.
I'm new to Android development.
I created a simple master-detail app that starts with a simple, vertical scrolling list of topics.
When the user selects a topic, a details screen appears, replacing the first screen, with a list of details that pertain to the selected topic.
I want the title for the details screen to show the topic the user has selected on the first page, but haven't been able to solve the problem after working for almost a week.
All I need to know is, Can this be done? Not looking for someone to solve this for me, but maybe a hint or a link to a tutorial that shows how this can be done.
Note: I'd post a drawing of what I want to do, but I'm new here and don't have 10 reputation yet.
Thanks,
SonCoder
Not exactly sure what you want but either way..
-You have a listview. Each view (the data) in the listview should be a represented by a model. (aka a separate class containing specific information that you want to represent for each listitem.
-Write a custom list adapter (extend from base adapter).
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
In the getView method of this class you load the the String field of the model that you want in the textview.
-Make sure to use the viewholder pattern in the adapter above. I noticed the example doesnt use one. This speeds up scrolling in the list because there are much fewer calls to findViewById.
-in the list activity set up a View onClick listener. This should create an intent (for launching an activity) or a fragment transaction (for fragments). Send the instance of your entire model (will get from
parent.getAdapter().getItem(position);
in the on click method) into the detail activity.
-if you want to set a textview title just get the textview and set it from the model. It will be the same filed you inflated in the getView method of the adapter.
-if you want to set the titile in the actionbar set:
this.getActionBar().setTitle(title)
This is simple. Just send extra data in the intent that starts the activity and then in the activity's onCreate read the data and then use the setTitle(myString) method from the activity.
setTitle(String title) can be called from anywhere using the activity by the way.
So, your in your listadapter, then you set a listener on your view right? A simple onClickListener on the whole "root" view is just fine.
In the listener you say something in the ways of this:
Intent intent = new Intent(myActivity, MySubActivity.class);
intent.putExtra(key, titleName);
myActivity.startActivity(intent);
Note that the activity reference should be set in the constructor of the adapter and that the "key" String is something you get from your strings.xml. Do not duplicate these in code since if you change one and forget to change the others you might get some wierd NPEs.
Continue in your MySubActivity's onCreate()
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String key = getString(R.string.my_title_key);
String title = intent.getString(key);
setTitle(title);
}
NOTE: I'm not sure of all method names are correct and such but something like this.
I'm working on an interface that provides a set of multiple Button objects, each of which has attached the same OnClickListener. When said Buttons are clicked, they should launch an Activity, as specified in onClick.
Here is my code for reference:
public class Calcs extends SherlockFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
CalcLoader buttonListener = new CalcLoader(getActivity());
LinearLayout buttons = (LinearLayout) v.findViewById(R.id.calculatorlist); // v is the inflated View
for (int i = 0; i < buttons.getChildCount(); i++) {
View b = buttons.getChildAt(i);
if (b instanceof Button) {
((Button) b).setOnClickListener(buttonListener);
}
}
// Test Code: Location 1
Intent i = new Intent(getActivity(), MyCalcActivity.class);
getActivity().startActivity(i);
// ...
}
private class CalcLoader implements OnClickListener {
private Activity mOwner;
public CalcLoader(Activity owner) {
mOwner = owner;
// Test Code: Location 2
Intent i = new Intent(mOwner, MyCalcActivity.class);
mOwner.startActivity(i);
}
public void onClick(View v) {
if (v instanceof Button) {
// Actual Code: Location 3
Intent i = new Intent(mOwner, MyCalcActivity.class);
mOwner.startActivity(i);
}
}
}
}
Despite this, however, I'm getting some odd behavior. In the above code, I've placed some startActivity tests, labelled locations 1 and 2. In both cases, the Activity launches correctly, and all is well!
However, at location 3, where the working code should execute, I get some strange behavior from the launched Activity:
At first, the Activity is launched just fine. It displays a single text field and it is focused, with the soft keyboard coming up. This is correct.
Now, when I click the back button, the keyboard closes. This is correct.
Click back again, and the field loses focus. This should NOT happen. Instead, the Activity SHOULD close and return to the previous one.
Click back again, and the entire app closes (instead of returning to the previous Activity). Obviously, this should NOT happen.
To reiterate, when the Activity is started from location 1 or 2, everything functions correctly; the back stack is correct and returns to the initial Activity properly.
What is going wrong here? Why, when I start my Activity from onClick, does it fail, while it works from any other location?
Update: Saving the Intent in the constructor and reusing it in the onClick method produces the same glitched result, as does starting the Activity from the UI thread.
Second update: Making the text field unfocusable had no effect on the glitch; the back button still closed the app. Additionally, running in the 2.3.3 emulator had the same result. Oddly, though, after the second back button press (the text field losing focus), if you wait ~3 seconds, the Activity closes and returns to the main one.
Third update: No key events (onKeyDown or onBackPressed) are fired for the back button that takes focus from the text field. Additionally, if you interact with the Activity after the text field loses focus, it shows the animation of loading a new Activity of the same type, but the glitch is present here as well.
This appears to be an OS-level issue, found in Android 2.2 (API 8), 2.3.1 (API 9), and 2.3.3 (API 10). Eclair (API 7), and APIs 11+ do not have this issue. At this point, I believe I'm looking for some kind of workaround...
Turns out my issue was not caused by something I detailed in my original post, so I apologize for that.
The issue was caused by a SurfaceView item on a tab unrelated to the tab I was testing on. After rebuilding the tabs and layouts from the ground up (and building each time), I discovered the lag-back-glitch was only caused when a SurfaceView was present in a non-focused tab.
I finally found that I was not the only one with this issue.
To solve:
Created an onPause method in the main Activity. In here, I destroy the SurfaceView using container.removeView(..);.
Created an onResume method in the main Activity. In here, I inflate the SurfaceView from a new XML file containing ONLY the SurfaceView item, and add it to the original container.
Lastly, implemented a android.view.SurfaceHolder.Callback in the SurfaceView to erase the contents of the surface before it is removed.
It stumps me that this happens only on APIs 8-10, but I'm glad it's solved now. Kudos to everyone that offered their assistance!