Basicly I have very same code as described here http://www.learn2crack.com/2013/12/android-swipe-view-tab-layout-example.html:
In each of the fragments I have different asynctask, that just fetches data from website. Fragment class looks like this :
Code:
TextView text;
String content;
View today;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
today = inflater.inflate(R.layout.today, container, false);
text = (TextView) today.findViewById(R.id.textView);
// ((TextView) today.findViewById(R.id.textView)).setText("Today");
new RetriveSiteData().execute("http://menza.lupajz.eu/?den=dnes");
content = (String) text.getText();
return today;
<here is the asynctask, too long >
}
I am wondering if the data is always fetched, while swiping through fragments if the TabPagerAdapter class (on the website) has this method implemented the same way
Code:
@Override
public Fragment getItem(int i) {
switch (i) {
case 0:
//Fragement for Android Tab
return new Android();
case 1:
//Fragment for Ios Tab
return new Ios();
case 2:
//Fragment for Windows Tab
return new Windows();
}
return null;
}
In case if the data is always fetched and the asynctask is always executed how can I prevent that ? Maybe adding some onResume() methods to each fragment ?
What is the best solution just to make connection to website, fetch data once and then just keep displaying them while I am swiping between fragments ?
lupajz said:
Basicly I have very same code as described here http://www.learn2crack.com/2013/12/android-swipe-view-tab-layout-example.html:
In each of the fragments I have different asynctask, that just fetches data from website. Fragment class looks like this :
Code:
TextView text;
String content;
View today;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
today = inflater.inflate(R.layout.today, container, false);
text = (TextView) today.findViewById(R.id.textView);
// ((TextView) today.findViewById(R.id.textView)).setText("Today");
new RetriveSiteData().execute("http://menza.lupajz.eu/?den=dnes");
content = (String) text.getText();
return today;
}
I am wondering if the data is always fetched, while swiping through fragments if the TabPagerAdapter class (on the website) has this method implemented the same way
Code:
@Override
public Fragment getItem(int i) {
switch (i) {
case 0:
//Fragement for Android Tab
return new Android();
case 1:
//Fragment for Ios Tab
return new Ios();
case 2:
//Fragment for Windows Tab
return new Windows();
}
return null;
}
In case if the data is always fetched and the asynctask is always executed how can I prevent that ? Maybe adding some onResume() methods to each fragment ?
What is the best solution just to make connection to website, fetch data once and then just keep displaying them while I am swiping between fragments ?
Click to expand...
Click to collapse
Yes, that data is always fetched since onCreateView is always called when a Fragment which hasn't been in layout appears, whether it was already instantiated or not. Have a look at the diagram on the right here for better understanding on how the specific methods are called. The dumb solution would be to put that code into the constructor, but Google suggests not doing anything there and instead using onCreate, which is also only called once.
Instead it might be better to just fire up the tasks for each Fragment (maybe sequentially as well) in the Activity, but that depends on how much data you are loading here, since the user might be switched to the page you are loading at the very end.
Thanks for answear yea I was looking at the fragment google site and I guessed that was the problem, but I am not getting the second part.
Instead it might be better to just fire up the tasks for each Fragment (maybe sequentially as well) in the Activity, but that depends on how much data you are loading here, since the user might be switched to the page you are loading at the very end.
Click to expand...
Click to collapse
I am just getting about 30+ lines of pure text, so it is not that big.
lupajz said:
Thanks for answear yea I was looking at the fragment google site and I guessed that was the problem, but I am not getting the second part.
I am just getting about 30+ lines of pure text, so it is not that big.
Click to expand...
Click to collapse
What I meant was that if you need to load much data over a possibly slow connection and do it in a specific order (meaning start with one category, then when that's finished the next one and so on) it might be that the user is swiping to the last category that will load and has to wait untill all other have been loaded. This is what speaks against loading everything in the activity and then reloading the Fragments with their specific content, but of course this is not the case with just a few lines of text . That would be the the way I would do it (load everything in the onCreate() of the activity and pass it to the Fragments) if there is little to medium data to load since you don't have to open an internet connection everytime the user swipes thus swiping will be much smoother (or it won't show a ProgressBar like that stupid xda-app ).
If it is data that you don't need to reload more than once every day, you can think about cashing it as well!
Related
Hey all,
I'm a new Droid developer (but long time Java programmer) and have been playing around with writing some apps. I've managed to get my first app working really well but have hit a snag. The program, which lets me view recent PVP comics, works like this:
1. Download the RSS from PVP
2. Parse the RSS to pull out comic links
3. Show the most recent comic (download it if needed) and allow user to view previous comics
Everything works fine. However, there is one thing that I just can't seem to figure out how to stop. The download of the RSS and image files take place in threads. In order to get the RSS immediately on load I put my method call in the onCreate() method. This works great. However, every time I rotate the phone, it seems like everything resets itself and reloads the RSS again.
I tried using a global boolean variable "first" which gets set to false when I first load the RSS, but when the phone is rotated it goes back to true. I'm obviously missing something in terms of how applications work on the android, but have been unable to find any work-arounds.
Any suggestions for me? I'm at a loss.
Thanks for any help.
Matthew
PS. Here's the basic structure of the code:
Code:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// set up all the appropriate listeners and layout stuff
loadRSS(); // this is the method that I only want to call the first time
}
I tried the following with no luck:
Code:
private boolean first = true;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// set up all the appropriate listeners and layout stuff
if (first)
{
first = false;
loadRSS(); // this is the method that I only want to call the first time
}
}
onCreate() is fired everytime the activity is loaded. If you rotate the phone you are basically reloading the activity. Put a breakpoint on the onCreate() method and you should see it get called when you rotate.
Thanks, I had seen that with a breakpoint. Is there any solution or best practice to get around it? Downloading and parsing the RSS file is a fairly expensive process (a few seconds) and I'd rather not do it except when needed (I can't cache the RSS file like I do the images as it will change over time). However, I don't want to have to click a "get it now" button on starting the app but would rather the program know to do this the first time it loads and then not again. Is there anything that allows you to either store some value in a variable that isn't reset on the "onCreate()" method or some other method that the first call should be put in (e.g. "onStartup()"...completely made that name up).
Thanks,
Matthew
I'm new to this as well, but this seems like something that you should use this Class for:
http://developer.android.com/reference/android/os/AsyncTask.html
I think you are not considering the Activity lifecycle. I don't see a problem to call LoadRSS() each time onCreate is called (probably onResume() is a better place), because LoadRSS() should spawn a thread to retrieve the RSS. If the Activity is destroyed by Android you want to keep the Thread handle to continue running the loading, you can do that saving it with onRetainNonConfigurationInstance() and restore the thread handle calling getLastNonConfigurationInstance() when the Activity is resumed, remember it could be another instance of the activity.
Code:
private Thread _rssThread;
public void OnCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// set up all the appropriate listeners and layout stuff
LoadRSS();
}
private void LoadRSS() {
_rssThread = (Thread)getLastNonConfigurationInstance();
if (_rssThread == null) {
_rssThread = new Thread(... )
}
}
public Object onRetainNonConfigurationInstance() {
return _rssThread ;
}
Probably you want to do something similar with the actual RSS already loaded, and put some logic in the Thread to update the RSS instead to reload all.
I like the suggestion of basically caching the RSS and loading from there. the Activity should basically check if it has already downloaded the RSS and just 'reload' it locally instead of downloading it again.
Failing that, why don't you just force landscape mode only since this is a comic anyway?
Unconn
What you need to do is handle configuration changes within your activity.
First, update your activity tag in the AndroidManifest.xml like so:
Code:
<activity android:name=".MyActivity"
android:configChanges="keyboardHidden|orientation">
...
</activity>
That's all you need to do to prevent your activity from being recreated with each configuration change.
If you need to update something, such as reloading the layout for an orientation change, just override the onConfigurationChanged method like so:
Code:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.myactivity);
...
}
Randroid. said:
What you need to do is handle configuration changes within your activity.
First, update your activity tag in the AndroidManifest.xml like so:
Code:
...
That's all you need to do to prevent your activity from being recreated with each configuration change.
If you need to update something, such as reloading the layout for an orientation change, just override the onConfigurationChanged method like so:
Code:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.myactivity);
...
}
Click to expand...
Click to collapse
this is correct
That worked perfectly! Thanks a lot for the help.
Hi,
Im using a content provider to query data, the following code was working good until I test it in another device(low end) with a larger data(~3000). With a larger data app became unusable, what can I do for improve this?
Code:
public void ContentSearch(String uriS,String id)
{
Uri uri = Uri.parse(uriS);
Cursor cur = getContentResolver().query(uri, NULL,
"_id = " + id, null, null);
cur.moveToFirst();
do {
//Do Things
} while (cur.moveToNext());
cur.close();
}
try to put it in a thread:
Code:
new Thread(new Runnable() {
[user=439709]@override[/user]
public void run() {
//CODE GOES HERE
}
}).start();
You do this for anything that might take the system a long time to execute and isn't directly needed for the UI.
If it is needed by the UI try an AsyncTask:
Code:
AsyncTask<Params,Progress,Result>() {
[user=439709]@override[/user]
protected Result doInBackground(Params params) {
}
protected void onProgressUpdate(Progress progress) {
}
protected void onPostExecute(Result result) {
}
}.execute();
I never used Content Providers so I'm not sure what you would put in for each thing on the Async but here is the Android Docs perhaps you can figure it out
Im filling an array to inflate in listview, my approach is load 25 items then break, and when the list reaches the end load more 25 and so on, but it seems that the cursor is in the same overloaded.
I need it for the UI so I dont have sure if the thread solve the problem, but I will try it anyway.
avlisF said:
Im filling an array to inflate in listview, my approach is load 25 items then break, and when the list reaches the end load more 25 and so on, but it seems that the cursor is in the same overloaded.
I need it for the UI so I dont have sure if the thread solve the problem, but I will try it anyway.
Click to expand...
Click to collapse
You fill the array then you fill the list? This might be what's causing our crash as the list is trying to setup before the array is done.
You could just use the async to do the lookup and set the list item info in the list adapter and as the async finishes each lookup it will enter each item in the list
Sent from my Nexus 7 using XDA Premium HD app
I just discovered how to use the action bar to have a OptionsMenu. I just solved a problem with it and I wanted to know if I did it the right way.
What I did
So, I added the menu to a fragment started by an activity, adding to it the setHasOptionsMenu(true) in the onCreate method and setting up the two convenience methods public void onCreateOptionsMenu() and public boolean onOptionsItemSelected() of course setting up the xml first.
The problem
Now, if I rotate my device in landscape mode the button in the action bar duplicates. If I put it in portrait mode again, the number of items stays the same (I'm sure it doesn't actually increase, checked the size in different ways) though.
What I thought and how I solved it
So, I was thinking about some fragment overlaps, but if they actually overlap then I shouldn't notice anything, right?
Is the menu being recreated, while not destroyed when the fragment is destroyed?
I solved the problem removing the item in the menu, in the Fragment.onDestroy() method manually.
Is the menu supposed to be cleared manually, or there is something wrong with my code (eg. fragments overlapping, etc..) ?
domenicop said:
Is the menu supposed to be cleared manually, or there is something wrong with my code (eg. fragments overlapping, etc..) ?
Click to expand...
Click to collapse
Could you please post your code? That would make helping much easier.
nikwen said:
Could you please post your code? That would make helping much easier.
Click to expand...
Click to collapse
Of course. Thanks for the interest.
This is the onCreate method of MainActivity.java, from where I handle the arrangement of fragments on the screen.
Also, place check my comment under the line "Log.d(TAG, "Orientation Portrait detected.");", where I try to explain why I handle fragments in that specific way. It's the way I understood it, but I'm not sure if that's correct.
Code:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Initialize the mDatabase
mContactsDatabase = ContactsDatabase.getInstance(getApplicationContext());
// Determine device orientation
mDualPane = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
// Set the fragment that will be changed
mFragmentToReplace = mDualPane ? R.id.contactsPagerFragmentContainer : R.id.portraitFragmentContainer;
// Set up the GUI
FragmentManager fm = getSupportFragmentManager();
if (!mDualPane) {
Log.d(TAG, "Orientation Portrait detected.");
// First, look for previously saved fragments
// findByFragmentId(int id) look for the fragment that was previously associated
// to the resource that has for id the argument passed in. Then, we try to cast it
// to the type of fragment we want, and if that goes all right, we have our fragment.
// Else, null will be returned.
mContactListFragment = (ContactListFragment) fm.findFragmentById(R.id.portraitFragmentContainer);
if (mContactListFragment == null) {
mContactListFragment = ContactListFragment.newInstance(mContactsDatabase);
fm.beginTransaction()
.replace(R.id.portraitFragmentContainer, mContactListFragment)
.commit();
}
}
else {
Log.d(TAG, "Orientation Landscape detected.");
// First, look for previously saved fragments
mContactListFragment = (ContactListFragment) fm.findFragmentById(R.id.landscapeFragmentContainer);
mContactsPagerFragment = (ContactsPagerFragment) fm.findFragmentById(R.id.contactsPagerFragmentContainer);
if (mContactListFragment == null) {
mContactListFragment = ContactListFragment.newInstance(mContactsDatabase);
fm.beginTransaction()
.replace(R.id.contactListFragmentContainer, mContactListFragment)
.commit();
}
if (mContactsPagerFragment == null) {
final int FIRST_CONTACT_POSITION = 0;
mContactListFragment = ContactListFragment.newInstance(mContactsDatabase);
mContactsPagerFragment =
ContactsPagerFragment.newInstance(FIRST_CONTACT_POSITION, mContactsDatabase);
fm.beginTransaction()
.replace(R.id.contactsPagerFragmentContainer, mContactsPagerFragment)
.commit();
}
}
}
This are the relevant pieces of the ContactListFragment.java, that have something to do with the menu
Note that I changed the way I checked for double menu entries.
Now I check if (menu.size() != 1), because I have just one item in there.
If I remove that clause, there will be two item in the menu after rotating to landscape mode, and if I take the device back to portrait mode, the two items will remain two. That's so even if I change from landscape to portrait and vice versa a hundred times from now, the menu items will always be two.
Code:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
Bundle args = getArguments();
mDatabase = (ContactsDatabase) args.getSerializable(DATABASE);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (menu.size() != 1) {
inflater.inflate(R.menu.contact_list_fragment_menu, menu);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addContactMenu:
mCallback.onAddContactMenuOptionSelected();
default:
return super.onOptionsItemSelected(item);
}
}
domenicop said:
I just discovered how to use the action bar to have a OptionsMenu. I just solved a problem with it and I wanted to know if I did it the right way.
What I did
So, I added the menu to a fragment started by an activity, adding to it the setHasOptionsMenu(true) in the onCreate method and setting up the two convenience methods public void onCreateOptionsMenu() and public boolean onOptionsItemSelected() of course setting up the xml first.
The problem
Now, if I rotate my device in landscape mode the button in the action bar duplicates. If I put it in portrait mode again, the number of items stays the same (I'm sure it doesn't actually increase, checked the size in different ways) though.
What I thought and how I solved it
So, I was thinking about some fragment overlaps, but if they actually overlap then I shouldn't notice anything, right?
Is the menu being recreated, while not destroyed when the fragment is destroyed?
I solved the problem removing the item in the menu, in the Fragment.onDestroy() method manually.
Is the menu supposed to be cleared manually, or there is something wrong with my code (eg. fragments overlapping, etc..) ?
Click to expand...
Click to collapse
I agree with nikwen but broadly the idea is...
- the menu belongs to the Activity not the Fragment.
- for an Activity for which you'd like an options menu you override onCreateOptionsMenu and do 2 things...
1/ call menu.add(...) for each menu item
2/ return 'true' at the end, so that your menu can be displayed
Also, see the Activity docs for onCreateOptionsMenu()
"This is only called once, the first time the options menu is displayed.
To update the menu every time it is displayed, see onPrepareOptionsMenu(Menu)."
If you want to add menu options to the Activity menu from within a Fragment you can also..
- override setHasOptionsMenu() in Fragment to return true
- override onCreateOptionsMenu() to add any items you like (just like you did at the Activity level)
- override onDestroyOptionsMenu()
The key thing here is that onCreateOptionsMenu() in Fragment is adding to the Activity menu.
It's hard to see without debugging exactly what's going on here but watch for calls to all of the above methods in Activity and Fragment and that will probably tell you what's going on.
If it is possible to control all menu options at the Activity level instead of the Fragment level, I would do that.
If not, and you need to use the Fragment menu methods, beware of Android's Fragment management (saving / restoring state)
Also, make sure your Fragments have an ID and/or tag.
(from the docs..)
"The fragment being instantiated must have some kind of unique identifier so that it can be re-associated with a previous instance if the parent activity needs to be destroyed and recreated. This can be provided these ways:
If nothing is explicitly supplied, the view ID of the container will be used.
android:tag can be used in <fragment> to provide a specific tag name for the fragment.
android:id can be used in <fragment> to provide a specific identifier for the fragment."
Finally, if all else fails, using Menu's findItem() before calling add() would be a safeguard, I suppose.
---------- Post added at 10:14 PM ---------- Previous post was at 09:52 PM ----------
domenicop said:
Of course. Thanks for the interest.
Click to expand...
Click to collapse
Sorry caught in the crossfire - have only just seen your code.
I think much of the above applies.
Set the menu up in the Activity instead of the Fragment, if you can.
I would also consider using layout-port and layout-land to control your two different layouts.
PicomatStudios said:
I agree with nikwen but broadly the idea is...
- the menu belongs to the Activity not the Fragment.
- for an Activity for which you'd like an options menu you override onCreateOptionsMenu and do 2 things...
1/ call menu.add(...) for each menu item
2/ return 'true' at the end, so that your menu can be displayed
Also, see the Activity docs for onCreateOptionsMenu()
"This is only called once, the first time the options menu is displayed.
To update the menu every time it is displayed, see onPrepareOptionsMenu(Menu)."
If you want to add menu options to the Activity menu from within a Fragment you can also..
- override setHasOptionsMenu() in Fragment to return true
- override onCreateOptionsMenu() to add any items you like (just like you did at the Activity level)
- override onDestroyOptionsMenu()
The key thing here is that onCreateOptionsMenu() in Fragment is adding to the Activity menu.
It's hard to see without debugging exactly what's going on here but watch for calls to all of the above methods in Activity and Fragment and that will probably tell you what's going on.
If it is possible to control all menu options at the Activity level instead of the Fragment level, I would do that.
If not, and you need to use the Fragment menu methods, beware of Android's Fragment management (saving / restoring state)
Also, make sure your Fragments have an ID and/or tag.
(from the docs..)
"The fragment being instantiated must have some kind of unique identifier so that it can be re-associated with a previous instance if the parent activity needs to be destroyed and recreated. This can be provided these ways:
If nothing is explicitly supplied, the view ID of the container will be used.
android:tag can be used in <fragment> to provide a specific tag name for the fragment.
android:id can be used in <fragment> to provide a specific identifier for the fragment."
Finally, if all else fails, using Menu's findItem() before calling add() would be a safeguard, I suppose.
---------- Post added at 10:14 PM ---------- Previous post was at 09:52 PM ----------
Sorry caught in the crossfire - have only just seen your code.
I think much of the above applies.
Set the menu up in the Activity instead of the Fragment, if you can.
I would also consider using layout-port and layout-land to control your two different layouts.
Click to expand...
Click to collapse
Wow. thanks for that detailed answer. :good: (Why have I used all my thanks?)
I've always put it into the Activity as well but it might make sense to add it to the Fragment sometimes. For example if you need the same Fragment in multiple Activities...
In that case you'd need to add a listener to the item in the Fragment method though.
@PicomatStudio Thank you for the detailed answer, I really appreciate that =)
Now I'm creating the menu in the activity and I don't have to worry about the fragments life cycle anymore.
The only problem is: I didn't get the menuInflater for free here, I guess it's because of the fact that in the Fragment scenario, I had to use the Activity inflater, whereas here in the activity, I can get my own, with getMenuInflater().
Here's the way I modified it, now is in MainActivity.java.
Please report back if you find something strange
Code:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (getSupportFragmentManager().findFragmentByTag(CONTACT_LIST_FRAGMENT) != null)
getMenuInflater().inflate(R.menu.contact_list_fragment_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addContactMenu:
onAddContactMenuOptionSelected();
default:
return super.onOptionsItemSelected(item);
}
}
domenicop said:
@PicomatStudio Thank you for the detailed answer, I really appreciate that =)
Now I'm creating the menu in the activity and I don't have to worry about the fragments life cycle anymore.
The only problem is: I didn't get the menuInflater for free here, I guess it's because of the fact that in the Fragment scenario, I had to use the Activity inflater, whereas here in the activity, I can get my own, with getMenuInflater().
Here's the way I modified it, now is in MainActivity.java.
Please report back if you find something strange
Code:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (getSupportFragmentManager().findFragmentByTag(CONTACT_LIST_FRAGMENT) != null)
getMenuInflater().inflate(R.menu.contact_list_fragment_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.addContactMenu:
onAddContactMenuOptionSelected();
default:
return super.onOptionsItemSelected(item);
}
}
Click to expand...
Click to collapse
I don't tend to use MenuInflater (just menu.add()..)
But looking at the docs it takes a Context so could you do..
Code:
new MenuInflater(this);
.. from your Activity ?
On a general design point the less your Activity depends on its Fragments the better, I reckon.
domenicop said:
The only problem is: I didn't get the menuInflater for free here, I guess it's because of the fact that in the Fragment scenario, I had to use the Activity inflater, whereas here in the activity, I can get my own, with getMenuInflater().
Click to expand...
Click to collapse
Well, you can get one:
Code:
getActivity().getMenuInflater();
I've been trying to learn to program for Android lately by simply coming up with ideas and implementing them. It started out easy enough with pulling information from an online RSS feed and showing this in a nice environment. But the current idea has me stumped.
I'd like the following to happen:
Take a picture using intent
Entire picture is shown in a new activity
Zoom in on a certain spot
Add predefined items to the picture
Press next which connects the items from left to right
Add some more items
Press next to connect the new items
Zoom out
Save the image
First taking a picture, this wasn't too hard using the camera intent:
Code:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
I can then extract the absolute path from fileUri with the following line:
Code:
String path = new File(fileUri.getPath()).getAbsolutePath();
This path can be put in a bundle which can be put in an intent which is then used to start the activity that should show the image.
Code:
public class TestActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = TestActivity.class.getSimpleName();
private String path = "";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SurfaceView view = new SurfaceView(this);
setContentView(view);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
path = bundle.getString("path");
view.getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Canvas canvas = holder.lockCanvas();
if (canvas == null) {
Log.d(TAG,"Can't draw because canvas is null");
}
else {
Bitmap bitmap = BitmapFactory.decodeFile(path);
Paint paint = new Paint();
if(bitmap == null) {
Log.d(TAG,"Can't draw because bitmap is null");
}
else {
canvas.drawBitmap(bitmap,0,0,paint);
}
holder.unlockCanvasAndPost(canvas);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int frmt, int w, int h) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
The first issue here is that it of course doesn't show the entire photo. Not that surprising considering it's larger than the view. Ideally I'd like to zoom out to show the entire photograph. Once I've zoomed one way I'd assume that zooming in on the part that you want should also be possible.
Next is adding the objects. My idea was simply catching any touch events and adding a new object once the finger is released. This way I'd end up with a list of items with each having a draw function which can be called through the surfaceview when it is redrawn.
Connecting these items could simply be done by creating a line object and going through the list of all items and using their locations for the begin and endpoints of the lines
One of the big issues here is that the x and y locations would be relative to the screen, not to the photo. Which would mean that when you zoom back out the entire background would change but the actual items would remain at the same spot and in the same size.
I've been searching and searching for any tutorial or other question about the same issue, but either I've had no luck or I've been using the wrong keywords. And for all I know everything I have up till now could be wrong.
If anyone could give some pointers, or maybe knows a guide or tutorial somewhere or some better keywords I could use for searching I'd really appreciate it.
Xylon- said:
One of the big issues here is that the x and y locations would be relative to the screen, not to the photo. Which would mean that when you zoom back out the entire background would change but the actual items would remain at the same spot and in the same size.
Click to expand...
Click to collapse
would you just not need to either control or track the sample/scale if the image so that you know the 1st pixel displayed (top left) and the scale factor, then the eventX/Y can be processed to be relative to what you want ?
Hello, I am hoping someone can point out anything I might be doing wrong that is causing my issue. (seems hard to find "best practice" type of advise for newer android features)
My problem is that a ListView which is inside a fragment, controlled by a ViewPager does not get displayed on the screen if I swipe to the next fragment. (but a TextView inside the same fragment shows up fine on all fragment instances),
To set the scene, I have only one fragment class out of which I instantiate all the fragments used by the ViewPager.
Inside the fragments onActivityCreated I create a cursor loader and a custom cursor adapter and on the loaders onLoadFinished I swap the cursor as its supposed to be. Naturally the customCursorAdapter that I created handles the inflation of the listView row in the newView method and binds the data from the cursor in the bindView method.
Does this sound right? I mean I did it this way with the intent of not having tight coupling, having the fragment be independent. So why won't it draw out the listview for subsequent pages? From what I have seen in the logs, all methods get called for all fragments, including getItem, newView, bindView etc.
Final quirk is that the "previous" fragmet's listView does get drawn. Meaning I start on Fragment 1 - listView is there. Move to fragment 2 - listview not there, move to fragment 3 list view not there, move back to fragment 2 list view IS there now, and back to fragment 1 it is NOT there anymore.
I don't have time to post code right now but will as soon as I get a chance.
Thank you all.
Code:
//main activity which creates the view pager and adapter and starts the process
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG,"onCreate begin");
super.onCreate(savedInstanceState);
setContentView(R.layout.pager_task_tracking);
viewPager = (ViewPager) findViewById(R.id.pager);
FragmentManager fragmentManager = getSupportFragmentManager();
MyPagerAdapter myPagerAdapter = new MyPagerAdapter(fragmentManager);
viewPager.setOffscreenPageLimit(0); // trying to force drawing of fragments
viewPager.setAdapter(myPagerAdapter);
Log.d(TAG,"onCreate viewPager done");
//MyPagerAdapter getItem (extends FregmentSatePagerAdapter
public Fragment getItem(int i) {
Log.d(TAG,"getItem called with item:"+i);
return TaskListFragment.newInstance(i);
}
//fragment onActivityCreated , this fragment instanciated in getView of viewPager
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated with datePointer:"+datePointer);
TextView textViewFragmentTitle = (TextView) getView().findViewById(R.id.fragmentTitle);
textViewFragmentTitle.setText("DATE:"+datePointer);
loaderManager = getLoaderManager();
list = (ListView) getActivity().findViewById(R.id.TaskListView);
customAdapter = new CustomCursorAdapter(getActivity(), null, 1 , datePointer);
list.setAdapter(customAdapter);
loaderID = datePointer; //attempt to get fragment listview to draw - not working
loaderManager.initLoader(loaderID, null, this);
}
///cursor loader onFinish
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader,
Cursor newCursor) {
Log.d(TAG, "onLoadFinished:"+datePointer);
if (customAdapter != null && newCursor != null ){
Log.d(TAG, "onLoadFinished swapCursor:"+datePointer);
customAdapter.swapCursor(newCursor);
//doesnt help customAdapter.notifyDataSetChanged();
} else {
Log.v(TAG,"OnLoadFinished: mAdapter is null");
}
}
//MyCustomCursorAdapter (used by the listview inside the fragment above)
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View retView = inflater.inflate(R.layout.task_list_item_layout, null);
RelativeLayout.LayoutParams relativeLayoutParameters;
Log.d(TAG,"newView layout inflated:"+datePointer);
return retView;
}
///bindView of same MyCustomCursorAdapter
public void bindView(View view, Context context, Cursor cursor) {
Log.d(TAG,"bindView:"+datePointer);
TextView tvName = (TextView) view.findViewById(R.id.textviewItemName);
tvName.setText(cursor.getString(cursor.getColumnIndex(DBHelper.C_TASK_NAME))+" ["+datePointer+"]");
}
Also check out the LogCat logs with description of the action in the name corresponding to the log statements in the code above.
I noticed more detail about what happens (if you look at the logcat you will see also)
When the screen is displayed the first fragment has the listview present, but the fragment has the id/datePointer (same thing) of "0" BUT the listview items have an id/datePointer of "1"
If you look at the initial logcat you will see "newView layout inflated:1" but no "newView layout inflated:0" how this is being skipped I have no idea. And how the id's can be mix-matched between fragment instances baffles me.
And lastly, after scrolling right twice (to the 0,1, 2nd fragment) it did not have the listview as reported, but scrolling BACK ONE the listview shows up in the 1st fragment ... but even more baffling with lisvtView items that report being part of the "0" fragment .... whaaaat?
Why are you using a listview inside fragment when you have listfragment available?
EatHeat said:
Why are you using a listview inside fragment when you have listfragment available?
Click to expand...
Click to collapse
EatHeat, I am doing this for the sake of flexibility for adding additional controls/views to the fragment besides just a list view (Example I envision adding several buttons to the bottom of the fragment/screen which will be "outside" the listview.
Does it make more sense what I am doing now? That is exactly one of the questions I have, its so hard to find advise on what makes more sense when it comes to these complex combinations of viewPager+fragments+custom listViews+loaders
So my current flow is:
1--Activity (creates ViewPager with myPagerAdapter)
2----ViewPager in itst getItem method instantiates a fragment from class TaskListFragment
3-------The fragment in it's onActivityCreated instantiates a CustomCursorAdapter (with null cursor) and initializes a loader
4-------The loader swaps the cursor in it's onLoadFinished (and this is supposed to populate the listview)
Items 2-4 repeat for every "swipe" or every fragment instantiated.
-The listView control XML is defined in an XML file which is used by the fragment's setContentView
-The lisView row layout XML is defined in a separate XML file inflated by the customCursorAdapter's newView method.
SOLVED: (after literally one week of headache and rewriting the code in every way I know)
the fragments onCreateView I had it getting the listview with getActivity() .. but I should have done it with getView()
the solution was replacing this line
Code:
list = (ListView) getActivity().findViewById(R.id.TaskListView);
with this line
Code:
list = (ListView) getView().findViewById(R.id.TaskListView);
That was it!!! all the headache!!
I don't particularly understand what getView does as opposed to getActivity .. but right now I am pleased it works.
Hi Can u please provide me the code .. I an working on same thing .. bt my getView Function is not called ..
Email : [email protected]
Make sure you custom pager adapter returns all pages as per count.
Use recyclerview in fragments
Sent from my Lenovo A6000 using Tapatalk
The offscreen page limit is by default 1. It is useless to set the limit lesser equals as 1.
Code:
viewPager.setOffscreenPageLimit(0);