In the main view class / activity I have several checkboxes. Now in another class and with another view active, I would like to check the state of the checkboxes in the 'main' window of my Android app. How can I do that?
Here is what I tried:
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
setContentView(R.layout.main);
View v = findViewById(R.id.cbHasWifi);
CheckBox check = v.findViewById(R.id.cbHasWifi);
v.setContentView(v);
The whole code block gets me nowhere as it seems. I'm also worrying that another View context is active and may create followup problems if it is not 'restored' after my setContentView(), is that justified?
You cannot do anything to the UI in any thread other than the main UI thread, so trying to set a content view from doInBackground is not going to work.
Additionally, you haven't made clear if you are running another activity or not. If you are running a new activity, there is no guarantee your data is still there from the first one.
Related
So full admission, I am a bit self taught when it comes to Android Dev, so I maybe going about this all wrong. As such I am open to suggestions! I'm essentially trying to semi-automate a task I do every day currently.
Question: How to Pass a LinearLayout, it's contents intact, between Activities?
So I have this 2nd Activity, called reportGeneratorActivity In this activity there is a Linear Layout directly under the Report Preview.
The Linear Layout itself is defined in a separate XML file as previewplate.xml
Now this Activity functions, when you put text into the upper fields it updates the preview below. Which brings me to the brick wall I'm hitting. The Goal is to take that preview plate and add it to my main activity that I've named rootActivity in the white area which is a Linear Layout itself named rootWorkingLayout.
Now the Strings from the text are all stored temporarily in reportGeneratorActivity at which point I am doing this when the button is pressed:
public void beginReport (View view) {
//Bundle the Preview
Bundle previewBundle = new Bundle();//Create the Bundle
previewBundle.putString("date", dateHolder);
previewBundle.putString("client", clientNameHolder);
previewBundle.putString("machine", machineTypeHolder);
previewBundle.putString("serial#", serialNumberHolder);
previewBundle.putString("notes", notesHolder);
// Prepare The Intent
Intent previewPasser = new Intent(this, rootActivity.class);
previewPasser.putExtras(previewBundle); // Add the Bundle to Intent
//Send Preview to Root
startActivity(previewPasser);
//Send Preview to History
//Send User to Decision Tree
}
From what I understand, I've put all the strings in Bundle previewBundle, then attached the bundle to the previewPasser intent and sent the intent back to rootActivity.
In rootActivity, within the onCreate function I have placed this code:
Bundle previewReceiver = getIntent().getExtras();
//If There is a Bundle, Process it
if(previewReceiver != null) {
newPreview(previewReceiver);
}
The Goal here is to grab the Intent, and grab the bundle then pass it to my newPreview function (currently empty) that will duplicate finished preview from report_generator_activity and desplaying within the Linear Layout: rootWorkinglayout in an identical fashion.
It's this final step that I am hitting a brick wall on, I can only assume there is an easier way, perhaps a way to duplicate the Layout and it's contents and send it over? Or if I am doing this functionally, How do I unpack the data in an identical manner?
Please forgive the verbosity and lack of images as I am a new member of the community.
Edit #1:
In response to SoroushA's excellent answer that has put me on the correct path, I've adjusted my newPreview Method to be this:
public void newPreview (Bundle previewReceiver) {
//Extract Strings from Bundle
String date = previewReceiver.getString("date");
String client = previewReceiver.getString("client");
String machine =previewReceiver.getString("machine");
String serialNum = previewReceiver.getString("serial#");
//Create New Inflater
LayoutInflater previewInflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View previewLayout = previewInflater.inflate(R.layout.previewplate, null);
//Add previewLayout to rootWorkingLayout
rootWorkingLayout.addView(previewLayout);
}
Currently, I am just trying to get the grey box of the preview plate layout to appear as it's background is defined in it's own XML file. However, nothing is occurring when I go through the process clearly due to my own error. I am unsure of what step I am missing.
Thanks in advance!
I hope that I understood your question clearly.
In your newPreview method, start by getting the Strings back from the Bundle:
public void newPreview(Bundle preview){
String dateHolder = preview.getString("date");
//similarly for other strings
}
Then inflate the LinearLayout and start setting its elements.
LayoutInflater inflater = (LayoutInflater)context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.your_xml, null);
//call findviewbyid on the layout and set its children using the strings you extracted
How to Pass a LinearLayout, it's contents intact, between Activities?
You don't. Widgets and containers (i.e., subclasses of View) are owned by their activity.
I can only assume there is an easier way
Have only one activity, altering its UI as needed (e.g., use fragments and replace them as needed). These seem to be way too closely coupled to be two separate activities.
The Goal here is to grab the Intent, and grab the bundle then pass it to my newPreview function (currently empty) that will duplicate finished preview from report_generator_activity and desplaying within the Linear Layout: rootWorkinglayout in an identical fashion.
There is nothing intrinsically wrong with this approach. You act as though you are having problems implementing it ("How do I unpack the data in an identical manner"), but we do not have nearly enough information on which to provide you with much advice. In general, a Bundle has getter methods, to retrieve that values that you put into the Bundle via the setter methods.
How to open an application inside another application within the latters boundaries in android? ie., similar to what iframe does in HTML.
You basically can't. It goes against the rules of Android. The most you can do is open a web page as part of an app. This is done using the webView. You can control the boundaries of the screen by setting the bounds of the webview in the xml file for the Webview.
public class WebViewFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
public WebViewFragment() {
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mainView = inflater.inflate(R.layout.fragment_facebook,
container, false);
WebView webView = (WebView) mainView.findViewById(R.id.webView1);
webView.setWebViewClient(new MyWebViewClient());
webView.getSettings().setSupportZoom(false);
webView.getSettings()
.setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setDomStorageEnabled(true);
webView.loadUrl(""); //URL needs to be entered in this line
return mainView;
}
}
Hope this helps :)
This is not possible because of security reasons. Previous versions of Android allowed this with System-grade permissions (ones that most developers will never get to use), but it was rarely used and is not in the SDK anymore as far as I know.
Some manufacturers implement additional functionalities like Samsung's Mini Apps (if I remember the name correctly) which may be opened in a floating window above other apps. You can also draw your own app over another using a service (like Facebook messenger does). But there is no way to force a third party app to do any of these things.
However, every time you open an application from your application, the process of the new one will have the invoker's process assigned as parent. This allows you, to some extend, check if this other app was opened from your app.
Also, your app will not die when opening a new one, but will simply be "below it". If you need some kind of data from the other app, you may start it forResult. This way the other app will "know" you are expecting a defined result from it, so it will process some data and pass it back to your app (which will reappear after the other one is finished preparing the result).
It could be possible if use the android property
android:launchMode="singleTask while declaring your activity in the AndroidManifest.xml (inside the activity element).
If you so so, if you minimize your app and launch it again (from background or from app icon from the list of apps), it would still show you the new app.
I am not sure if the result would be as per your desired effect.
I have these lines of code , which i want to use inside getview() method of CustomAdapter .
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
final MobileServiceList<User> result =
mUser.where().field("name").eq(currentItem.getTo()).select("designation").execute().get();
int counter=
mUser.where().select("designation").execute().get().getTotalCount();
for (User item : result) {
// Log.i(TAG, "Read object with ID " + item.id);
desig[0] = item.getDesignation();
Log.v("FINALLY DESIGNATION IS", desig[0]);
}
} catch (Exception exception) {
exception.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// gb.setDesignation(desig[0]);
designation.setText(desig[0]);
}
}.execute();
This is my AsyncTask code which , I am using to populate custom listview .This piece of code keeps on running , I don't know how many times. But at the end it is giving me right results after so many updates on TextView (designation). This is not only degrading the performance of my application but also showing multiple updates on TextView before reaching to result.
I am getting data in desig[0] variable , have a look on my code .
Data is coming from azure But don't worry if you are not an azure guy . Just help me on Java part.
QUESTION
My question is how can use Async task inside getview() method . Do i have to make functions , which i can call latter . Data is coming from azure But don't worry if you are not an azure guy . Just help me on Java part. plzz help
getView gets called every time a line of list view must be drawn. So don't forget that there will be multiple doInBackground running at the same time. What is designation ? A view inside an element of ListView ?
EDIT
As designation is a text in each cell, you have to make sure that the cell you will upgrade is the good one.
What I usually do is that I use a ViewHolder that I attach to the recycled View. Then I register the ViewHolder as a listener (listening to AsyncTask).
ViewHolder starts the request and gives an ID to the AsyncTask. Then, while the AsyncTask is running, I periodically ask the ViewHolder if the ID that was given to the AsyncTask is the good one. If it's not, I cancel the AsyncTask (no need to be synchronous).
Then when the AsyncTask is finished, I check a last time that the ID matches the one given by the ViewHolder and I notify the listener (ViewHolder) that the result is available.
This way, you can be sure that the AsyncTask is not doing work for nothing.
But of course it will depend of what kind of task you are actually doing in AsyncTask...
Call the AsyncTask subclass in side Activity or onActivityCreated of Fragment and pass the result to CustomAdapter to update the view. If you can play your Activity or Fragment class to see where appropriate to put it.
you need make a data model for you view. like make a class which contains all display information(here a string for desig[0]). so you can update the view in AsyncTask.onPostExecute().
or if you need the view only show when the desig got, hide it or add a loading waiting dialog when you getting the desig from azure.
I am in a peculiar situtation in my app.
When i app first loads there is a custom listview which is populated with data from the server.I am also using a class which contains different fields for the string data from the server.
When i click an item on the custom listview,the object of the corresponding class is passed onto the next fragment.
That is the current fragment is replaced with a new fragment and the object is passed with bundle.
Now a new listview loads with different tasks.On clicking a task a new fragment with a camera is loaded.
After taking the image and uploading to server, the status in the JSON changes to "COMPLETED".But now when i press back the old listview is shown.
Is there a way to populate the listview on back pressed with new data?
The issue is that I am passing an object right from the first fragment.
Now i need a new object on back pressed,how to pass the new object on back pressed?
When Fragment 2 gets the data, it should pass it along at some point before Fragment 1 is woken.
There are almost a half dozen ways to pass data, and the best way depends on a number of factors like who should own the lifecycle of the data, data pull vs push, dependency between fragments, do multiple components need updating, etc.
I'm just going to advise to simply cache the data on the activity until you learn more about the different methods.
//Fragment 2 puts data to activity
((MyActivity) getActivity).mListViewData = listViewData;
Then the next part of the question is how does fragment 1 get the data. Fragment 1 is hibernating on the backstack. When it wakes up it will call the onViewCreated() method (because it's previous view was destroyed before being placed on the backstack).
In that method, we check if there's new data waiting for Fragment 1.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
MyDataType listViewData = ((MyActivity) getActivity).mListViewData;
if(listViewData != null){
//setData is your own function for replacing the adapters
//data backing
listView.getAdapter().setData(listViewData);
}else{
listView.getAdapter().setData(...defaultData);
}
listView.getAdapter.notifyDataChanged();
}
Override the onBackPressed in the Activity that manages the Fragments. In it you can check if the fragment is visible or not (the one from which an action should be performed if the back is pressed) and then execute your action.
#Override
public void onBackPressed(){
Fragment myFragment = getFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment.isVisible()) {
String json = myFragment.getJsonData(); //update it locally
if(isUpdated){
Fragment listFragment = getFragmentManager().findFragmentByTag("MY_LIST_FRAGMENT");
listFragment.updateListView(json); //Add this method on your fragment
}
}
super.onBackPressed();
}
Obs.: To use the .findFragmentByTag() you should add tags once you're making the transaction like so:
fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");
If, for any reason the listFragment has been cleaned from memory, you would have to reload the data anyway so just download the new data again.
To update the ListView please see: How to refresh Android listview? . Note thought that you will need to will need to send a new data set to the list view (which you can do inside the updateListView() method)
Background
I have a ViewPager that will display up to 4 Fragments. The number available at any given time is dynamic (it could be 1, 2, 3, or 4). It makes most sense to have these fragments manage themselves. By that I mean they are singletons. Rather than creating a new fragment with the new keyword, I've written a 'getInstance(String key)' method which attempts to retrieve the fragment for the specified key from the map, or if it does not exist in the map, creates a new instance, places the fragment in the map with the given key, sets the fragments arguments with a bundle containing that key so the fragment can retrieve it onCreate(), and then returns a new instance of that fragment.
For those who aren't following, here's the code:
public class DishListFragment extends ListFragment {
public static final String MENU = "menu";
...
private static Map<String, DishListFragment> mInstances = new HashMap<String, DishListFragment>();
public static DishListFragment getInstance(String menuKey) {
if (mInstances.containsKey(menuKey))
return mInstances.get(menuKey);
Bundle b = new Bundle();
b.putString(MENU, menuKey);
DishListFragment dlf = new DishListFragment();
dlf.setArguments(b);
mInstances.put(menuKey, dlf);
return dlf;
}
}
You may have noticed this is not thread safe.
Walkthrough
OnCreate, my main activity sets its view then spawns an AsyncTask responsible for obtaining data from a server which will populate my DishListFragments. Meanwhile, the main activity continues on and sets the PagerAdapter. When the PagerAdapter requests a new DishListFragment, the number is converted into a key dynamically and the value from the DishListFragment.getInstance(key); method is returned. Initially the content class that is observed by the ListFragments has dummy data so one page always shows up and so there is always one page available for the ViewPager to show.
When the AsyncTask starts, a progress dialog is shown. When it completes, it dismisses the progress dialog and calls a method in my activity which then sets the data in my content class. Then a method, refresh(), is called which tells all the DishListFragments in existence to notify their adapters that the dataset has changed. After that method completes, the ViewPagerAdapter is notified that its dataset has changed.
In my main Activity:
public void onRetrieveData(Result result) {
switch(result.getCode()) {
case Result.SUCCESS:
Log.i(UITHREAD, "Menu successfully loaded!");
/* On SUCCESS the MenuContent class should be given the data and
* the adapters notified. */
mRequestedDate = mPendingDate;
MenuContent.setMenuData(result.getValue());
DishListFragment.refresh();
mMenuPagerAdapter.notifyDataSetChanged();
...
}
}
And the refresh method in the DishListFragment class:
public static void refresh() {
for (String key : mInstances.keySet()) {
mInstances.get(key).mListAdapter.notifyDataSetChanged();
Log.d("glic", "DishListFragment: " + key + " refreshed");
}
Log.d("glic", "DishListFragments refreshed");
}
Problem
The problem is, on a cold start, everything but the frist page is updated. Further, from my Logcat output, I gather there is only one DishListFragment in my map:
10-18 22:11:41.624: I/##############(16802): Menu successfully loaded!
10-18 22:11:41.744: D/glic(16802): DishListFragment: breakfast refreshed
10-18 22:11:41.744: D/glic(16802): DishListFragments refreshed
10-18 22:11:41.744: D/GLIC(16802): lunch
However, my view pager shows 4 pages with the first still containing dummy data. If I rotate the screen, the first page is updated and displays the correct information. Also, if I select an item in the dummy list, a details fragment is displayed with real (from the server) information for the position of the item I selected -- even though I only selected a dummy item.
My first thought is I might have two instances of my singleton fragments. One with a map containing a fragment with the initial dummy data and one containing the real data returned from the server. I guess this is possible since my singleton is not thread safe. However, I don't think this should cause any problems. My DishListFragments do not contain the data they display, they only observe it so regardless of how many instances I might have of the same DishListFragment (same being for the same page), they should all observe the same data and should not show different data -- the dummy data is cleared when the new data from the server is parsed and added.
But, two instances of my mInstances map may explain why the view is not updating. Perhaps the Adapters in only one of the sets of DishListFragments are being notified that their dataset has changed. According to my Logcat though, breakfast, which is my first page and the one that is filled with dummy data, is indeed being notified that its dataset has changed. Interestingly, the others are not.
Question..
So, as for my original question: Am I implementing a singleton grouping of Fragments correctly? If so, what other factors might be causing the weird behavior I'm experiencing. Thanks in advance (=