Launch Different View Layout based on JSON Key Values - java

In my android application, I want to display different App Layout based on JSON Config files from server, For example if config Layout key is Set to ListView than show ListView when App Launched, Same way if Config Layout key is set to GridView than show GridView in app.
For this purpose I have :
public void sendView(View view) throws JSONException, IOException{
String[] viewType = pm.getScreetypeConfigFromJsonElement();
if ( viewType[0] == "LV"){
Intent intent = new Intent(this, AUListView.class);
startActivity(intent);
}else if(){....} //For any other view
}
And now Im calling this function inside MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
sendView(/*Cant solve how to pass view */);
} catch (JSONException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
.
.
.
}
How can I fix this issue of having to Launch different AppLayout Based on JSON Config Values in Android.

There are many ways to do this. One simple solution is to make different layouts and call setContentView() depending on the one you want. For example, make 2 layouts for your activity. One of them has a ListView and another one has a GridView say. You can inflate based on that:
String[] viewType = pm.getScreetypeConfigFromJsonElement();
if ( viewType[0] == "LV"){
setContentView(R.layout.main_layout_with_list_view);
else if ( viewType[0] == "GV"){
setContentView(R.layout.main_layout_with_grid_view);
You can put this code in your onCreate() method to dynamically inflate the layout based on your JSON values.

after super.onCreate(savedInstanceState); call the method where you are checking the json keys in that method use setContentView(R.layout.activity_main); in your conditions
if(viewType[0]== type1)
setContentView(R.layout.yourlayout1);
else if(viewType[0]== type2)
setContentView(R.layout.yourlayout2);
you dont have to have different activities have multilpe layouts and put all the code in this activity and it will work as per your requirement

Related

Custom adapter's asynchronous behaviour

I have created my own custom adapter class in my android app and I am calling it from one of my activity. I am adding some elements to the view from the adapter class and I need to access those variables from my activity class.
Now, ideally I would expect it to fill the view and then execute the further code in my activity class, but adapter class is taking some time to populate the view and in the meanwhile further code in my activity class is getting executed where no such elements have been added yet.
How do I handle this situation? I come from a js background. Do we have something like promises in java?
According to the answers I have my changed my code to this:
public class HomeActivity extends Activity {
GridView grid;
String text[] = {"Calendar","Uber","Weather","News","Youtube","Clock","Email","Maps","Twitter","Facebook"};
String list_app_name[] = {"calendar","uber","weather","news","youtube","clock","email","maps","twitter","facebook"};
String id_button[] = {"button_calendar","button_uber","button_weather","button_news","button_youtube","button_clock","button_email","button_maps","button_twitter","button_facebook"};
int image[] = {R.drawable.social_icons1,R.drawable.social_icons2,R.drawable.social_icons3,R.drawable.social_icons4,
R.drawable.social_icons5,R.drawable.social_icons6, R.drawable.social_icons7,R.drawable.social_icons8,
R.drawable.social_icons9,R.drawable.social_icons10};
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_home);
//setting up the adapter for gridView
grid = (GridView)findViewById(R.id.simpleGrid);
ImageAdapter ia = new ImageAdapter(this,image,text,id_button);
grid.setAdapter(ia);
ia.notifyDataSetChanged();
try {
initStateOfApps();
} catch (JSONException e) {
e.printStackTrace();
}
}
public void initStateOfApps() throws JSONException {
Log.d("here","here");
ArrayList<String> list = getEnabledApps();
Log.d("apps",list.toString());
for(int i=0;i<list.size();i++) {
String app_name = list.get(i);
ToggleButton button=null;
if(app_name.equals("calendar")) {
button = (ToggleButton)findViewById(R.id.button_calendar);
button.setChecked(true);
}
}
}
}
So what is happening is that I am creating some toggle buttons that are getting populated in the ImageAdapter class that I wrote.
Once the ImageAdapter is called, I call the notifydatasetchanged() on the adapter in order to update the view.
What I am doing inside the adapter is giving each of the toggle buttons some custom ID I wrote in res/values/ids.xml.
After using setId on each of the toggle buttons, I try using that ID in my activity class but it gives me nullPointerException in the initStateOfApps() where I am trying to change the state of button.
So even after using the notifyDataSetChanged it is still behaving the same.
ImageAdapter.java
public class ImageAdapter extends BaseAdapter {
private Context context;
private final int item_image[];
private final String item_text[];
private final String button_id[];
public ImageAdapter(Context context, int item_image[], String[] item_text,String[] button) {
this.context = context;
this.item_image = item_image;
this.item_text = item_text;
this.button_id = button;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View gridView;
if (convertView == null) {
gridView = new View(context);
// get layout from custom_gridview.xml
gridView = inflater.inflate(R.layout.item, null);
// set value into imageview
final ImageView image = (ImageView) gridView.findViewById(R.id.item_image);
image.setImageResource(item_image[position]);
// set value into textview
TextView text = (TextView) gridView.findViewById(R.id.item_text);
text.setText(item_text[position]);
final ToggleButton button_ = (ToggleButton) gridView.findViewById(R.id.item_button);
if(position==0) {
button_.setId(R.id.button_calendar);
image.setId(R.id.image_calendar);
}
button_.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener()
{
#Override
public void onCheckedChanged(CompoundButton toggleButton, boolean isChecked)
{
if(context.getResources().getResourceEntryName(toggleButton.getId()).equals("button_calendar")) {
if(isChecked) {
try {
setStateOfApp("calendar","true");
} catch (JSONException e) {
e.printStackTrace();
}
Intent intent = new Intent(context, GoogleApp.class);
((Activity) context).startActivityForResult(intent,10);
} else {
try {
setStateOfApp("calendar","false");
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
}
} else {
gridView = (View) convertView;
}
return gridView;
}
}
You are trying to access View which is not a part of Activity's content view. So you can't access that view directly.
button = (ToggleButton)findViewById(R.id.button_calendar); // will return null
This ToggleButton will be null because findViewById will fail to find out ToggleButton in current content view because that view is present in your Adapter not in content view.
And you are getting nullpointerException because you are trying to access property on null view.
button.setChecked(true); // This button is null
In java we have <Future>, but I don't think it's what you're looking for.
The adapter (extending BaseAdaper) behaviour lets you create the adapter and, even in a second moment, change underlying data via getAdapter().setData() or whatever method you choose to add.
From this perspective, the adapter is a "stupid" component acting as A View containers, you should retrieve data elsewhere (CursorAdapter is different).
So, in your Activity, fill the adapter with needed data and, when finished, call adapter.notifyDatasetChanged(). This will inform the adapter that its own data has changed and it must refresh views
Yes, ideally, the population of the adapter should be coming from the outside. The adapter should really just take in a list of data and map that data to the views. For example, some method or task in the Activity could produce a list of data (probably asynchronously...since you mentioned it) that you then pass into the adapter and then you can notifyDataSetChanged() if you need to.
I can't see your code, but if for some reason the data is truly required to be populated from inside the adapter, you could use an event bus and subscribe to it in the Activity. I would recommend going with the first option, but here are some links if you choose to use an event bus:
https://github.com/greenrobot/EventBus
http://square.github.io/otto/
As per my understanding with your question
You are not properly managed the adapter data in your activity.
If any of the data or code interlinked with your adapter data or values
Then you can start those code after you retrieve the values or data and update the view in your activity.
Please note that use Viewholders in adapter to avoid slow populating and scrolling in listviews.
Viewholders will smooth your process.
I personally suggest you that
Please go with Recyclerview and RecyclerViewAdapter.
So many Android developers are using it.
If you have background tasks in adapter you can prefer to use RX Java or EventBus
If you provide the code
It's better for us to suggest exact solution

Android - Finding ID of view from inflated layout

I know there are lots of other answers on stackoverflow on the same thing but I can't seem to get it to work.
What I'm trying to do is find the ID of a view from an inflated layout. I want WV1 to load google.com when the button is clicked, you can see I'm using onClick from XML to do this.
public void ButtonClicked(View view)
{
View inflatedView = getLayoutInflater().inflate(R.layout.tab_content, null);
WV1 = (WebView) inflatedView.findViewById(R.id.tab1WV);
WV1.setWebViewClient(new InsideWebViewClient());
if (WV1.isShown()) {
WV1.requestFocus();
}
else{
}
if (WV1.isFocused()) {
WV1.loadUrl("http://www.google.com");
}
}
This is in the MainActivity, the webview (WV1) is in the other, inflated class.
Problem is, nothing happens at all...
I've been stuck on this for quite some time now, I appreciate all help given to me.. If there's any other information you require then just ask, thanks in advance!
--Edit--
In the MainActivity, theres tabhost and a button that creates new tabs. When new tabs are created the MainActivity inflates the second class file containing the webview, I can't get the mainactivity to find the webview from the inflated class. I dont know if this helps any more or not...
Check out this link:
Android - Add textview to layout when button is pressed
Where one of the answers does this:
mLayout.addView(createNewTextView(mEditText.getText().toString()));
where mLayout is a linear layout in the activity.
You'd have to add a view to one of your current layouts or start up an activity that opens up with a web view in it.
Alternative way to create webview :
Webview WV1 = new WebView(view.getContext);
WV1.setWebViewClient(new InsideWebViewClient());
if (WV1.isShown()) {
WV1.requestFocus();
}
else{
}
if (WV1.isFocused()) {
WV1.loadUrl("http://www.google.com");
}
}
Now add this to a view group
viewgroup.addchild(WV1);
You're not attaching it to anything. You need to either supply the parent when you inflate it, or call addView on the ViewGroup that should contain it.
public void ButtonClicked(View view){
View inflatedView = getLayoutInflater().inflate(R.layout.tab_content, (ViewGroup) findViewById(android.R.id.content));
WV1 = (WebView) inflatedView.findViewById(R.id.tab1WV);
WV1.setWebViewClient(new InsideWebViewClient());
if (WV1.isShown()) {
WV1.requestFocus();
}
if (WV1.isFocused()) {
WV1.loadUrl("http://www.google.com");
}
}
Or:
((ViewGroup)findViewById(android.R.id.content)).addChild(WV1);
Both of these will add your view at the end. You may need to add some layout attributes to get it to look like you want.

onListItemClick add item to ListView in another activity

I am very sorry if this question already exists, but I couldn't find any answer to my problem. The idea of my application is a Shopping List. The user can see a list of food and on clicking on an item, it should automatically be added to a list.
What I already have is a ListView generated from an xml-file in a raw folder. This is my food, I haven't stored it in a SQLite Database.
What I want to do now is that when I click on an item in this list, it's added to a ListView in another Activity called "ShoppingList.java". It shouldn't open immediately, so the user has the possibility to add more items.
Now, when I click on an item, it's added to a TextView called "selection" in the same Activity on the top of the screen.
How is it possible to add an item from one Activity to another one?
Thank you very much for your help!
public class FishOk extends ListActivity {
TextView selection;
ArrayList<String> items=new ArrayList<String>();
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.foodok_list);
selection=(TextView)findViewById(R.id.selection);
try {
InputStream in=getResources().openRawResource(R.raw.fish);
DocumentBuilder builder=DocumentBuilderFactory
.newInstance()
.newDocumentBuilder();
Document doc=builder.parse(in, null);
NodeList words=doc.getElementsByTagName("product");
for (int i=0;i<words.getLength();i++) {
items.add(((Element)words.item(i)).getAttribute("value"));
}
in.close();
}
catch (Throwable t) {
Toast
.makeText(this, "Exception: "+t.toString(), 2000)
.show();
}
ListView lstView = getListView();
lstView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lstView.setTextFilterEnabled(true);
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
items));
}
public void onListItemClick(ListView parent, View v, int position,
long id) {
selection.setText(items.get(position).toString());
}
public void onClick(View view) {
ListView lstView = getListView();
String itemsSelected = "Selected items: \n";
for (int i=0; i<lstView.getCount(); i++) {
if (lstView.isItemChecked(i)) {
itemsSelected += lstView.getItemAtPosition(i) + "\n";
}
}
Toast.makeText(this, itemsSelected, Toast.LENGTH_LONG).show();
}
Adding an item to the ListView of an Activity which isn't visible to the user and doesn't yet exist makes no sense. You should have a place where you'll store the data, it can be a SQLite database, a plain text file, or SharedPreferences if there's not much data. When you're clicking on a Button inside your current Activity you should store the information to your data storage, and then retrieve it to populate the ListView when the second Activity starts. Hope this helps.
Activity is a window where you can put your UI stuff so that user can interact with the application.
Now, for using the data in the activities across the application, you have to use either Collections or Database.
But as per your requirement, I think you should use Collections.
Maintain an Arraylist or a HashTable according to your data.
Pass that data from one activity to other.
OR
Maintain a singleton class and update the data in that class. Access the data from other activities.
I hope this helps you.

Android BaseAdapters & Multiple Listviews

I am currently creating a basic news aggregator app for Android, I have so far managed to create multiple HorizontalListViews derived from this: http://www.dev-smart.com/archives/34
I am parsing all data from live JSON objects and arrays.
The process goes something like this:
1) Start app
2) Grab a JSON file which lists all feeds to display
3) Parse feed titles and article links, add each to an array
4) Get number of feeds from array and create individual HorizontalListView for each. i.e. "Irish Times".
5) Apply BaseAdapter "mAdapter" to each HorizontalListView during creation.
My baseadapter is responsible for populating my HorizontalListViews by getting each title and thumbnail.
My problem is however that all my feeds seem to contain the same articles and thumbnails. Now I am only new to Android so I'm not 100% sure whats going wrong here. See screenshot below.
Do I need to create a new BaseAdaptor for each HorizontalListview or can I use the same one to populate all my listviews with unique data.
Here's some code to help explain what I mean:
1) OnCreate method to get JSON data, parse it, get number of feeds and create each HorizontalListView
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listviewdemo);
//--------------------JSON PARSE DATA------------------
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
String json = jParser.getJSONFromUrl(sourcesUrl);
//Parse feed titles and article list
getFeeds(json);
//Create Listviews
for(int i = 0; i < feedTitle.size()-1; i++){
//getArticleImage(i);
addHorzListView(i);
articleArrayCount++;//Used to mark feed count for adaptor to know which array position to look at and retrieve data from.
//Each array position i.e. [1] represents a HorizontalListview and its related articles
}
}
2) addHorzListView method, used to create HorizontalListView and apply adaptor
//Method used to dynamically add HorizontalListViews
public void addHorzListView(int count){
LinearLayout mainLayout = (LinearLayout) findViewById(R.id.main_layout);
View view = getLayoutInflater().inflate(R.layout.listview, mainLayout,false);
//Set lists header name
TextView header = (TextView) view.findViewById(R.id.header);
header.setText(feedTitle.get(count));
//Create individual listview
HorizontalListView listview = (HorizontalListView) view.findViewById(R.id.listviewReuse);
listview.setAdapter(mAdapter);
//add listview to array list
listviewList.add(listview);
mainLayout.addView(view, count);
}
3) Baseadaptor itself:
private BaseAdapter mAdapter = new BaseAdapter() {
private OnClickListener mOnButtonClicked = new OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(HorizontalListViewDemo.this);
builder.setMessage("hello from " + v);
builder.setPositiveButton("Cool", null);
builder.show();
}
};
#Override
public int getCount() {
return noOfArticles.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
//Each listview is populated with data here
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View retval = LayoutInflater.from(parent.getContext()).inflate(R.layout.viewitem, null);
TextView title = (TextView) retval.findViewById(R.id.title);
title.setText(getArticleTitle(position));
new DownloadImageTask((ImageView) retval.findViewById(R.id.ImageView01)) .execute(getArticleImage(position));
Button button = (Button) retval.findViewById(R.id.clickbutton);
button.setOnClickListener(mOnButtonClicked);
return retval;
}
};
The adapter mAdapter is currently displaying the articles from the last HorizontalListView that calls it.
Currently I am using the same BaseAdaptor for each ListView as I figured it populated the listview as soon as its called but i looks as though a BaseAdaptor can only be called once, I really dont know.
I want to dynamically populate feeds though without having to create a new Adaptor manually for each HorizontalListView.
Any help would be much appreciated.
So...you got the same info in 4 listview, right? In that case you only need oneAdapter populating 4 listview.
An adapter just provide the views which are visible in that moment to the listview (if it is implemented in the right way) so you can reuse the adapter if the info contained is the same.

How to switch activity with item specific data sent

I've had a look around, and it might be because I'm not sure what I'm looking for, but I can't find out how to do something I presume should be quite easy with android.
I have an array of data to display on the screen. This data is a class that holds a database key, name and image.
I'm currently displaying this data as an ImageView and a TextView. I loop through the array and add a new row to a TableLayout containing the image and text.
I'd like both the image and text to be clickable, changing to a new activity.
This new activity needs to know the database key of the row clicked in order to display the correct data.
Here's what I have so far:
private void fillSuggestionTable(TableLayout tabSuggestions, Suggestion[] arrToAdd)
{
for(int i = 0; i < arrToAdd.length; i++)
{
/* Create a new row to be added. */
TableRow trSuggestion = new TableRow(this);
trSuggestion.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
/* Create objects for the row-content. */
ImageView imgDisplayPicture = new ImageView(this);
ImageHandler.loadBitmap(arrToAdd[i].strImageURL, imgDisplayPicture);
imgDisplayPicture.setLayoutParams(new LayoutParams(50,50));
TextView txtArtistName = new TextView(this);
txtArtistName.setText(arrToAdd[i].strName);
txtArtistName.setTextColor(Color.parseColor("#000000"));
/* Add data to row. */
trSuggestion.addView(imgDisplayPicture);
trSuggestion.addView(txtArtistName);
/* Add row to TableLayout. */
tabSuggestions.addView(trSuggestion, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
}
Is there a reason you're using a TableView? it seems like what you want to accomplish would be much easier with a ListView & custom CursorAdapter, where the adapter can handle translating from the database to the ListView row. At that point starting a new activity that knows the database ID is trivial:
mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick (AdapterView<?> parent, View view, int position, long id) {
Intent i = new Intent(MyActivity.this, MyOtherActivity.class);
i.putExtra("database_id", id);
startActivity(i);
}
});
And in MyOtherActivity:
private int dbId;
protected void onCreate(Bundle savedInstanceState) {
//do stuff
dbId = getIntent().getIntExtra("database_id", -1); // the -1 is the default if the extra can't be found
}
To pass extra data to another Activity, you need to add extra information with the Intent.putExtra(name, value) methods.
For example, to send the Intent:
Intent i = new Intent([pass info about next Activity here]);
i.putExtra("databaseKey", databaseKey);
startActivity(i);
To get the data out again:
public void onCreate(Bundle savedInstance)
{
// Do all initial setup here
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey("databaseKey"))
{
int databaseKey = extras.getInt("databaseKey");
// Load database info
}
else
{
// No data was passed, do something else
}
}
EDIT: To find out when the table's row is clicked, you'll need to implement View.OnClickListener and set the onClickListener for the TableRows you use.
For example:
/* Create a new row to be added. */
TableRow trSuggestion = new TableRow(this);
trSuggestion.setOnClickListener([listener]);
The only problem you'll have is relating a View's ID to the related database row ID. A HashMap should help.
This is a pretty simple procedure. This blog explains it in simple terms.

Categories

Resources