I have defined a HomeActivity with three tabs and each tab is a seperate activity.I used the example in the android developer site. http://developer.android.com/resources/tutorials/views/hello-tabwidget.html
Tab B's (second tab) UI conatins a text and button (named Search).When the user clicks the search button,it should contact a REST webservice and show the results as a list.
In Order to do this,inside TAB B activity,on the click of the button,i call a method which creates an intent and calls a new SearchResultsActivity(referring as SRA henceforth).Inside the SRA(extends List Activity),i have the logic for connecting to the webservice and parsing the JSON result returned which displays the results as a list.I am able to achieve this functionality.But i see some drawbacks here and my questions are:
Is it fine to define a new activty (SRA) to handle the search results? or would it be better to have it handled in TAB B activity itself?The main reason why i went for a seperate activity is,the SRA extends ListActivity which would be needed if i want to display it as List and TabB is just extending Activity and wouldnt allowme to display teh results.So,is there a better way to do this?
Given the above implementation,when i navigate from TabB (click search button) to SRA,the tabs are not seen anymore.As TabB is calling a new activity(
Intent srchIntent = new Intent(TabB.this, SearchResultActivity.class);
TabB.this.startActivity(srchIntent);),the tab goes away.What could be the best solution in this case so that the tabs appear/results shown within Tab B ?
While navigating from TabB to SRA,i am trying to show a Progress dialog/Loading defined in TabB before calling StartActivity and cancel it afterwards.But the loading icon does not appear.I have tried showing the dialog and canceling in SRA as well.But the loading does not appear.
Hey Bala, what i have to say is:
1) It would be best to extend the TAB B as a ListActivity and the search done by a helper class. This way you are making your code more independent.
2) Implement 1) and you will be ok.
3) You should show a progress dialog when you start the request, and stop it when you got results. I would implement a broadcast receiver to achieve that (I can help you out, if you choose to do that).
There are two approaches to achieve this goal..
Whenever you make start your another activity (i.e. search activity), just before that set your search activity to your desired tab. You can achieve this by taking a instance of your TabActivity (i.e. your activity which is extending this class) and calling new Intent().setClass(TABACTIVITY_INSTANCE,ACTIVITY YOU_WANT_TO_SET_TO_THIS_TAB). But make to make the different objects of intent as member class .. Don't do something like this (new Intent().setClass()).
Declare the no of intent objects as no of Tabs you are holding and then use setClass method.
(This will solve your problem of the tab disappearing)
Now for taking data from server, I suggest you to implement AsyncTask (wonderful api available on Android):
private class DownloadImageTask extends AsyncTask<String, Void, String>
{
AbousUsHandler aboutHandeler;
#Override
protected void onPreExecute()
{
mProgress.setMessage("Please wait");
mProgress.show();
super.onPreExecute();
}
protected String doInBackground(String... urls)
{
/* Do you your background task i.e. getting data from server
but don't do ui related things here as this method is called in Thread
pool not on Android Ui thread.*/
return null;
}
protected void onPostExecute(String result)
{
try
{
mProgress.dismiss();
/* set Your List View Adapter here */
}
}
}
Execute this from your UI thread only by calling new DownloadImageTask().execute().
First preExecute will be called and then doInBackground and when you get your data from the server, onPostExecute will be called.
I hope this solves your problem.
Related
I have an app that hold post information in an activity. in this activity related posts listed in bottom of post. User by clicking on related post can go to post activity and see that post info and related posts too.
As you can see in image, I have Activity A that holds post and it's related posts. When user Click on post I send user to Activity A with new post id and fill activity by new data.
But I think this is not Right way!
should I used Fragment instead of Activity?
Opening another Instance of an Activity on top of another is simplest way of navigating a content graph. User can simply press back, and go to previously opened content, until user reaches back to starting Activity, then the application closes. Though pretty straight forward, this particular approach has two issues:
It may happen that a lot of Instances of same activity are on the stack, utilising a large amount of device resources like memory.
You don't have a fine grained control over Activity Stack. You can only launch more activities, finish some, or have to resort to intent flags like FLAG_CLEAR_TOP etc.
There is another approach, that re-uses the same Activity instance, loads new content in it while also remembering the history of content that was loaded. Much like a web browser does with web page urls.
The Idea is to keep a Stack of content viewed so far. Loading new content pushes more data to stack, while going back pops the top content from stack, until it is empty. The Activity UI always displays the content from top of the stack.
Rough Example:
public class PostActivity extends AppCompatActivity {
// keep history of viewed posts, with current post at top
private final Stack<Post> navStack = new Stack<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get starting link from intent extras and call loadPost(link)
}
private void loadPost(String link){
// Load post data in background and then call onPostLoaded(post)
// this is also called when user clicks on a related post link
}
private void onPostLoaded(Post post){
// add new post to stack
navStack.push(post);
// refresh UI
updateDisplay();
}
private void updateDisplay(){
// take the top Post, without removing it from stack
final Post post = navStack.peek();
// Display this post data in UI
}
#Override
public void onBackPressed() {
// pop the top item
navStack.pop();
if(navStack.isEmpty()) {
// no more items in history, should finish
super.onBackPressed();
}else {
// refresh UI with the item that is now on top of stack
updateDisplay();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
// cancel any background post load, release resources
}
}
I would choose:
activity/fragment depends on complexity with:
horizontal recyclerview with custom expanded card view
and inside this expanded card view second vertical recyclerview :)
Here's what you can try.
Create a PostActivity which is a shell for fragments. Inside this activity you can just replace fragments using FragmentTransaction.
Your PostActivity can now have a PostFragment which will hold post and related posts. Now on click of post you can replace PostFragment with PostDetailFragment with postID being sent to the new fragment as a bundle. The PostDetailFragment will now display details according to id.
Check here: http://www.vogella.com/tutorials/Android/article.html#components_fragments
By seeing the picture the way i would implement is i would have create an activity with a bottom listview for your items and on top there would be a framelayout for holding fragments . when user click on any list item i would load the respective fragment in the activity
It all depends on what you are trying to achieve. What would you expect to happen when the user touches the back button after going down a couple of levels? If you want to the application to exit, no matter how deep in the sequence they have gone, then the best solution in my opinion is to simply reload the same activity with the new data and invaliding the affected views. If you need the back button to take the user back to the previous data, then the next question would be if you are keeping track of the past data breadcrumb. If so, then just intercept the back button and load the previous data for as long as there is data in your stack, or exit if you get to the top. If you don't want to keep track of the previous data chain, then instead of loading one activity with the new data, you can start a new activity of the same class, but with the new data. Android with keep the track of activities and each back button touch would close the running activity and take the user to the previous activity. Choice of activity versus fragment is just yours. You can use fragments that hold the data that you want to change after each user touch, create new ones when needed, disconnect the previous ones, and connect the new ones. You will need to do some extra work to make sure the back button works correctly (depending on you want the back button to behave). Based on what I can tell, it is simpler to just have one activity and load new data when needed and keep a trail of data changes, if you need to be able to go back.
It can be achieved using activity alone. Though I preferred moving all related UI to fragment.
You can use Navigator class.
Here the steps:
1. Add Navigator Class
public class Navigator {
private static Navigator instance;
public synchronized static Navigator getInstance() {
if (instance == null) {
instance = new Navigator();
}
return instance;
}
public void navigateToActivityA(Context context) {
Intent activity= AActivity.getCallingIntent(context);
context.startActivity(activity);
}
}
2. Add the calling method to your Activity class.
public static Intent getCallingIntent(Context context) {
return new Intent(context, AActivity.class);
}
3. Call the activity with the following code in your caller activity.
Navigator.getInstance().navigateToActivityA(this);
I suggest that you read about AndroidCleanArchitecture
For this task...
0) Starting new activity
I read again about question, and understood that you need advice for starting activity. So, starting new activity it's Ok, your main problem will be with another things (see below).
But lets talk about starting another data. Using Fragment instead doesn't resolve your task, fragments helps with different screen work. Using for example just data refreshing as a variant. You may use just single activity and refresh only data, it will look much better, if you also add animation, but not better than starting activity.
Using Fragment helps your with different screen actions. And maybe, answering on your question - it will be most suitable solution. You just use single acitivity - PostActivity, and several fragments - FragmentMainPost, FragmentRelated - which will be replaced, each other, by selecting from related post.
1) Issues with returning back
Lets imagine, that users clicks to new one activity and we loaded new data. It's Ok, and when Users clicks over 100 activities and receiving a lot of information. It's Ok, too. But main question here it's returning back (also another about caching, but lets leave it, for now).
So everyone know, it's bad idea to save a lot of activities in stack. So for my every application, with similar behavior we override onBackPressed in this activity. But how, lets see the flow below:
//Activities most have some unique ID for saving, for ex, post number.
//Users clicks to 100 new activities, just start as new activity, and
//finish previous, via method, or setting parameter for activity in AndroidManifest
<activity
noHistory=true>
</activity>
....
//When activity loaded, save it's activity data, for ex, number of post
//in some special place, for example to our Application. So as a result
//we load new activity and save information about it to list
....
// User now want return back. We don't save all stack this activities,
// so all is Ok. When User pressing back, we start action for loading
//activities, saved on our list..
.....
onBackPressed () {
//Getting unique list
LinkedTreeSet<PostID> postList =
getMyApplication().getListOfHistory();
//Getting previous Post ID based on current
PostID previousPostID = postList.get(getCurrentPost());
//Start new activity with parameter (just for ex)
startActivity(new Intent().putExtra(previousPostID));
}
RESULT
I found this as the best solution for this tasks. Because in every time - we work only with single activity!
[Update Solution]
Referring to the post in the link
ViewPager PagerAdapter not updating the View
public void onSomeButtonClicked(View view) { // registered to Button's android:onClick in the layout xml file
Log.w(TAG,"Some button clicked !!");
getIntent().setAction(IntentManager.Intents.ACTION_SPAWN_LIST_BY_SOMETHING);
mViewPager.getAdapter().notifyDataSetChanged();
}
// And inside my PagerAdapter
#Override
public int getItemPosition(Object object) {
return 0;
}
Fixed all my problems, i just used Intent.setAction().
[Update to below Post]
My problem is i have a ViewPager PagerAdapter in my Main Activity. On clicking one of the 3 buttons., any specific intent will be fired (i used intent, i could have gone with just State variable as well, just that i pass some Uri with the intent). What happens is., i do
public void onSomeButtonClicked(View view) { // registered to Button's android:onClick in the layout xml file
Log.w(TAG,"Some button clicked !!");
getIntent().setAction(IntentManager.Intents.ACTION_SPAWN_LIST_BY_SOMETHING);
mViewPager.getAdapter().notifyDataSetChanged();
}
This is why i was guessing maybe i should just do startActivity again, with the new Intent Action on the same Activity.
Spawning a new Activity, i would have to redraw every other view in the layout which is basically the same code, for the most part in the current activity.
Any suggestions here? Please help
[Original Post]
I have a PagerAdapter and 3 Buttons in the my Main Activity. This activity is enter from Main Launcher.
When i press any one of the buttons, the Intent Action is changed.
My question:
The changed Intent action reflects some changed view in the ViewPager and does_not spawn a new Activity as such, only the view is updated.
What approach should i take to get this task?
Can i start the currentActivity using startActivity() and different Intent actions on button click?
or is there any other efficient way in android to do this?
[No need code, just explanation of logic / method would suffice]
Thanks in advance
If you are saying that you are trying to use startActivity to bring up the same activity again, and its not working, it could be because you set something like singleTop in your Android manifest.
If you are asking whether or not you should use an intent to change the state of your Activity, then the answer is "it depends". If the user would expect the back button to return your app to its previous state (instead of going back to the home screen), then it might be a good choice for you. If that is the case, however, I would ask why not just make 2 different Activities? Otherwise, just do as Dan S suggested and update the state of your Activity as the user interacts with it.
You can always use the onNewIntent() hook. Do something like this in your activity:
protected void onNewIntent(Intent intent){
//change your activity based on the new intent
}
Make sure to set the activity to singleTop in your manifest. Now whenever startActivity is called the onNewIntent() will be executed. Also, note that per the documentation:
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
I am trying to implement item click listener on my list in my main class that extends Activity, because for some reason if i extend ListActivity and expand my list with setListAdapter, the app force closes on startup, but if i extend Activity and expand it with setAdapter it runs fine.
Now my problem is i cannot find a way to implement a click listener for my list, I have tried implementing it in the custom ListAdapter.
The list clicks are going to open another activity which has another list.
------Updated------
#Override
public void run() {
// call any new activity here or do any thing you want here
final Intent intent = new Intent();
if(selectedListItem == 0) {
intent.putExtra("value1", "value1");
intent.setClass(this, com.lister.listexample.ListexampleActivity.class);
}
startActivityForResult(intent, selectedListItem);
}
Change ListView background - strange behaviour
check the above link where i mentioned a list example. that will enable you to trick down your list problems.
Try making a sample project first by copy pasting the above example. then you will be able to understand the answer better
Hope it helps :)
I currently have a tab layout with 2 tabs, one tab with a list view and one with the option make strings so I can add them in the list view. Both tabs have their own activity because this made the code much more structured, and I dont have to repeat my self later.
Lets say im in the tab that offer me to create an string, and i press the update list button, how do I update the list view without startActivity()? If i use startActivity(), it starts List.java, and instead of displaying the list in the list view tab, it takes full screen, which defies the purpose of the tab view. In other words, the startActivity() steals the focus from the tab view of the list, and sends it fulscreen.
Thanks for your time.
Edit: I want to update the activity in my list view tab, without starting a new activity that goes to fullscreen, and doesnt update the one in the tab.
One solution is to have your data model separate from your view (Activity), this is good practice in general, but in this case allows your two tabs to interact with the same model.
You could provide access to the data model in your Application class. Then, when onResume is called on your list activity you can update the view based on the current data.
edit:
public class MyApplication extends Application {
private List<MyObject> myData;
public List<MyObject> getMyData() {
return myData;
}
public void setMyData(List<MyObject> mydata) {
this.myData = myData;
}
}
In your manifest you need to add the application tag to specify that it should use MyApplication as the application class.
Then, in your activity:
public void onResume() {
MyApplication app = (MyApplication) getApplication();
List<MyData> data = app.getMyData();
// update my view with the data
}
I had the same problem when i was making my app and the only solution i found was to add this flag to my intent so every time i go to the tab it would refresh it self
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
I hope it helps.
I have a simple application, it starts, loads xml feed from the net, you can browse a list of news and then read details for a chosen news item. What I would like to do is have a splash screen, meaning as soon as you click application, it should display an image (app name in my case) and then display news list only after they've loaded.
I read about similar (I think) problems, and usually people say to use FrameLayout, but I can't really sort it out. I'm not sure if this can be done in the first activity that is launched, maybe I should just display this splash image in one activity and only then call activity displaying my news list?
I know that on iPhone you can set splash screen in app settings while developing, would be nice to have this functionality in android's app's manifest...
Android suggests you take advantage of using a splash screen when performing lengthy calculations on start up. Here's an excerpt from the Android Developer Website - Designing for Responsiveness:
"If your application has a time-consuming initial setup phase, consider showing a splash screen or rendering the main view as quickly as possible and filling in the information asynchronously. In either case, you should indicate somehow that progress is being made, lest the user perceive that the application is frozen." -- Android Developer Site
You can create an activity that shows a Progress Dialog while using an AsyncTask to download the xml feed from the net, parse it, store it to a db (if needed) and then start the Activity that displays the News Feeds. Close the splash Activity by calling finish()
Here's a skeleton code:
public class SplashScreen extends Activity{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// set the content view for your splash screen you defined in an xml file
setContentView(R.layout.splashscreen);
// perform other stuff you need to do
// execute your xml news feed loader
new AsyncLoadXMLFeed().execute();
}
private class AsyncLoadXMLFeed extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute(){
// show your progress dialog
}
#Override
protected Void doInBackground(Void... voids){
// load your xml feed asynchronously
}
#Override
protected void onPostExecute(Void params){
// dismiss your dialog
// launch your News activity
Intent intent = new Intent(SplashScreen.this, News.class);
startActivity(intent);
// close this activity
finish();
}
}
}
hope that helps!
I know this is old but for those of you who are still facing this problem, you can use this simple android-splash library to show your splash screen.
SplashBuilder
.with(this, savedInstanceState)
.show();
You can set SplashTask that will execute while the splash screen is displayed.