Oblivionkey3 Oblivionkey3 - 3 months ago 11
Java Question

Android Tabbed View Not Updating Until Touch

I have an android app with a tabbed layout that contains a list view. I'm trying to update the list after retrieving information from a server. However, the list doesn't update until the screen is touched. All of the information is correct, but no matter how long I wait, the list won't populate the screen until I've tapped it. Does anyone know how to fix this?

Tab1.java

import android.os.AsyncTask;
import android.os.Build;
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.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

/**
* Created by hp1 on 21-01-2015.
*/

//NEW
public class Tab1 extends Fragment {
MainActivity mainActivity;
List<Post> postList;
public static NewAdapter newAdapter;

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.tab_1,container,false);

return v;
}

@Override
public void onStart() {
super.onStart();
postList = new ArrayList<Post>();

try {
//get data from azure
mainActivity = (MainActivity) getActivity();

//set lists
ListView newListView = (ListView) mainActivity.findViewById(R.id.newListView);
newAdapter = new NewAdapter(mainActivity, postList);
newListView.setAdapter(newAdapter);
}catch(Exception e){

}

//get the posts loaded asynchronously
retrievePosts();
}

public void retrievePosts(){
AsyncTask<Void,Void,Void> task = new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
try {
postList= mainActivity.postTable.execute().get();
Log.e("TAG",postList.get(0).text);
newAdapter.updateList(postList);
} catch (final Exception e) {
}
return null;
}
};

runAsyncTask(task);
}

private AsyncTask<Void, Void, Void> runAsyncTask(AsyncTask<Void, Void, Void> task) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
return task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
return task.execute();
}
}
}


NewAdapter.java

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

public class NewAdapter extends BaseAdapter {
List<Post> postList;
Context context;
LayoutInflater inflater;

public NewAdapter(MainActivity mainActivity, List<Post> myPostList) {
postList=myPostList;
context=mainActivity;
inflater = LayoutInflater.from(context);
}

@Override
public int getCount() {
return postList.size();
}

@Override
public Object getItem(int position) {
return postList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

PostCell postCell=new PostCell();
View cellView = inflater.inflate(R.layout.post_cell, null);

postCell.textView=(TextView) cellView.findViewById(R.id.textView1);
postCell.textView.setText(postList.get(position).text);

cellView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "You Clicked "+postList.get(position).text, Toast.LENGTH_LONG).show();
}
});

return cellView;
}

public List<Post> updateList(List<Post> myPostList){
postList = myPostList;
notifyDataSetChanged();
return postList;
}

public List<Post> addToList(Post post){
postList.add(post);
notifyDataSetChanged();
return postList;
}
}


EDIT: Final Answer - here is my final code with the problem solved. Bnydev was right about the problem, but there were a few more things I had to change as well.

public void retrievePosts(){
//NOTE: must have a return type for an async task to run onpostexecute, which
//is executed on the ui thread so the screen can be updated

AsyncTask<Void,Void,Boolean> task = new AsyncTask<Void,Void,Boolean>(){
@Override
protected Boolean doInBackground(Void... params) {
try {
postList= mainActivity.postTable.execute().get();
} catch (final Exception e) {
e.printStackTrace();
}
return true;
}
protected void onPostExecute(Boolean reult) {
newAdapter.updateList(postList);
}
};

task.execute();
}

Answer

In Tab1.java, you have the method retrievePosts(), which contains an AsyncTask. Within doInBackground() of this AsyncTask, you call newAdapter.updateList(), and within updateList(), you call notifyDataSetChanged().

The documentation here says, that notifyDataSetChanged() refreshs the UI. But as far as I know, refreshing the UI should only be possible from the UI thread, not from any background thread. You could try to call newAdapter.updateList() in onPostExecute() within the AsyncTask, see the example here. doInBackground() is executed on a background thread, onPostExecute() is executed on the UI thread.

public void retrievePosts(){
    AsyncTask<Void,Void,Void> task = new AsyncTask<Void,Void,Void>(){
        @Override
        protected Void doInBackground(Void... params) {
            try {
                postList= mainActivity.postTable.execute().get();
                Log.e("TAG",postList.get(0).text);
            } catch (final Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        protected void onPostExecute() {
            newAdapter.updateList(postList);
        }
    };

    runAsyncTask(task);
}

PS: I don't think that it is good to catch all exceptions without anything like e.printStackTrace() etc.