I am writing an app to pull movie data from the MovieDB api and display the information in a GridView.
When the app first loads I would expect the view to populate initially, but it does not. I have a sort option in the menu bar and when the sort option is set the first time the GridView is populated by movies in order of popularity, as it should initially, but regardless of what sort criteria is actually selected.
I have used the logs to determine that the correct data is being retrieved from the API and being processed properly, so I have to assume that the adapter is not updating the view properly.
Why isn't the view showing initially or updating as it should?
FilmFragment.java:
public class FilmFragment extends Fragment {
private ArrayList<FilmParcelable> filmParcels = new ArrayList<FilmParcelable>();
private ImageAdaptor mFilmAdaptor;
protected String[] sortOptions = {
"popularity.desc",
"vote_average.desc"
};
protected String sortBy = sortOptions[0];
private final String LOG_TAG = FilmFragment.class.getSimpleName();
public FilmFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if (savedInstanceState == null || !savedInstanceState.containsKey("films")){
updateFilms();
mFilmAdaptor = new ImageAdaptor(getActivity(),filmParcels);
} else {
filmParcels = savedInstanceState.getParcelableArrayList("films");
mFilmAdaptor = new ImageAdaptor(getActivity(),filmParcels);
}
// allow fragment to handle menu events
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
inflater.inflate(R.menu.filmfragment, menu);
}
public boolean onOptionsItemSelected(MenuItem item){
//Handle action bar item clicks. 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();
if (id == R.id.action_sort){
showSortDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onSaveInstanceState(Bundle outState){
outState.putParcelableArrayList("films", filmParcels);
super.onSaveInstanceState(outState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
// Find GridView to populate with poster images
GridView gridView = (GridView) rootView.findViewById(R.id.gridView);
// Set the adaptor of the GridView to my ImageAdaptor
gridView.setAdapter(mFilmAdaptor);
updateAdaptor();
return rootView;
}
// Update movie data in case there is a change in the "sort by" option
// Or the fragment is started with no saved data
public void updateFilms(){
new FetchFilmTask().execute();
}
public void updateAdaptor(){
mFilmAdaptor.clear();
mFilmAdaptor.addAll(filmParcels);
mFilmAdaptor.notifyDataSetChanged();
}
// Show dialog sort pop up
public void showSortDialog(){
DialogFragment dialog = new SortDialog();
dialog.setTargetFragment(this, 0);
dialog.show(getActivity().getSupportFragmentManager(), "SortDialog");
}
// If a fragment or activity called by this fragment returns to this fragment,
// Get the information returned via the intent
public void onActivityResult(int requestCode, int resultCode, Intent data){
if (requestCode == 0){
int mSelected = data.getIntExtra("Selected Option", -1);
if (mSelected != -1){
sortBy = sortOptions[mSelected];
updateFilms();
updateAdaptor();
}
}
}
// Class to get JSON data from The Movie Database API
public class FetchFilmTask extends AsyncTask<Void, Void, FilmParcelable[]> {
private final String LOG_TAG = FetchFilmTask.class.getSimpleName();
private final String MOVIE_DB_API_KEY = "e1968ef8ba074d7d5bf07a59de8b2310";
protected FilmParcelable[] doInBackground(Void... params){
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain raw JSON response as a string
String movieDBStr = null;
try {
// Construct URL for Movie DB query
Uri.Builder builder = new Uri.Builder();
builder.scheme("http")
.authority("api.themoviedb.org")
.appendPath("3")
.appendPath("discover")
.appendPath("movie")
.appendQueryParameter("api_key", MOVIE_DB_API_KEY)
.appendQueryParameter("sort_by", sortBy);
String myUrl = builder.build().toString();
Log.d(LOG_TAG, myUrl);
URL url = new URL(myUrl);
// Create the request to The Movie DB, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null){
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
movieDBStr = buffer.toString();
} catch (IOException e){
Log.e(LOG_TAG, "Error: ", e);
return null;
} finally {
if (urlConnection != null){
urlConnection.disconnect();
}
if (reader != null){
try{
reader.close();
} catch (final IOException e){
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
try {
return getFilmDataFromJson(movieDBStr);
} catch (JSONException e){
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
return null;
}
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private FilmParcelable[] getFilmDataFromJson(String movieDBStr)
throws JSONException {
// JSON objects that need to be extracted
final String MDB_RESULTS = "results";
final String MDB_ID = "id";
final String MDB_SYNOPSIS = "overview";
final String MDB_RELEASE = "release_date";
final String MDB_POSTER = "poster_path";
final String MDB_TITLE = "title";
final String MDB_RATING = "vote_average";
JSONObject filmJson = new JSONObject(movieDBStr);
JSONArray filmArray = filmJson.getJSONArray(MDB_RESULTS);
FilmParcelable[] resultFilms = new FilmParcelable[filmArray.length()];
for (int i = 0; i < filmArray.length(); i++){
// Data needed by the FilmParcelable
int id;
String title;
String releaseDate;
String posterUrl;
Double voteAverage;
String plotSynopsis;
JSONObject film = filmArray.getJSONObject(i);
id = film.getInt(MDB_ID);
plotSynopsis = film.getString(MDB_SYNOPSIS);
releaseDate = film.getString(MDB_RELEASE);
posterUrl = "http://image.tmdb.org/t/p/w300" + film.getString(MDB_POSTER);
title = film.getString(MDB_TITLE);
voteAverage = film.getDouble(MDB_RATING);
Log.d(LOG_TAG, title);
Log.d(LOG_TAG, posterUrl);
resultFilms[i] = new FilmParcelable(id, title, releaseDate, posterUrl, voteAverage, plotSynopsis);
}
return resultFilms;
}
#Override
protected void onPostExecute(FilmParcelable[] result){
if (result != null){
filmParcels = new ArrayList<>(Arrays.asList(result));
}
}
}
}
ImageAdaptor.java:
public class ImageAdaptor extends ArrayAdapter<FilmParcelable> {
public ImageAdaptor(Activity context, ArrayList<FilmParcelable> filmParcels){
super(context, 0, filmParcels);
}
public View getView(int position, View convertView, ViewGroup parent){
Context context= getContext();
View gridView;
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
String mUrl = getItem(position).getUrl();
if (convertView == null) {
gridView = inflater.inflate(R.layout.gridview_film_layout, parent, false);
// Find the image view from the gridview_film_layout
ImageView posterView = (ImageView) gridView.findViewById(R.id.grid_item_image);
// Set the image view to contain image located at mUrl
Picasso.with(getContext()).load(mUrl).into(posterView);
} else {
gridView = convertView;
}
return gridView;
}
}
accordingly to the code you posted you are returning over and over the same cell of your GridView. You should have those two lines
ImageView posterView = (ImageView) gridView.findViewById(R.id.grid_item_image);
Picasso.with(getContext()).load(mUrl).into(posterView);
out of the if/else guard:
if (convertView == null) {
// inflate
} else {
// gridView = convertView;
}
ImageView posterView = (ImageView) gridView.findViewById(R.id.grid_item_image);
Picasso.with(getContext()).load(mUrl).into(posterView);
return gridView;
I was attempting to update the adapter after populating the arraylist used for the adapter. However the arraylist was populated and updated in the background so the code:
updateFilms();
updateAdaptor();
was causing the adaptor to update before the data had completed loading in the background.
After fixing that Blackbelt's solution was correct.
Related
Now in detail. I am writing an App for a dictionary. For that I have created a custom Object called Word. This Word contains the term and its' corresponding translation:
public class Word implements Serializable {
private int _id;
private int wordType;
private String engWordSi;
private String okyWordPl;
private String engWordPl;
private String okyWordSi;
private String engEx;
private String okyEx;
/** Creates a custom class, which allows save a term, it's translation, as well as the plural and example in both
* languages
* #param _id saves the Id of the Word in the Database
* #param engWordSi saves the English translation of the word
* #param okyWordSi saves the Oshikwanyama translation of the word
* #param wordType saves the type of word in form of a number:
* 0 = phrase; 1 = noun; 2 = verb; 3 = adjective; 4 = pronoun; 5 = other
*/
public Word(int _id, int wordType, String engWordSi, String okyWordSi){
this._id = _id;
this.wordType = wordType;
this.engWordSi = engWordSi;
this.okyWordSi = okyWordSi;
}public int get_id(){
return _id;
}
public void set_id(int i){
_id = i;
}
public int getWordType(){
return wordType;
}
public void setWordType(int i){
if(i < 0 || i > 6){
return;
}
wordType = i;
}
public String getEngWordSi(){
return engWordSi;
}
public void setEngWordSi(String word){
engWordSi = word;
}
public String getOkyWordSi(){
return okyWordSi;
}
public void setOkyWordSi(String word){
okyWordSi = word;
}
public String getEngWordPl(){
return engWordPl;
}
public void setEngWordPl(String word){
engWordPl = word;
}
public String getOkyWordPl(){
return okyWordPl;
}
public void setOkyWordPl(String word){
okyWordPl = word;
}
public String getEngEx(){
return engEx;
}
public void setEngEx(String word){
engEx = word;
}
public String getOkyEx(){
return okyEx;
}
public void setOkyEx(String word){
okyEx = word;
}
The data is loaded via a php file connected to the database. The ORDER BY statement only allows me to choose one language to order the results by. But what I need is, that the search term, which might be found in words of both languages, defines if the English word or the Oshikwanyama word is the word which is being arranged in the order. I have check which translation to use in each case. My guess would be to do it in onPostExecute(). The data is returned by the PHP file in the JSON format. From there I put them into an ArrayList.
private class Query extends AsyncTask<Void, Void, Void>{
#Override
protected void onPostExecute(Void aVoid) {
try{
JSONArray jsonArray = new JSONArray(result);
for (int i = 0; i < jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
Word word = new Word(jsonObject.getInt("_id"), jsonObject.getInt("type"), jsonObject.getString("eng"), jsonObject.getString("oky") );
arrayList.add(word);
Log.d("JSON", word.toString());
}
}catch (JSONException e){
e.printStackTrace();
}
ProgressBar bar = (ProgressBar) findViewById(R.id.bar);
bar.setVisibility(View.GONE);
Button button = (Button) findViewById(R.id.SearchButton);
button.setVisibility(View.VISIBLE);
super.onPostExecute(aVoid);
if (arrayList.isEmpty()){
Toast.makeText(SearchActivity.this, "Unfortunately there were no results, the missing word was sent to our developers.", Toast.LENGTH_LONG).show();
return;
}
Intent intent = new Intent(SearchActivity.this, ResultActivity.class);
ItemDetailsWrapper wrapper = new ItemDetailsWrapper(arrayList);
intent.putExtra("results", wrapper);
intent.putExtra("term", searchTerm);
startActivity(intent);
}
InputStream inputStream = null;
String result = "";
#Override
protected void onPreExecute() {
if (arrayList != null){
arrayList.clear();}
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
try{
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(uri.toString());
//httpPost.setEntity(new UrlEncodedFormEntity(null));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
inputStream = httpEntity.getContent();
}
catch (UnsupportedEncodingException e1){
e1.printStackTrace();
} catch (ClientProtocolException e2){
e2.printStackTrace();
}catch (IllegalStateException e3){
e3.printStackTrace();
}catch (IOException e4){
e4.printStackTrace();
}try{
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = bufferedReader.readLine()) != null){
stringBuilder.append(line + "\n");
}
inputStream.close();
result = stringBuilder.toString();
}catch (IOException e){
e.printStackTrace();
}
return null;
}
}}
I already have a place to check whether the term searched for is contained in the English or Oshikwanyama word. There I use it to define the flag used in the layout.
public class WordAdapter extends ArrayAdapter<Word> {
private Context mContext;
private List<Word> wordList = new ArrayList<>();
private int srcCode;
private String term;
/** uses words and puts them into a list
*
* #param context stores the context of the calling activity
* #param list stores the ArrayList that was passed into the constructor, and which contains the
* content
* #param searchTerm stores the term that was searched for in SearchActivity to later compare it
* to the contents of the Word and to arrange the correct flag for the source
* language
*/
public WordAdapter(#NonNull Context context, ArrayList<Word> list, String searchTerm) {
super(context, 0 , list);
mContext = context;
wordList = list;
term = searchTerm;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listItem = convertView;
if(listItem == null){
listItem = LayoutInflater.from(mContext).inflate(R.layout.list_item,parent,false);}
final Word currentWord = wordList.get(position);
//Add Images for the flags of the countries and the flag
final TextView sourceTerm = (TextView) listItem.findViewById(R.id.searchTerm);
final TextView translationTerm = (TextView) listItem.findViewById(R.id.translationTerm);
ImageView flag = (ImageView) listItem.findViewById(R.id.src_flag);
ImageButton button = (ImageButton) listItem.findViewById(R.id.flag);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), EditorActivity.class);
intent.putExtra("mode", "report");
intent.putExtra("id", currentWord.get_id());
intent.putExtra("source", sourceTerm.getText());
intent.putExtra("trans", translationTerm.getText());
getContext().startActivity(intent);
}
});
if (currentWord.getOkyWordPl() == null){
currentWord.setOkyWordPl("");
}
if (currentWord.getEngWordPl() == null){
currentWord.setEngWordPl("");
}
if (currentWord.getEngWordSi().contains(term) || currentWord.getEngWordPl().contains(term)){
srcCode = 0;
}
if (currentWord.getOkyWordSi().contains(term) || currentWord.getOkyWordPl().contains(term)){
srcCode = 1;
}
if (srcCode == 0){
sourceTerm.setText(currentWord.getEngWordSi());
translationTerm.setText(currentWord.getOkyWordSi());
flag.setImageResource(R.drawable.britain);
}
if (srcCode == 1){
sourceTerm.setText(currentWord.getOkyWordSi());
translationTerm.setText(currentWord.getEngWordSi());
flag.setImageResource(R.drawable.namibia);
}
return listItem;
}}
Thank you in advance. :)
EDIT:
Adding example Words:
1.
EngWordSi: good
OkyWordSi: nawa
wordType: 2
2.
EngWordSi: good morning
OkyWordSi: wa lele po?
wordType: 0
3.
EngWordSi: morning
OkyWordSi: ongula
WordType: 1
what you can do is, sort your object property like below in your adapter,
public WordAdapter(#NonNull Context context, ArrayList<Word> list, String searchTerm) {
super(context, 0 , list);
mContext = context;
wordList = list;
term = searchTerm;
Collections.sort(list, new Comparator<Word>() {
#Override
public int compare(Word word1, word2) {
return word1.getEngWordSi().compareToIgnoreCase(word2.getEngWordSi());
}
});
}
this is helpful to you.
Here is my demo code
public class Main {
static class Word{
String prority1;
#Override
public String toString() {
return "Word{" +
"prority1='" + prority1 + '\'' +
'}';
}
}
public static void main(String[] args) {
ArrayList<Word> words = new ArrayList<>();
Word word;
for (int i = 0; i < 5; i++) {
word =new Word();
word.prority1 = "aaaa"+(5-i);
words.add(word);
System.out.println("wrod "+i+" is "+word);
}
Collections.sort(words, new Comparator<Word>() {
#Override
public int compare(Word o1, Word o2) {
int ret = o1.prority1.compareTo(o2.prority1);
if (ret > 0) {
return 1;
} else if (ret < 0) {
return -1;
}
return 0;
}
});
System.out.println("after sort check words");
for (Word w : words) {
System.out.println("check word:"+w);
}
}
}
and following is console's output:
wrod 0 is Word{prority1='aaaa5'}
wrod 1 is Word{prority1='aaaa4'}
wrod 2 is Word{prority1='aaaa3'}
wrod 3 is Word{prority1='aaaa2'}
wrod 4 is Word{prority1='aaaa1'}
after sort check words
check word:Word{prority1='aaaa1'}
check word:Word{prority1='aaaa2'}
check word:Word{prority1='aaaa3'}
check word:Word{prority1='aaaa4'}
check word:Word{prority1='aaaa5'}
Hope that can help you.
I created app that takes JSON with AsyncTask from server. When User click a button app starts new Activity and download data from server and show it as a items in ListView. The Problem is when I open new Activity it takes too long to load. When button is pressed app freeze on about one or two seconds and then show black screen for another 2/3 seconds. After that activity is displayed but it is very slow. It freeze every time user is scrolling or pressing button to display more options of custom adapter. Is there any way to make app more smooth? Json data that is downloaded is just simple JSONArray with JSONObjects that has 2 string values and one HTML format. This 3 values is display to user.
Part of Custom Adapter class
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
SuggestionList suggestionList = getItem(position);
int actualPosition = 0;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.sugestion_list, parent, false);
}
final Button suggestionsButton = (Button) convertView.findViewById(R.id.suggestionsMore);
final TextView suggestionNumber = (TextView) convertView.findViewById(R.id.sugestionNumber);
final TextView suggestionDescription = (TextView) convertView.findViewById(R.id.suggestionDescription);
final ImageView bio = convertView.findViewById(R.id.sugestionBio);
final ImageView block = convertView.findViewById(R.id.sugestionBlock);
final ImageView call = convertView.findViewById(R.id.sugestionCall);
...
final Animation slideUp = AnimationUtils.loadAnimation(getContext(), R.anim.slideup);
final Animation slideDown = AnimationUtils.loadAnimation(getContext(), R.anim.slidedown);
final Handler handler = new Handler();
suggestionsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (bioSuggestions.getVisibility() == View.GONE) {
bio.setVisibility(View.VISIBLE);
block.setVisibility(View.VISIBLE);
call.setVisibility(View.VISIBLE);
bioSuggestions.startAnimation(slideUp);
blockSuggestions.startAnimation(slideUp);
callSuggestions.startAnimation(slideUp);
} else if (bioSuggestions.getVisibility() == View.VISIBLE) {
bioSuggestions.startAnimation(slideDown);
blockSuggestions.startAnimation(slideDown);
callSuggestions.startAnimation(slideDown);
handler.postDelayed(new Runnable() {
#Override
public void run() {
bio.setVisibility(View.GONE);
block.setVisibility(View.GONE);
call.setVisibility(View.GONE);
}
}, 300);
}
}
});
if (actualPosition != position) {
if (bio.getVisibility() == View.VISIBLE) {
bio.setVisibility(View.GONE);
block.setVisibility(View.GONE);
call.setVisibility(View.GONE);
}
actualPosition = position;
}
JSONObject jsonValSuggestions = new getSugestions().sugestionsDetails(position, "suggestions");
try {
final String name = jsonValSuggestions.getString("client_name");
final String num = jsonValSuggestions.getString("client_number");
final String description = jsonValSuggestions.getString("client_description");
bio.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent suggestionsDetails = new Intent(view.getContext(), SuggestionsDetails.class);
suggestionsDetails.putExtra("client_number", num);
suggestionsDetails.putExtra("client_name", name);
suggestionsDetails.putExtra("client_description", description);
activity.startActivityForResult(suggestionsDetails, position);
}
});
block.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent suggestionBlock = new Intent(view.getContext(), BlockSuggestionsActivity.class);
activity.startActivity(suggestionBlock);
}
});
call.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent suggestionCall = new Intent(view.getContext(), CallSuggestionActivity.class);
suggestionCall.putExtra("client_number", num);
suggestionCall.putExtra("client_name", name);
activity.startActivity(suggestionCall);
}
});
} catch (Exception e) {
e.printStackTrace();
}
try {
if (suggestionList.suggestionName.equals("null") || suggestionList.suggestionName.equals("")) {
suggestionNumber.setText(suggestionList.suggestionNumber);
} else {
suggestionNumber.setText(suggestionList.suggestionName);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
suggestionDescription.setText(Html.fromHtml(suggestionList.suggestionDescription, Html.FROM_HTML_MODE_LEGACY));
} else {
suggestionDescription.setText(Html.fromHtml(suggestionList.suggestionDescription));
}
} catch (Exception e) {
Log.i("exception", e.getMessage());
}
return convertView;
}
Part of AsyncTask class
public static final String REQUEST_METHOD = "GET";
public static final int READ_TIMEOUT = 15000;
public static final int CONNECTION_TIMEOUT = 15000;
#Override
protected String doInBackground(String... params) {
String clientUrl = params[0];
String result;
String inputLine;
JSONObject obj;
String data;
String message;
try {
URL myUrl = new URL(clientUrl);
HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection();
connection.setRequestMethod(REQUEST_METHOD);
connection.setReadTimeout(READ_TIMEOUT);
connection.setConnectTimeout(CONNECTION_TIMEOUT);
connection.connect();
InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
BufferedReader reader = new BufferedReader(streamReader);
StringBuilder stringBuilder = new StringBuilder();
while ((inputLine = reader.readLine()) != null) {
stringBuilder.append(inputLine);
}
reader.close();
streamReader.close();
result = stringBuilder.toString();
} catch (IOException e) {
e.printStackTrace();
result = null;
}
return result;
}
public String[] getSuggestionsList() {
String[] suggestionList = new String[5];
String result;
String status;
JSONObject listObj;
String suggestionsData;
JSONObject suggestionsDataObj;
JSONArray suggestionsDataArr;
String ClientsSugestionsUrl = "https://example.com/token=" + authToken;
getApiClientSugestions getSugestionsFromApi = new getApiClientSugestions();
try {
result = getSugestionsFromApi.execute(ClientsSugestionsUrl).get();
try {
listObj = new JSONObject(result);
status = listObj.getString("result");
suggestionsData = listObj.getString("suggestions");
suggestionsDataArr = new JSONArray(suggestionsData);
} catch (Exception e) {
e.printStackTrace();
suggestionsDataArr = null;
status = null;
}
suggestionList[3] = status;
suggestionList[4] = suggestionsDataArr.toString();
} catch (Exception e) {
e.printStackTrace();
}
return suggestionList;
}
Activity
public class CallsSuggestionsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calls_suggestions);
Slidr.attach(this);
getSupportActionBar().setTitle("Skontaktuj siÄ™");
}
#Override
protected void onResume() {
super.onResume();
CallsSuggestionList();
}
public void CallsSuggestionList() {
final ListView suggestionList = findViewById(R.id.sugestionList);
final ArrayList<SuggestionList> suggestionArray = new ArrayList<SuggestionList>();
SuggestionListAdapter suggestionListAdapter = new SuggestionListAdapter(getContext(), suggestionArray, this);
String[] suggestionListArray = new getSugestions().getSuggestionsList();
String suggStat = suggestionListArray[3];
String arrayList = suggestionListArray[4];
String clientName;
String clientNumber;
String clientDescription;
try {
JSONArray jsonArray = new JSONArray(arrayList);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject explrObject = jsonArray.getJSONObject(i);
clientName = explrObject.getString("client_name");
clientNumber = explrObject.getString("client_number");
clientDescription = explrObject.getString("client_description");
if (suggStat.equals("true")) {
SuggestionList suggestionList1 = new SuggestionList(clientName, clientDescription, clientNumber);
suggestionListAdapter.addAll(suggestionList1);
suggestionListAdapter.notifyDataSetChanged();
suggestionList.setAdapter(suggestionListAdapter);
}
}
} catch (Exception e) {
Log.i("exception", e.getMessage());
e.printStackTrace();
clientName = null;
clientDescription = null;
clientNumber = null;
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
SuggestionList
public class SuggestionList {
public String suggestionNumber;
public String suggestionDescription;
public String suggestionCallType;
public String suggestionName;
public SuggestionList(
// String suggestionCallType,
String suggestionName, String suggestionDescription, String suggestionNumber) {
this.suggestionNumber = suggestionNumber;
// this.suggestionCallType = suggestionCallType;
this.suggestionName = suggestionName;
this.suggestionDescription = suggestionDescription;
}
}
Adapter are custom with custom view displayed to user. I use similar custom adapter to show content from sqlite that is on phone and there app isn't so slow. But when I open this activity it slow down dramatically. Also I noticed when I press back button it take very long to back to previous screen.
The problem is in the getSuggestionsList function. in this function, you are calling getSugestionsFromApi.execute(ClientsSugestionsUrl).get(); which make your code sync again. I mean your code is waiting this code to be executed.
One way (not right way, but easy way): you can call new getSugestions().getSuggestionsList(); in a new thread.
Second way, call getSugestionsFromApi.execute(ClientsSugestionsUrl) without get() function. But to get result of the code, you need to give an interface.
To get right usage: https://xelsoft.wordpress.com/2014/11/28/asynctask-implementation-using-callback-interface/
How to achieve this?
Okay I have this process
On Index Activity, when I click the side nav Profile, it will call Fragment (Profile) thru Fragment Transaction
if (id == R.id.nav_profile){
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.setCustomAnimations(R.anim.enter,R.anim.exit,R.anim.enter,R.anim.exit);
transaction.replace(R.id.flContent, new Profile(), "ProfileFragment");
transaction.addToBackStack(null);
viewPager.getAdapter().notifyDataSetChanged();
transaction.commit();
}
Now I'm on the Profile Fragment:
When I click "Apply for Developer" button, it will call DevRegistration activity by Intent
case 1:
btnBeDeveloper.setText("Apply for Developer");
btnBeDeveloper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent index = new Intent(getActivity(), DevRegistration.class);
startActivity(index);
}
});
break;
Step 3:
On DevRegistration after I click Register, it will display a dialog fragment
FragmentManager fm = getSupportFragmentManager();
df_SuccessDevRegistration dialogFragment = new df_SuccessDevRegistration();
dialogFragment.show(fm, "Dev Register.");
Now this is my Dialog Fragment code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
View rootView = inflater.inflate(R.layout.fragment_success_developer_registration, container, false);
btnDevGoProfile = (Button) rootView.findViewById(R.id.btnDevGoProfile);
btnDevGoProfile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
getActivity().finish();
}
});
return rootView;
}
Now my problem is, when I press the button on the dialog fragment, it should refresh my profile fragment. how to achieve that? I tried detach attach but my app just crashed and for null exception.
public class Profile extends Fragment {
TextView txvStudID, txvStudUsername, txvStudEmail, txvStudBday,txvProfileName;
CollapsingToolbarLayout ctlName;
ImageView imvProfilePic;
Button btnBeDeveloper;
View rootView;
String picURL;
FragmentTransaction ft; Fragment currentFragment;
/** Recycler View**/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rootView = inflater.inflate(R.layout.activity_profile, container, false);
Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.profile_toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view) {
NavigationView navigationView = (NavigationView) getActivity().findViewById(R.id.nav_view);
getFragmentManager().popBackStack();
navigationView.getMenu().getItem(0).setChecked(true);
}
});
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((AppCompatActivity)getActivity()).getSupportActionBar().setHomeButtonEnabled(true);
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(true);
txvStudID = (TextView) rootView.findViewById(R.id.txvStudID);
txvStudUsername = (TextView) rootView.findViewById(R.id.txvStudUsername);
txvStudEmail = (TextView)rootView.findViewById(R.id.txvStudEmail);
txvStudBday = (TextView) rootView.findViewById(R.id.txvStudBday);
txvProfileName = (TextView) rootView.findViewById(R.id.txvProfileName);
ctlName = (CollapsingToolbarLayout) rootView.findViewById(R.id.ctlName);
imvProfilePic = (ImageView) rootView.findViewById(R.id.imvProfilePic);
btnBeDeveloper = (Button) rootView.findViewById(R.id.btnBeDeveloper);
checkLevelOfAccess();
/** get user's data **/
getCurrentUserData(DataClass.currentEnteredUsername);
return rootView;
}
public void checkLevelOfAccess()
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
String acctID = preferences.getString("acctID", "DEFAULT");
switch (checkLevelOfAccess(acctID)) {
// if the level of access is developer
case 1:
btnBeDeveloper.setText("Developer Console");
btnBeDeveloper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent index = new Intent(getActivity(), UploadApp.class);
startActivity(index);
}
});
break;
// else if the level of access is not a developer
case 0:
switch (checkIfRegistered(acctID))
{
//already apply
case 0:
btnBeDeveloper.setText("Cancel Developer Request");
break;
case 1:
btnBeDeveloper.setText("Apply for Developer");
btnBeDeveloper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent index = new Intent(getActivity(), DevRegistration.class);
startActivityForResult(index, 10001);
}
});
break;
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == 10001) && (resultCode == Activity.RESULT_OK))
{
System.out.println("IM HERE NA!!!");
checkLevelOfAccess();
}
}
public void getCurrentUserData(String currentUser) {
try {
String accountURL = DataClass.localAddress + "android_php/account.php";
URL url = new URL(accountURL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("users");
for (int x = 0; x < parentArray.length(); x++) {
JSONObject finalObject = parentArray.getJSONObject(x);
if (finalObject.getString("username").equalsIgnoreCase(currentUser) || finalObject.getString("studID").equalsIgnoreCase(currentUser)
|| finalObject.getString("email").equalsIgnoreCase(currentUser)) {
txvStudID.setText(finalObject.getString("studID"));
txvStudUsername.setText(finalObject.getString("username"));
txvStudEmail.setText(finalObject.getString("email"));
txvStudBday.setText(convertDate(finalObject.getString("bday")));
ctlName.setTitle(finalObject.getString("name"));
txvProfileName.setText(finalObject.getString("name"));
//set Profile Picture
picURL = DataClass.localAddress + finalObject.getString("pic");
LoadImageFromURL loadImage = new LoadImageFromURL();
loadImage.execute();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String convertDate(String date) throws ParseException {
String strCurrentDate = date;
DateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd");
DateFormat outputFormat = new SimpleDateFormat("dd MMM yyyy");
Date parseDate = inputFormat.parse(strCurrentDate);
String converted = outputFormat.format(parseDate);
return converted;
}
public class LoadImageFromURL extends AsyncTask<String, Void, Bitmap>{
#Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
try {
InputStream is = new URL(picURL).openConnection().getInputStream();
Bitmap bitMap = BitmapFactory.decodeStream(is);
GetCircleBitmap gcb = new GetCircleBitmap();
Bitmap b = gcb.GetCircleBitmap(bitMap);
return b;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
imvProfilePic.setImageBitmap(result);
}
}
public int checkLevelOfAccess(String data)
{
try {
String accountURL = DataClass.localAddress + "android_php/account.php";
URL url = new URL(accountURL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("users");
for (int x = 0; x < parentArray.length(); x++) {
JSONObject finalObject = parentArray.getJSONObject(x);
// true
if (finalObject.getString("acctid").equalsIgnoreCase(data) && finalObject.getString("acctlofa").equals("1"))
{
return 1;
}
else if (finalObject.getString("acctid").equalsIgnoreCase(data) && finalObject.getString("acctlofa").equals("0"))
{
return 0;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return 2;
}
/** Check if the user already applied to become a developer **/
public int checkIfRegistered(String data) {
try {
String accountURL = DataClass.localAddress + "android_php/developer_account.php";
URL url = new URL(accountURL);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("users");
for (int x = 0; x < parentArray.length(); x++) {
JSONObject finalObject = parentArray.getJSONObject(x);
// pending application
if (finalObject.getString("acctID").equalsIgnoreCase(data) && finalObject.getString("devStatus").equals("0"))
{
return 0;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return 1;
}
}
I'dd suggest you using intents between activity call, and StartForRsults().
Then when your activity resume using public void onActivityResult(int requestCode, int resultCode, Intent intent) you'll be able to check if the user correctly registered (and not cancelled registration) through a boolead in the intent.
Then, set a global variable "refreshProfile", and make it true when your activity resume with the correct intent saying user registered. Override public void onPostResume(), use a if statement to check wether or not you need to refresh the profile. If yes, do so then make the variable false. if not, do nothing.
Doing so will prevent you from updating your profileFragment when activity is resuming wich can cause some crash sometimes ("IllegalStateException: Can not perform this action after onSaveInstanceState") because you are updating the UI at the wrong moment.
Other option consists into changing the dialogFragment, setting a custom function to refresh your activity.
build.setPositiveButton(positiveButton, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
/*refresh profile here
with instruction like getActivity().refresh();
where refresh is your activity public function to refresh profile.
*/
}
});
However, i dislike that way because your profile will wait user to confirm before being updated. I find it more clearer and elegant to have profile updated THEN prevent the user everything went fine. But personnal opinion here.
In your fragment that you need to refresh create and register a broadcast receiver.
When you want to refresh the fragment (in your case when clicking the button on the dialog fragment) send a broadcast which will be caught by your broadcast receiver on the profile fragment.
This will also make sure that the solution is not too tightly coupled.
You need to return the result back to the activity which contains the profile data. This can be done in several ways. In this case, I assume you want the profile to remain changed permanently. For example if the user quits the app and starts it again a week later, the changes should persist to the profile screen. This suggests that you need the data to be stored permanently. For small amounts of data, such as a boolean flag or a String, you can use SharedPreferences. For more complex data, use a SQLite database or a flat file. Now the dialog just saves the data to the chosen medium and the profile fragment loads the data in onCreate().
Not solved yet, so someone please help. Please.
I have a ListView in Main Activity which is being populated dynamically by the data from Google Books API JSON and I want to start a new Intent(same activity every time) on the click on ListView so that it carries with it all the data contained in the clicked ListView item. I'm using "Bundle" but unable to do that.
See the details below and please tell me what mistake I'm making. I'm a newbie and completely stuck on it for 2-3 days.
Kindly see and help me. Thanks.
My problem is similar to the following questions but the solution there couldn't help me. These are the links to those threads: how to start new activity in listview item click and Pass custom list item content to new activity when list item is clicked from a listview
Here is my MainActivity: which populate the activity_main.xml with "title, author, and publisher very easliy"
public class MainActivity extends AppCompatActivity {
String title;
String firstAuthor;
String publisher;
String pageCount;
String description;
int averageRating;
String publishedDate;
String isbnType;
String isbnValue;
Books booksObject = new Books();
private String searchQuery;
/**
* Tag for the log messages
*/
public static final String LOG_TAG = MainActivity.class.getSimpleName();
/**
* URL to query the GoogleBook dataset for book's information
*/
private static String BOOK_REQUEST_URL = "https://www.googleapis.com/books/v1/volumes?q=";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button search = (Button) findViewById(R.id.search);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Find the edit text's actual text and make it compatible for a url search query
searchQuery = ((EditText) findViewById(R.id.searchQuery)).getText().toString().replace(" ", "+");
//Check if user input is empty or it contains some query text
if (searchQuery.isEmpty()) {
Context context = getApplicationContext();
String text = "Nothing Entered in Search";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
} else {
// String to be attached to the BOOK_REQUEST_URL
String appendableQuery = searchQuery + "&key=MyGoogleBookAPIKey&maxResults=10&country=IN";
BOOK_REQUEST_URL += appendableQuery; //final value of "URL for Google Book API"
BookAsyncTask task = new BookAsyncTask();
//If network is available then perform the further task of AsynckTask calling
if (isNetworkAvailable()) {
// Kick off an {#link AsyncTask} to perform the network request
task.execute();
} else {
Toast.makeText(getApplicationContext(), "Network not available", Toast.LENGTH_SHORT).show();
//Reset the to the original URL to prevent app crash
BOOK_REQUEST_URL = "https://www.googleapis.com/books/v1/volumes?q=";
}
}
}
});
}
//Check if network is available or not
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
/**
* Update the screen to display information from the given {#link Books}.
*/
private void updateUi(final ArrayList<Books> book) {
final ListView listView = (ListView) findViewById(R.id.list);
BooksAdapter booksAdapter = new BooksAdapter(MainActivity.this, book);
listView.setAdapter(booksAdapter);
/*Setting click listener on ListView*/
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
Books bookses = book.get(position);
Bundle bookDetailsBundle = new Bundle();
bookDetailsBundle.putParcelableArrayList("bookDetailsArrayList", book);
Intent booksIntent = new Intent(getApplicationContext(), BookDetailsActivity.class);
booksIntent.putExtra("bookDetailsBundle", bookDetailsBundle);
startActivity(booksIntent);
}
});
}
/**
* {#link AsyncTask} to perform the network request on a background thread, and then
* update the UI with the first earthquake in the response.
*/
private class BookAsyncTask extends AsyncTask<URL, Void, ArrayList<Books>> {
#Override
protected ArrayList<Books> doInBackground(URL... urls) {
// Create URL object
URL url = createUrl(BOOK_REQUEST_URL);
// Perform HTTP request to the URL and receive a JSON response back
String jsonResponse = "";
try {
jsonResponse = makeHttpRequest(url);
} catch (IOException e) {
// TODO Handle the IOException
}
// Extract relevant fields from the JSON response and create an {#link Books} object
ArrayList<Books> book = extractFeatureFromJson(jsonResponse);
// Return the {#link Books} object as the result fo the {#link BookAsyncTask}
return book;
}
/**
* Update the screen with the given book (which was the result of the
* {#link BookAsyncTask}).
*/
#Override
protected void onPostExecute(ArrayList<Books> book) {
if (book == null) {
return;
}
updateUi(book);
EditText editText = (EditText) findViewById(R.id.searchQuery);
editText.setText(null);
BOOK_REQUEST_URL = "https://www.googleapis.com/books/v1/volumes?q="; //Reset the to the original URL
}
/**
* Returns new URL object from the given string URL.
*/
private URL createUrl(String stringUrl) {
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException exception) {
Toast.makeText(MainActivity.this, "Error Creating URL", Toast.LENGTH_SHORT).show();
return null;
}
return url;
}
/**
* Make an HTTP request to the given URL and return a String as the response.
*/
private String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
if (url == null) {
return jsonResponse;
}
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.connect();
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Toast.makeText(MainActivity.this, "Error Response Code: "
+ urlConnection.getResponseCode(), Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
// TODO: Handle the exception
Toast.makeText(MainActivity.this, "There is an IO exception: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
// function must handle java.io.IOException here
inputStream.close();
}
}
return jsonResponse;
}
/**
* Convert the {#link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
/**
* Return an {#link Books} object by parsing out information
* about the first earthquake from the input googleBooksJSON string.
*/
private ArrayList<Books> extractFeatureFromJson(String googleBooksJSON) {
try {
ArrayList<Books> arrayListOfBooks = new ArrayList<Books>();
JSONObject baseJsonResponse = new JSONObject(googleBooksJSON);
//Check if the base/root JSONObject has the desired "key" of value "items" and then only proceed
if (baseJsonResponse.has("items")) {
JSONArray itemsArray = baseJsonResponse.getJSONArray("items");
if (itemsArray.length() > 0) {
for (int i = 0; i < itemsArray.length(); i++) {
JSONObject volumeInfo = itemsArray.getJSONObject(i).getJSONObject("volumeInfo");
//Check if the JSONObject volumeInfo has the desired string with value "title" and then only proceed
booksObject.setVolumeId(i);
if (volumeInfo.has("title")) {
title = volumeInfo.getString("title");
booksObject.setTitle(title);
}
// String publisher = volumeInfo.getString("publisher");
//Check if the JSONObject volumeInfo has the desired string with value "authors" and then only proceed
if (volumeInfo.has("authors")) {
JSONArray authors = volumeInfo.getJSONArray("authors");
//get first author's name
firstAuthor = authors.getString(0);
booksObject.setAuthor(firstAuthor);
}
if (volumeInfo.has("publisher")) {
publisher = volumeInfo.getString("publisher");
booksObject.setPublisher(publisher);
}
if (volumeInfo.has("pageCount")) {
pageCount = volumeInfo.getString("pageCount");
booksObject.setPageCount(pageCount);
}
if (volumeInfo.has("description")) {
description = volumeInfo.getString("description");
booksObject.setDescription(description);
}
if (volumeInfo.has("averageRating")) {
averageRating = volumeInfo.getInt("averageRating");
booksObject.setRatings(averageRating);
}
if (volumeInfo.has("publishedDate")) {
publishedDate = volumeInfo.getString("publishedDate");
booksObject.setPublishedDate(publishedDate);
}
if (volumeInfo.has("industryIdentifiers")) {
JSONArray industryIdentifiers = volumeInfo.getJSONArray("industryIdentifiers");
JSONObject firstISBN = industryIdentifiers.getJSONObject(0);
isbnType = firstISBN.getString("type");
isbnValue = firstISBN.getString("identifier");
booksObject.setISBNType(isbnType);
booksObject.setISBNValue(isbnValue);
}
arrayListOfBooks.add(new Books(booksObject.getVolumeId(), booksObject.getTitle(), booksObject.getAuthor(), booksObject.getPublisher(),
booksObject.getPageCount(), booksObject.getDescription(), booksObject.getRatings(),
booksObject.getPublishedDate(), booksObject.getISBNType(), booksObject.getISBNValue()));
}
}
return arrayListOfBooks;
} else
Toast.makeText(MainActivity.this, "No Book found, search again", Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
Toast.makeText(MainActivity.this, "Problem parsing the Google Books JSON results" + e, Toast.LENGTH_SHORT).show();
}
return null;
}
}
}
My BookAdapter goes here:
public class BooksAdapter extends ArrayAdapter<Books> {
// View lookup cache
private static class ViewHolder {
TextView title;
TextView author;
TextView publisher;
}
public BooksAdapter(Context context, ArrayList<Books> books){
super(context, 0, books);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
final Books currentBook = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
ViewHolder viewHolder; // view lookup cache stored in tag
if (convertView == null) {
// If there's no view to re-use, inflate a brand new view for row
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.activity_main_items, parent, false);
/*Find the TextView and ImageView and set them on the VIewHolder*/
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
viewHolder.author = (TextView) convertView.findViewById(R.id.author);
viewHolder.publisher = (TextView) convertView.findViewById(R.id.publisher);
// Cache the viewHolder object inside the fresh view
convertView.setTag(viewHolder);
} else {
// View is being recycled, retrieve the viewHolder object from tag
viewHolder = (ViewHolder) convertView.getTag();
}
// Populate the data into the template view using the data object
viewHolder.title.setText(currentBook.getTitle());
viewHolder.author.setText(currentBook.getAuthor());
viewHolder.publisher.setText(currentBook.getPublisher());
return convertView;
}
}
Here is the activity(intent) which gets called every time the listview is clicked:
public class BookDetailsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.book_details_listview);
//Bundle bundle = new Bundle();
ArrayList<Books> booksArrayList = getIntent().getBundleExtra("bookDetailsBundle").getParcelableArrayList("bookDetailsArrayList");
BookDetailsAdapter bookDetailsAdapter = new BookDetailsAdapter(this, booksArrayList);
ListView listView = (ListView) findViewById(R.id.book_details_listview);
listView.setAdapter(bookDetailsAdapter);
}
}
And it's Adapter is here:
public class BookDetailsAdapter extends ArrayAdapter<Books> {
public BookDetailsAdapter(Activity context, ArrayList<Books> bookses) {
super(context, 0, bookses);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Check if the existing view is being reused, otherwise inflate the view
View listItemView = convertView;
if (listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.book_details_items, parent, false);
}
// Get the {#link AndroidFlavor} object located at this position in the list
Books currentBook = getItem(position);
// Find the TextView in the list_item.xml layout with the ID version_name
TextView title_book = (TextView) listItemView.findViewById(R.id.title_book);
TextView author_book = (TextView) listItemView.findViewById(R.id.author_book);
TextView publisher_book = (TextView) listItemView.findViewById(R.id.publisher_book);
TextView page_count_book = (TextView) listItemView.findViewById(R.id.page_count_book);
TextView description_book = (TextView) listItemView.findViewById(R.id.description_book);
TextView ratings_book = (TextView) listItemView.findViewById(R.id.ratings_book);
TextView publication_date_book = (TextView) listItemView.findViewById(R.id.publication_date_book);
TextView isbn_type_book = (TextView) listItemView.findViewById(R.id.isbn_type_book);
TextView isbn_value_book = (TextView) listItemView.findViewById(R.id.isbn_value_book);
// set this text on these TextViews
title_book.setText(currentBook.getTitle());
author_book.setText(currentBook.getAuthor());
publisher_book.setText(currentBook.getPublisher());
page_count_book.setText(currentBook.getPageCount());
description_book.setText(currentBook.getDescription());
ratings_book.setText(currentBook.getRatings());
publication_date_book.setText(currentBook.getPublishedDate());
isbn_type_book.setText(currentBook.getISBNType());
isbn_value_book.setText(currentBook.getISBNValue());
return listItemView;
}
}
Whatever I do, I get this same error:Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
at com.example.android.booklisting.BookDetailsActivity.onCreate(BookDetailsActivity.java:24)
I'm completely clueless now and lost but know it clearly that I'm unable to get the position of the clicked "list item" of "listview" even though I tried using things like "Books books= getItem(position);" in "onItemClick". Please tell me where exactly am I wrong and what's the solution. Your reply is most welcome.
My book_details_item is here:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/book_details_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/title_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/author_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/publisher_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/page_count_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/description_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/ratings_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/publication_date_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/isbn_type_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
<TextView
android:id="#+id/isbn_value_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="book's title" />
I have an Activity that show a list of database records .
In this activity there is a custom ListView.
In the custom ListView, there is a Button and a TextView and a ProgressBar .
My button listener that call AsyncTask is in CustomAdapter class .
DownloadTask downloadTask = new DownloadTask(getContext());
downloadTask.execute(url[position].toString());
AsynkTask work great .
But I want to update the Progress Bar during download process.
I've searched the Internet for three days but were unsuccessful.
I'm sorry for my English
public class listanimals extends ActionBarActivity {
private MyDatabase MyDataBase;
String[] listurl;
ProgressBar progressBar;
TextView url2;
CustomList adapter;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
int myProgress;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
final GlobalClass caches = (GlobalClass) context.getApplicationContext();
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/"+caches.getName_cach()+".mp3");
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
myProgress = (int)(total*100/connection.getContentLength());
output.write(data, 0, count);
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
//MY PROBLEM MAY HERE
progressBar.setProgress(myProgress);
}
#Override
protected void onPostExecute(String result) {
final GlobalClass caches = (GlobalClass) context.getApplicationContext();
if (result != null)
Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
else{
Toast.makeText(context,"File downloaded"+ "" + caches.getName_cach(), Toast.LENGTH_SHORT).show();
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////AsynkTask end
///////////////////////////////////////////////////////////////////////////////////////
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listanimals);
MyDataBase = new MyDatabase(this);
final GlobalClass caches = (GlobalClass) getApplicationContext();
final ListView listView=(ListView)findViewById(R.id.listView);
SQLiteDatabase mydb = MyDataBase.getReadableDatabase();
Cursor cursor = mydb.rawQuery("select * from animals", null);
ArrayList<String> myList = new ArrayList<String>();
final ArrayList<String> myListname = new ArrayList<String>();
ArrayList<String> myListurl = new ArrayList<String>();
try {
while(cursor.moveToNext()) {
myList.add(cursor.getString(cursor.getColumnIndex("_id")));
myListname.add(cursor.getString(cursor.getColumnIndex("name")).trim());
myListurl.add(cursor.getString(cursor.getColumnIndex("url")));
String[] listname = new String[myListname.size()];
listname = myListname.toArray(listname);
listurl = new String[myListurl.size()];
listurl = myListurl.toArray(listurl);
String[] listid = new String[myList.size()];
listid = myList.toArray(listid);
adapter = new
CustomList(listanimals.this, listname,listurl);
listView.setAdapter(adapter);
}} finally{
mydb.close();
}}
#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);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class CustomList extends ArrayAdapter<String> {
private MyDatabase MyDataBase;
private final Activity context;
private final String[] web;
private final String[] url;
public CustomList(Activity context,
String[] web,String[] url) {
super(context, R.layout.list_file, web);
this.context = context;
this.web = web;
this.url = url;
}
#Override
public View getView(final int position, View view, final ViewGroup parent) {
final GlobalClass caches = (GlobalClass) context.getApplicationContext();
MyDataBase = new MyDatabase(getContext());
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_file, null, true);
Typeface kamran= Typeface.createFromAsset(context.getAssets(), "IranNastaliq.ttf");
progressBar=(ProgressBar)rowView.findViewById(R.id.progressBar);
TextView txtTitle3 = (TextView) rowView.findViewById(R.id.textView);
txtTitle3.setTypeface(kamran);
url2=(TextView)rowView.findViewById(R.id.textView2);
url2.setText(url[position]);
txtTitle3.setText(web[position]);
Button download=(Button)rowView.findViewById(R.id.button);
download.setTag(position);// Any data associated with the button has to be added with setTag()
download.setOnClickListener(new View.OnClickListener() {/////////call AsynkTask
#Override
public void onClick(View arg0) {
caches.setName_cach(web[position]);
DownloadTask downloadTask = new DownloadTask(getContext());
downloadTask.execute(url[position].toString());
}
});
return rowView;
}
}
}
You need to call publishProgress from the doInBackground method to update the ProgressBar: publishProgress docs
This will call onProgressUpdate(Integer... values);
You don't need the myProgress instance variable;
Check out this link https://www.youtube.com/watch?v=5HDr9FdGIVg&list=PLonJJ3BVjZW6hmkEaYIvLLm5IEGM0kpwU&index=17
You need to call - publishProgress((int) total*100/connection.getContentLength());
in the while loop
to update your progressbar.Hope it helps.
You have a progress bar in each item of the list, while you keep a single instance in the activity. This means your progress view will point to the one in the last list item that the system asked you to draw. Which might not be the one from the list item you pressed the button for. I suggest you split the classes (take them out from the activity) and you'll better see your problem. But this is going to be only the first of your problems - because you launch the async task and in the meantime you can scroll that item off screen.