Hi I been trying for a while to figure this out and checked a lot of post. I am having this problem when I switch to a new tab only the XML layout is showing. Though when I start on the first tab and fragment the json content shows up how I like. I am not sure how to get the json content to change for a new tab.
Fragment
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.koushikdutta.async.future.FutureCallback;
import com.koushikdutta.ion.Ion;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Random;
/**
* A simple {#link Fragment} subclass.
*/
public class TVFragment extends Fragment {
public TVFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tv_activity, container, false);
ArrayList<String> media = new ArrayList<String>();
media.add("movie1");
media.add("movie2");
media.add("movie3");
this.loadMovieInfo(media);
// loadMoviePoster(media);
return rootView;
}
private void loadMovieInfo(ArrayList<String> media) {
Random random = new Random();
int x = (int) random.nextInt(media.size()) * 1;
//Use Ion to get json info for movie from movie/tv api.
Ion.with(this)
.load("http://www.omdbapi.com/?t=" + media.get(x)
+ "&apikey0000")
.asString()
.setCallback(new FutureCallback<String>() {
#Override
public void onCompleted(Exception e, String result) {
try {
// create json object
JSONObject json = new JSONObject(result);
//get json title and poster from the json object.
String name = json.getString("Title");
String urlString = json.getString("Poster");
//get TextView to display title
TextView mediaName = (TextView) getActivity().findViewById(R.id.synopsis_text_view);
mediaName.setText(name);
/* create new DownloadImageTask class for displaying image from url. Picasso API can be used instead if wanted to view picture as well.
this needs to be used since the app will crash due to nature of threading, so AsyncTask is implemented.
*/
new DownloadImageTask((ImageView) getActivity().findViewById(R.id.poster)).execute(urlString);
} catch (JSONException jsone) {
Log.wtf("Json Import problems", jsone);
}
}
});
}
}
MainActivity
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
/**
* Created by Samuel on 2/12/2018.
*/
public class TechnologyResultsActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the content of the activity to use the tv_activitylayout file
setContentView(R.layout.tab_viewpager_activity);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
MediaTypeAdapter adapter = new MediaTypeAdapter(getSupportFragmentManager(),getApplicationContext());
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
}
Adapter
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
/**
* Created by Samuel on 2/14/2018.
*/
public class MediaTypeAdapter extends FragmentPagerAdapter {
public MediaTypeAdapter(FragmentManager fragmentManager, Context applicationContext){
super(fragmentManager);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new TVFragment();
} else if (position == 1) {
return new MovieFragment();
}
else {
return new MovieFragment();
}
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
if(position == 0){
return "TV";
} else {
return "MOVIES";
}
}
}
tablayout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#color/colorPrimary"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
</LinearLayout>
movie_activity layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="bottom"
android:paddingBottom="16dp">
<ImageView
android:id="#+id/poster"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:paddingTop="16dp"
android:paddingBottom="16dp"
tools:src="#drawable/poster"
android:layout_weight="1"
/>
<ScrollView
android:id="#+id/synopsis_scroll"
android:layout_width="match_parent"
android:layout_height="81dp"
android:padding="8dp">
<TextView
android:id="#+id/synopsis_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Academy Award nominee, heart-warming, hit comedy from producer Judd Apatow (Bridesmaids and Trainwreck). The Big Sick is based on the real-life courtship between Pakistan-born comedian Kumail Nanjiani (Nanjiani) and grad student Emily Gordon (Zoe Kazan) who fall in love but struggle while dealing with Emily's mysterious illness and their families culture clash. Also staring Ray Romano and Holly Hunter. Included with Prime."/>
</ScrollView>
</LinearLayout>
</LinearLayout>
you have to create a new class moviefragment and have to write code to fetch movies in that.
public class MovieFragment extends Fragment{
TechnologyResultsActivity technology;
Context context;
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context=context;
technology= (TechnologyResultsActivity) context;
}
public static Fragment newInstance(Bundle bundle){
MovieFragment movie=new MovieFragment();
if(bundle!=null){
movie.setArguments(bundle);
}
return movie;
}
#Override
public void onResume() {
super.onResume();
// this will only called when fragment is visible to user
if(isVisible()) {
if (Constant.isInternetConnected(homeActivity)) {
ArrayList<String> media = new ArrayList<String>();
media.add("movie1");
media.add("movie2");
media.add("movie3");
loadMovieInfo(media)
} else {
Toast.makeText(homeActivity, "No Internet Connection", Toast.LENGTH_SHORT).show();
}
}
}
private void loadMovieInfo(ArrayList<String> media) {
Random random = new Random();
int x = (int) random.nextInt(media.size()) * 1;
//Use Ion to get json info for movie from movie/tv api.
Ion.with(this)
.load("http://www.omdbapi.com/?t=" + media.get(x)
+ "&apikey0000")
.asString()
.setCallback(new FutureCallback<String>() {
#Override
public void onCompleted(Exception e, String result) {
try {
// create json object
JSONObject json = new JSONObject(result);
//get json title and poster from the json object.
String name = json.getString("Title");
String urlString = json.getString("Poster");
//get TextView to display title
TextView mediaName = (TextView) getActivity().findViewById(R.id.synopsis_text_view);
mediaName.setText(name);
/* create new DownloadImageTask class for displaying image from url. Picasso API can be used instead if wanted to view picture as well.
this needs to be used since the app will crash due to nature of threading, so AsyncTask is implemented.
*/
new DownloadImageTask((ImageView) getActivity().findViewById(R.id.poster)).execute(urlString);
} catch (JSONException jsone) {
Log.wtf("Json Import problems", jsone);
}
}
});
}
}
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
The application crashes with an error stating that the Recyclerview is being called on a null object. However I can't seem to pinpoint what is causing this issue. Any help would be very much appreciated. If anymore code is needed, do let me know and I'll edit it in.
Logcat error:
2019-10-30 23:59:15.235 10878-10878/com.example.zaphk.studenthelperapplication3 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.zaphk.studenthelperapplication3, PID: 10878
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.zaphk.studenthelperapplication3/com.example.zaphk.studenthelperapplication3.view.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2861)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2943)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1630)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6626)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
at com.example.zaphk.studenthelperapplication3.view.MainActivity.onCreate(MainActivity.java:65)
at android.app.Activity.performCreate(Activity.java:7032)
at android.app.Activity.performCreate(Activity.java:7023)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1236)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2814)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2943)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1630)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6626)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
MainActivity.java
package com.example.zaphk.studenthelperapplication3.view;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import com.example.zaphk.studenthelperapplication3.database.DatabaseHelper;
import com.example.zaphk.studenthelperapplication3.database.model.Note;
import com.example.zaphk.studenthelperapplication3.utils.MyDividerItemDecoration;
import com.example.zaphk.studenthelperapplication3.utils.RecyclerTouchListener;
import com.example.zaphk.studenthelperapplication3.R;
public class MainActivity extends AppCompatActivity {
private NotesAdapter mAdapter;
private List<Note> notesList = new ArrayList<>();
private CoordinatorLayout coordinatorLayout;
private RecyclerView recyclerView;
private TextView noNotesView;
private DatabaseHelper db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notes);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
coordinatorLayout = findViewById(R.id.coordinator_layout);
recyclerView = findViewById(R.id.recycler_view);
noNotesView = findViewById(R.id.empty_notes_view);
db = new DatabaseHelper(this);
notesList.addAll(db.getAllNotes());
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showNoteDialog(false, null, -1);
}
});
mAdapter = new NotesAdapter(this, notesList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16));
recyclerView.setAdapter(mAdapter);
toggleEmptyNotes();
/**
* On long press on RecyclerView item, open alert dialog
* with options to choose
* Edit and Delete
* */
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this,
recyclerView, new RecyclerTouchListener.ClickListener() {
#Override
public void onClick(View view, final int position) {
}
#Override
public void onLongClick(View view, int position) {
showActionsDialog(position);
}
}));
}
/**
* Inserting new note in db
* and refreshing the list
*/
private void createNote(String note) {
// inserting note in db and getting
// newly inserted note id
long id = db.insertNote(note);
// get the newly inserted note from db
Note n = db.getNote(id);
if (n != null) {
// adding new note to array list at 0 position
notesList.add(0, n);
// refreshing the list
mAdapter.notifyDataSetChanged();
toggleEmptyNotes();
}
}
/**
* Updating note in db and updating
* item in the list by its position
*/
private void updateNote(String note, int position) {
Note n = notesList.get(position);
// updating note text
n.setNote(note);
// updating note in db
db.updateNote(n);
// refreshing the list
notesList.set(position, n);
mAdapter.notifyItemChanged(position);
toggleEmptyNotes();
}
/**
* Deleting note from SQLite and removing the
* item from the list by its position
*/
private void deleteNote(int position) {
// deleting the note from db
db.deleteNote(notesList.get(position));
// removing the note from the list
notesList.remove(position);
mAdapter.notifyItemRemoved(position);
toggleEmptyNotes();
}
/**
* Opens dialog with Edit - Delete options
* Edit - 0
* Delete - 0
*/
private void showActionsDialog(final int position) {
CharSequence colors[] = new CharSequence[]{"Edit", "Delete"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Choose option");
builder.setItems(colors, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
showNoteDialog(true, notesList.get(position), position);
} else {
deleteNote(position);
}
}
});
builder.show();
}
/**
* Shows alert dialog with EditText options to enter / edit
* a note.
* when shouldUpdate=true, it automatically displays old note and changes the
* button text to UPDATE
*/
private void showNoteDialog(final boolean shouldUpdate, final Note note, final int position) {
LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
View view = layoutInflaterAndroid.inflate(R.layout.note_dialog, null);
AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(MainActivity.this);
alertDialogBuilderUserInput.setView(view);
final EditText inputNote = view.findViewById(R.id.note);
TextView dialogTitle = view.findViewById(R.id.dialog_title);
dialogTitle.setText(!shouldUpdate ? getString(R.string.lbl_new_note_title) : getString(R.string.lbl_edit_note_title));
if (shouldUpdate && note != null) {
inputNote.setText(note.getNote());
}
alertDialogBuilderUserInput
.setCancelable(false)
.setPositiveButton(shouldUpdate ? "update" : "save", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox, int id) {
}
})
.setNegativeButton("cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogBox, int id) {
dialogBox.cancel();
}
});
final AlertDialog alertDialog = alertDialogBuilderUserInput.create();
alertDialog.show();
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Show toast message when no text is entered
if (TextUtils.isEmpty(inputNote.getText().toString())) {
Toast.makeText(MainActivity.this, "Enter note!", Toast.LENGTH_SHORT).show();
return;
} else {
alertDialog.dismiss();
}
// check if user updating note
if (shouldUpdate && note != null) {
// update note by it's id
updateNote(inputNote.getText().toString(), position);
} else {
// create new note
createNote(inputNote.getText().toString());
}
}
});
}
/**
* Toggling list and empty notes view
*/
private void toggleEmptyNotes() {
// you can check notesList.size() > 0
if (db.getNotesCount() > 0) {
noNotesView.setVisibility(View.GONE);
} else {
noNotesView.setVisibility(View.VISIBLE);
}
}
}
NotesAdapter.java
package com.example.zaphk.studenthelperapplication3.view;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.example.zaphk.studenthelperapplication3.calendar.database.Calendar;
import com.example.zaphk.studenthelperapplication3.database.model.Note;
import com.example.zaphk.studenthelperapplication3.R;
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.MyViewHolder> {
private Context context;
private List<Note> notesList;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView note;
public TextView dot;
public TextView timestamp;
public MyViewHolder(View view) {
super(view);
note = view.findViewById(R.id.note);
dot = view.findViewById(R.id.dot);
timestamp = view.findViewById(R.id.timestamp);
}
}
public NotesAdapter(Context context, List<Note> notesList) {
this.context = context;
this.notesList = notesList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.note_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Note note = notesList.get(position);
holder.note.setText(note.getNote());
// Displaying dot from HTML character code
holder.dot.setText(Html.fromHtml("•"));
// Formatting and displaying timestamp
holder.timestamp.setText(formatDate(note.getTimestamp()));
}
#Override
public int getItemCount() {
return notesList.size();
}
/**
* Formatting timestamp to `MMM d` format
* Input: 2018-02-21 00:15:42
* Output: Feb 21
*/
private String formatDate(String dateStr) {
try {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = fmt.parse(dateStr);
SimpleDateFormat fmtOut = new SimpleDateFormat("MMM d");
return fmtOut.format(date);
} catch (ParseException e) {
}
return "";
}
}
activity_notes.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coordinator_layout"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zaphk.studenthelperapplication3.view.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main_timetable" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#drawable/ic_add_white_24dp" />
</android.support.design.widget.CoordinatorLayout>
note_list_row.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/coordinator_layout"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zaphk.studenthelperapplication3.view.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main_timetable" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#drawable/ic_add_white_24dp" />
</android.support.design.widget.CoordinatorLayout>
content_main_timetable.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".activities.TimetableActivity"
tools:showIn="#layout/app_bar_main">
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/baseline_add_white_24"
tools:layout_editor_absoluteX="339dp"
tools:layout_editor_absoluteY="546dp" />
</FrameLayout>
There is no RecyclerView in your layout file, so when you call findViewById, no view is found, and your recyclerView is null, which is the reason for your null pointer exception.
In content_main_timetable did you mean RecyclerView instead of ViewPager? Replacing the view pager with a recycler view called recycler_view would fix your problem.
Your layout doesn't have a recyclerView. Which is why, findViewById returns a null. Your recyclerView is null, so you can't really set a layoutmanager on it. Fix your activity layout to include a recyclerview.
Using Android's Studio I started with a Navigation Drawer activity. Then I added a Master Detail activity making a "real" class from the DummyContent class template. The application works when hard coding the items. My needs are to use multiple languages so I must use strings.xml for the language translations.
I extended ProductsAZ.java using Activity trying unsuccessfully to use "this" and "getString()". I can assign String header1 = getString(R.string.header1);. How do I use this design/class to call strings from strings.xml when adding a new Product item?
addItem(new Product("1", "1_Title_here", "1_Header_here", "1_Body_here"));
addItem(new Product("2", "2_Title_here", "2_Header_here", "2_Body_here"));
addItem(new Product("3", "3_Title_here", "3_Header_here", "3_Body_here"));
Desire is:
addItem(new Product("1", "#string/1_Title_here", "#string/1_Header_here", "#string/1_Body_here"));
ProductAZ.java
import android.app.Activity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ProductAZ extends Activity {
// An array of items.
// public static List<Product> ITEMS = new ArrayList<>();
public static List<Product> ITEMS = new ArrayList<>();
// A map of items, by ID.
public static Map<String, Product> ITEM_MAP = new HashMap<>();
// Add items.
static {
addItem(new Product("1", "1_Title_here", "1_Header_here", "1_Body_here"));
addItem(new Product("2", "2_Title_here", "2_Header_here", "2_Body_here"));
addItem(new Product("3", "3_Title_here", "3_Header_here", "3_Body_here"));
}
private static void addItem(Product product) {
ITEMS.add(product);
ITEM_MAP.put(product.id, product);
}
// An item representing a piece of content.
public static class Product {
public final String id;
public final String title;
public final String header;
public final String details;
public Product(String id, String title, String header, String details) {
this.id = id;
this.title = title;
this.header = header;
this.details = details;
}
#Override
public String toString() {
return title;
}
}
}
ProductListActivity.java
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
import android.view.MenuItem;
import java.util.List;
/**
* An activity representing a list of Products. This activity
* has different presentations for handset and tablet-size devices. On
* handsets, the activity presents a list of items, which when touched,
* lead to a {#link ProductDetailActivity} representing
* item details. On tablets, the activity presents the list of items and
* item details side-by-side using two vertical panes.
*/
public class ProductListActivity extends AppCompatActivity {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_list);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle(getTitle());
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
// Show the Up button in the action bar.
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
View recyclerView = findViewById(R.id.product_list);
assert recyclerView != null;
setupRecyclerView((RecyclerView) recyclerView);
if (findViewById(R.id.product_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-w900dp).
// If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
private void setupRecyclerView(#NonNull RecyclerView recyclerView) {
recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(ProductAZ.ITEMS));
}
public class SimpleItemRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {
private final List<ProductAZ.Product> mValues;
public SimpleItemRecyclerViewAdapter(List<ProductAZ.Product> items) {
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.product_list_content, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mIdView.setText(mValues.get(position).id);
holder.mContentView.setText(mValues.get(position).title);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(ProductDetailFragment.ARG_ITEM_ID, holder.mItem.id);
ProductDetailFragment fragment = new ProductDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.product_detail_container, fragment)
.commit();
} else {
Context context = v.getContext();
Intent intent = new Intent(context, ProductDetailActivity.class);
intent.putExtra(ProductDetailFragment.ARG_ITEM_ID, holder.mItem.id);
context.startActivity(intent);
}
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView mIdView;
public final TextView mContentView;
public ProductAZ.Product mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mIdView = (TextView) view.findViewById(R.id.id);
mContentView = (TextView) view.findViewById(R.id.content);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
}
}
}
ProductDetailFragment.java
import android.app.Activity;
import android.support.design.widget.CollapsingToolbarLayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A fragment representing a single Product detail screen.
* This fragment is either contained in a {#link ProductListActivity}
* in two-pane mode (on tablets) or a {#link ProductDetailActivity}
* on handsets.
*/
public class ProductDetailFragment extends Fragment {
/**
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
// The content this fragment is presenting.
// private ProductAZ.Product mItem;
private ProductAZ.Product mProduct;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public ProductDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the content specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load content from a content provider.
mProduct = ProductAZ.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
Activity activity = this.getActivity();
CollapsingToolbarLayout appBarLayout = (CollapsingToolbarLayout) activity.findViewById(R.id.toolbar_layout);
if (appBarLayout != null) {
appBarLayout.setTitle(mProduct.title);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.product_detail, container, false);
// Show the content as text in a TextView.
if (mProduct != null) {
((TextView) rootView.findViewById(R.id.product_detail)).setText(mProduct.details);
}
return rootView;
}
}
ProductDetailActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
/**
* An activity representing a single Product detail screen. This
* activity is only used narrow width devices. On tablet-size devices,
* item details are presented side-by-side with a list of items
* in a {#link ProductListActivity}.
*/
public class ProductDetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own detail action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
// Show the Up button in the action bar.
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don't need to manually add it.
// For more information, see the Fragments API guide at:
//
// http://developer.android.com/guide/components/fragments.html
//
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(ProductDetailFragment.ARG_ITEM_ID,
getIntent().getStringExtra(ProductDetailFragment.ARG_ITEM_ID));
ProductDetailFragment fragment = new ProductDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.product_detail_container, fragment)
.commit();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, ProductListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
product_detail.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/product_detail"
style="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:textIsSelectable="true"
tools:context="com.bobh.znd6.ProductDetailFragment"/>
product_list.xml (small display)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/product_list"
android:name="com.bobh.znd5.ProductListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="com.bobh.znd6.ProductListActivity"
tools:listitem="#layout/product_list_content"/>
product_list_content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem"/>
<TextView
android:id="#+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem"/>
</LinearLayout>
Solved. I found the solution in link. I needed to delete my switch statement in ProductAZ.java. Then in DetailListActivity.java I edited the onCreate method. Using the prior post's outline fitting my class/method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DummyContent.ITEMS.isEmpty())
{
DummyContent.addItem(new DummyItem("1", getResources().getString(R.string.menu1)));
DummyContent.addItem(new DummyItem("2", getResources().getString(R.string.menu2)));
DummyContent.addItem(new DummyItem("3", getResources().getString(R.string.menu3)));
}
I'm new at this but I already made a small app that worked the same way.
I can't see what I'm doing wrong because the code looks quiet the same as my previous app.
When I run it or debug my app it shows my layout on my emulator so it does load the page that has to be loaded but that's all it does, it doesn't listen to button clicks. I also gives me no errors.
Here's my XML code for fragment_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity$PlaceholderFragment">
<TextView
android:text="Eventaris"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="100px"
android:textStyle="bold"
android:id="#+id/lblEventaris"
/>
<LinearLayout
android:layout_width="500px"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:orientation="vertical"
android:id="#+id/login">
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Gebruikersnaam"
android:id="#+id/txtGebruikersnaam"/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="Wachtwoord"
android:inputType="textPassword"
android:layout_below="#id/txtGebruikersnaam"
android:id="#+id/txtWachtwoord"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Inloggen"
android:id="#+id/btnInloggen"
android:layout_below="#id/txtWachtwoord"/>
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:layout_below="#id/login">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="nog geen account?"
android:gravity="center"
android:id="#+id/lblRegistratie"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Registeren"
android:id="#+id/btnRegistreren"
android:layout_below="#id/lblRegistratie"/>
</RelativeLayout>
</RelativeLayout>
Here's my fragmennt activity MainFragment.Java
package com.example.arno.eventaris;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import java.sql.SQLException;
/**
* Created by Arno on 28/04/2015.
*/
public class MainFragment extends Fragment {
private OnMainFragmentInteractionListener mListener;
private View view;
public MainFragment()
{
//required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
view=inflater.inflate(R.layout.fragment_main, container, false);
Button btnInloggen = (Button) view.findViewById(R.id.btnInloggen);
btnInloggen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
inloggen();
} catch (SQLException e) {
e.printStackTrace();
}
}
});
Button btnRegistreren = (Button) view.findViewById(R.id.btnRegistreren);
btnRegistreren.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
navigeerRegistratie();
}
});
return view;
}
#Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try{
mListener = (OnMainFragmentInteractionListener) activity;
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString() + "must implement OnFragmentInteractionListener");
}
}
public void inloggen() throws SQLException {
EditText gebr=(EditText) view.findViewById(R.id.txtGebruikersnaam);
EditText wachtw=(EditText) view.findViewById(R.id.txtWachtwoord);
String gebruiker = gebr.getText().toString();
String wachtwoord = wachtw.getText().toString();
mListener.login(gebruiker, wachtwoord);
}
public void navigeerRegistratie()
{
mListener.navigeerRegistratie();
}
#Override
public void onDetach()
{
super.onDetach();
mListener = null;
}
public interface OnMainFragmentInteractionListener {
//Todo: Update argument type and name
public void login(String gebruiker, String wachtwoord) throws SQLException;
public void navigeerRegistratie();
}
}
Here is my Main Activity MainActivity.java
package com.example.arno.eventaris;
import android.app.DialogFragment;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.example.arno.eventaris.Database.DBAdapter;
import java.sql.SQLException;
public class MainActivity extends ActionBarActivity implements MainFragment.OnMainFragmentInteractionListener,RegistratieFragment.OnRegistratieFragmentInteractionListener{
private Cursor gebruikerCursor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void login(String gebruiker, String wachtwoord) throws SQLException {
DBAdapter db = new DBAdapter(this);
db.open();
gebruikerCursor = db.getGebruiker(gebruiker);
if(gebruikerCursor.moveToFirst()) {
gebruikerCursor.moveToFirst();
String wwControle = gebruikerCursor.getString(gebruikerCursor.getColumnIndex("wachtwoord"));
if (wachtwoord.equals(wwControle)) {
HomeFragment fragment = new HomeFragment();
Bundle bundle = new Bundle();
bundle.putString("gebruikersnaam", gebruiker);
fragment.setArguments(bundle);
getFragmentManager().beginTransaction().replace(R.id.container, fragment).commit();
} else {
DialogFragment errorlogin = new ErrorLogin();
errorlogin.show(getFragmentManager(), "Wachtwoord incorrect!");
}
}
else
{
DialogFragment errorlogin = new ErrorLogin();
errorlogin.show(getFragmentManager(), "Gebruikersnaam incorrect!");
}
db.close();
}
#Override
public void navigeerRegistratie() {
getFragmentManager().beginTransaction().replace(R.id.container, new RegistratieFragment()).commit();
}
#Override
public void registreren(String gebruiker, String voornaam, String naam, String email, String wachtwoord, String herhaalWachtwoord) {
if(wachtwoord.equals(herhaalWachtwoord)) {
DBAdapter db = new DBAdapter(this);
db.open();
long id = db.insertGebruiker(gebruiker, voornaam, naam, email, wachtwoord);
getFragmentManager().beginTransaction().replace(R.id.container, new MainFragment()).commit();
}
else
{
DialogFragment errorregistratie = new ErrorRegistratie();
errorregistratie.show(getFragmentManager(), "Wachtwoorden komen niet overeen!");
}
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
And as last here is my activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="#+id/container"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity" tools:ignore="MergeRootFrame" />
Thanks in advance!
Fixed it by making a new project with the same code, had to be a problem way deeper than my code.
I had a gridview activity where I was populating the gridview with a custom object (a picture with some custom methods and an onclick listener). I could change the gridview size from the preferences menu. Everything worked beautifully.
I have since added some complexity to the code. Instead of using the normal Activity class, I am now using the FragmentActivity class, a fragmentPageAdapter, and a fragment to which my gridview is bound. This is because eventually I want the app to allow the user "swipe" from fragment to fragment.
Since using the fragment in this way, I am noticing a repeatable bug whenever I try to resize the gridview from the preferences menu: some of the objects get resized properly, other elements do not resize. Instead, they keep the same size that they had prior to changing the preference. Here is a screenshot:
This only happens when I try resizing from the preferences menu. Other calls to my resize method, such as on a configuration change, resize all of the gridview elements correctly.
I would appreciate any suggestions!
Here is my Code:
MAIN ACTIVITY:
package com.KhalidSorensen.animalsounds;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.GridView;
public class MainActivity extends FragmentActivity implements OnSharedPreferenceChangeListener{
private MyFragment m_myFragment = new MyFragment();
private ViewPager m_viewPager;
private static SharedPreferences m_prefs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
m_prefs = PreferenceManager.getDefaultSharedPreferences(this);
m_prefs.registerOnSharedPreferenceChangeListener(this);
setContentView(R.layout.activity_main);
m_viewPager = (ViewPager) findViewById(R.id.pager);
m_viewPager.setAdapter(new MyAdapter(getSupportFragmentManager(), m_myFragment));
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.i("Khalid","MainActivity: onSharedPreferenceChanged");
if (key.equals("key_prefs_enable_lscape")){
//do nothing for now
}else if (key.equals("key_prefs_picture_size")){
SetColumnWidth(m_myFragment.getM_gridView());
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i("Khalid","FragAnimalSounds: onConfigurationChanged");
SetColumnWidth(m_myFragment.getM_gridView());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i("Khalid","MainActivity: onCreateOptionsMenu");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.lbl_opt_menu_settings:
Intent i = new Intent("android.intent.action.PREFERENCES");
startActivity(i);
break;
case R.id.lbl_opt_menu_quit:
finish();
break;
default:
finish();
break;
}
return true;
}
public static void SetColumnWidth(GridView GV) {
Log.i("Khalid","MainActivity: SetColumnWidth");
int NumColumns, DesiredColumnWidth;
//Get the desired number of columns from the key prefs
NumColumns = Integer.parseInt(m_prefs.getString("key_prefs_picture_size","2"));
//Determine the desired column width
if (NumColumns == 1){
DesiredColumnWidth = 200;
}else if (NumColumns == 2){
DesiredColumnWidth = 100;
}else{
DesiredColumnWidth = 50;
}
//Set the desired column width
GV.setColumnWidth(DesiredColumnWidth);
}
}
class MyAdapter extends FragmentPagerAdapter{
Fragment m_frag_A = null;
public MyAdapter(FragmentManager fm, Fragment A) {
super(fm);
m_frag_A = A;
}
#Override
public Fragment getItem(int i) {
return m_frag_A; //only 1 item for now
}
#Override
public int getCount() {
return 1;
}
#Override
public CharSequence getPageTitle(int i) {
return "Title Frag A"; //only 1 item for now
}
}
MY FRAGMENT (THERE IS ONLY ONE FOR NOW):
package com.KhalidSorensen.animalsounds;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
public class MyFragment extends Fragment {
private GridView m_gridView;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.i("Khalid","FragAnimalSounds: onCreateView");
View view = inflater.inflate(R.layout.activity_animal_sounds, container, false);
m_gridView = (GridView) view.findViewById(R.id.lbl_gridView);
m_gridView.setAdapter(new VivzAdapter(view.getContext()));
MainActivity.SetColumnWidth(m_gridView);
return view;
}
public GridView getM_gridView() {
return m_gridView;
}
}
MY GRIDVIEW ADAPTER:
package com.KhalidSorensen.animalsounds;
import java.util.ArrayList;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class VivzAdapter extends BaseAdapter {
private Context m_context;
private ArrayList<AnimalKind> m_list = new ArrayList<AnimalKind>();
VivzAdapter(Context ctx) {
m_context = ctx;
int[] animalphotos = { R.drawable.cat_1, R.drawable.cow_1,
R.drawable.dog_1, R.drawable.donkey_1, R.drawable.duck_1,
R.drawable.peacock_1, R.drawable.rooster_1, R.drawable.seal_1 };
for (int i = 0; i <= 7; i++) {
AnimalKind animalKind = new AnimalKind(m_context, animalphotos[i]);
m_list.add(animalKind);
}
}
#Override
public int getCount() {
return m_list.size();
}
#Override
public AnimalKind getItem(int position) {
return m_list.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int i, View v, ViewGroup vg) {
return m_list.get(i);
}
}
MY CUSTOM OBJECT CLASS. THESE OBJECTS ARE POPULATING THE GRIDVIEW:
package com.KhalidSorensen.animalsounds;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
public class AnimalKind extends ImageView implements OnClickListener{
private int m_imageId;
public AnimalKind(Context ctx, int imageId) {
super(ctx);
m_imageId = imageId;
super.setImageResource(imageId);
super.setAdjustViewBounds(true);
super.setScaleType(ImageView.ScaleType.FIT_XY);
super.setPadding(1, 1, 1, 1);
super.setBackgroundColor(Color.BLACK);
super.setOnClickListener(this);
}
//#Override
public void onClick(View v) {
//Do Something
}
#Override
public void setPressed(boolean pressed) {
//Do Something
}
public int getM_imageId() {
return m_imageId;
}
}
MY PREFERENCE ACTIVITY:
package com.KhalidSorensen.animalsounds;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.util.Log;
public class Preferences extends PreferenceActivity {
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
Log.i("Khalid", "Preferences: onCreate");
}
}
MY XML FOR MY MAIN ACTIVITY:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.view.PagerTitleStrip
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/lbl_title"
android:background="#33B5E5"
android:layout_gravity="top"
android:paddingTop="0dp"
android:paddingBottom="0dp"> "
</android.support.v4.view.PagerTitleStrip>
</android.support.v4.view.ViewPager>
AND FINALLY, MY XML FOR THE GRIDVIEW:
<?xml version="1.0" encoding="utf-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lbl_gridView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:layout_margin="0px"
android:alwaysDrawnWithCache="false"
android:animateLayoutChanges="false"
android:background="#android:color/white"
android:columnWidth="130dp"
android:drawSelectorOnTop="true"
android:horizontalSpacing="#dimen/activity_horizontal_margin"
android:listSelector="#null"
android:numColumns="auto_fit"
android:padding="#dimen/activity_horizontal_margin"
android:scrollbarStyle="insideOverlay"
android:smoothScrollbar="true"
android:stretchMode="none"
android:verticalSpacing="#dimen/activity_vertical_margin" >
</GridView>
Use CENTER_INSIDE a scale type for your image view.
super.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
another thing that I would change is the way you handle the column width. I would remove the android:numColumns="auto_fit". On the other hand you know that the number of columns is the cealing of WidthViewGrid/desiderePicSize, where the most common case for WidthViewGrid is the screen's width. On then programmatically you can set number of columns of your GridView with setNumberOfColumns
I would say:
A. After calling setColumnWidth call the gridview.invalidate()
B. After returning from the change preference - call adapter's notifyDataSetChanged in order to make sure it re-creates the views in the adapter (i.e. getView will be called)
Here's my error:
*** Uncaught remote exception! (Exceptions are not yet supported across processes.)
android.util.AndroidRuntimeException: { what=1008 when=368280372 } This message is already in use.
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:171)
at android.os.Handler.sendMessageAtTime(Handler.java:457)
at android.os.Handler.sendMessageDelayed(Handler.java:430)
at android.os.Handler.sendMessage(Handler.java:367)
at android.view.ViewRoot.dispatchAppVisibility(ViewRoot.java:2748)
What I'm attempting is to have a listview, that is populated by custom list items, each list item has multiple views and each view has an onclick listener attached. When this onClickListener is pressed it sends a Message to a Handler with a what and arg1 arguments.
Clicking one of my elements fires an intent to start a new activity.
Clicking the other shows a toast.
When these are pressed in a combination I get the error above. Namely clicking the text to fire the intent, (then press back) then clicking the image to show the toast, then when you click the text to fire the intent again I get the FC.
And here is the code below, I tried to remove as much cruft as I could to get to the bones of the error:
If you want to skip to whats important look at the onClickListener's in ConversationAdapter.class and how they interact with StartPage.class
Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.handler.test"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".StartPage"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DetailsPage"
android:label="DetailsPage"
>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
StartPage.class:
package com.handler.test;
import java.util.ArrayList;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
public class StartPage extends ListActivity {
private ArrayList<Conversation> mConversations = null;
private ConversationAdapter mAdapter;
private Context mContext;
private ProgressDialog mProgressDialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this;
mConversations = new ArrayList<Conversation>();
this.mAdapter = new ConversationAdapter(mContext, R.layout.inbox_row, mConversations, mHandler);
setListAdapter(this.mAdapter);
new Thread(new Runnable() {
#Override
public void run() {
getConversations();
}
}).start();
mProgressDialog = ProgressDialog.show(StartPage.this, "Please wait...", "Retrieving data ...", true);
}
private void getConversations() {
try {
mConversations = new ArrayList<Conversation>();
Conversation o1 = new Conversation();
o1.setStatus("SF services");
o1.setMessage("Pending");
mConversations.add(o1);
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
private Runnable returnRes = new Runnable() {
#Override
public void run() {
if(mConversations != null && mConversations.size() > 0){
mAdapter.notifyDataSetChanged();
for(int i=0;i<mConversations.size();i++)
mAdapter.add(mConversations.get(i));
}
mProgressDialog.dismiss();
mAdapter.notifyDataSetChanged();
}
};
private Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
int convIndex = msg.arg1;
int viewTouched = msg.what;
switch(viewTouched){
case ConversationAdapter.PROF_ICON:
showNumber(convIndex);
break;
case ConversationAdapter.MESSAGE:
showMessageDetails(convIndex);
break;
}
super.handleMessage(msg);
}
};
private void showNumber(int convIndex) {
Toast.makeText(mContext, "Pressed: "+convIndex, Toast.LENGTH_LONG).show();
}
private void showMessageDetails(int convIndex) {
final Conversation conv = mConversations.get(convIndex);
Intent i = new Intent(mContext, DetailsPage.class);
i.putExtra("someExtra", conv);
startActivity(i);
}
}
DetailsPage.class
package com.handler.test;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class DetailsPage extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i("Test", "Details Page");
}
}
Conversation.class:
package com.handler.test;
import java.io.Serializable;
public class Conversation implements Serializable {
private static final long serialVersionUID = -437261671361122258L;
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
ConversationAdapter.class:
package com.handler.test;
import java.util.ArrayList;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class ConversationAdapter extends ArrayAdapter<Conversation> {
public static final int PROF_ICON = 0;
public static final int MESSAGE = 1;
private Context mContext;
private Handler mHandler;
private ArrayList<Conversation> mItems;
private int mXmlId;
private LinearLayout detailsOfConv;
private ImageView iconImage;
public ConversationAdapter(Context context, int textViewResourceId, ArrayList<Conversation> items, Handler handler) {
super(context, textViewResourceId, items);
this.mContext = context;
this.mItems = items;
this.mXmlId = textViewResourceId;
this.mHandler = handler;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(mXmlId, null);
}
final Message m = new Message();
m.arg1 = position;
Conversation c = mItems.get(position);
if (c != null) {
iconImage = (ImageView) v.findViewById(R.id.icon);
if (iconImage != null) {
iconImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
m.what = PROF_ICON;
mHandler.sendMessage(m);
}
});
}
detailsOfConv = (LinearLayout) v.findViewById(R.id.details);
if(detailsOfConv != null){
detailsOfConv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
m.what = MESSAGE;
mHandler.sendMessage(m);
}
});
}
}
return v;
}
}
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip"
>
<ListView
android:id="#+id/android:list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:cacheColorHint="#00000000"
/>
</LinearLayout>
inbox_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"
android:src="#drawable/icon" />
<LinearLayout
android:id="#+id/details"
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">
<TextView
android:id="#+id/toptext"
android:textColor="#99FF66"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:singleLine="true"
android:text="123456789"
/>
</LinearLayout>
</LinearLayout>
My guess would be that you are sending twice the same message. Indeed in the code there is one new Message() and two mHandler.sendMessage(m) which are possibly both executed.
Try making a new message for every time you send a message.
Edited:
Message.obtain() is preferable to Message m = new Message() (because it recycles used messages under the hood)
In your case you could use new.copyFrom(old) if you need a copy of existing message.