Issue
I have to create a RecyclerView which is updated every time a new item is created by my AsyncTask. So the RecyclerView is building itself up gradually.
Every Item is generated and then the Thread sleeps for a time to see the progress slower.
I tried to get the Adapter and update it with notifyDataSetChanged(), but it wont work like this. The Error I get is:
Only the original thread that created a view hierarchy can touch its views.
Another idea was to update the adapter in my MainActivity with the use of a interface. But I dont exactly know how to do that. First I have to know if its the right way to use an interface or if there is a better way or maybe a really easy solution for my problem.
public class MainActivity extends AppCompatActivity implements ListAdapter.Listener{
static RecyclerView recyclerView;
static ListAdapter adapter;
@Override
public void click(String name) {
if(getResources().getConfiguration().orientation== Configuration.ORIENTATION_LANDSCAPE){
DetailsFragment detailsFragment = (DetailsFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_details);
detailsFragment.setData(name);
}
else{
Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, DetailsActivity.class);
intent.putExtra("sorte_name", name);
startActivity(intent);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initRecyclerView();
new DataContainer().execute();
}
private void initRecyclerView(){
recyclerView = findViewById(R.id.meinRecyclerView);
adapter = new ListAdapter(this, DataContainer.meineSortenListe, this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
}
public class DataContainer extends AsyncTask<Void, Void, Void> {
public static ArrayList<String> meineSortenListe = new ArrayList<String>();
ListAdapter myAdapter;
@Override
protected void onPreExecute() {
myAdapter =(ListAdapter)MainActivity.recyclerView.getAdapter();
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... voids) {
for(int i= 0; i<50; i++){
meineSortenListe.add("Sorte "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
onProgressUpdate();
}
Log.i("info", "array befüllt");
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
myAdapter.notifyDataSetChanged();
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder>{
private ArrayList<String> mSorten;
private Context mContext;
private Listener listener;
public interface Listener{
void click(String name);
}
//Constructor
public ListAdapter(Context mContext, ArrayList<String> sortenListe, Listener listener) {
this.mContext = mContext;
this.mSorten = sortenListe;
this.listener=listener;
}
///////////////////////
public class ViewHolder extends RecyclerView.ViewHolder {
TextView sortenName;
LinearLayout sorteLayout;
public ViewHolder(View itemView) {
super(itemView);
sortenName = itemView.findViewById(R.id.nameSorte);
sorteLayout = itemView.findViewById(R.id.sorteLayout);
}
}
////////////////////////////////
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
holder.sortenName.setText(mSorten.get(position));
holder.sorteLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.click(mSorten.get(position));
}
});
}
@Override
public int getItemCount() {
return mSorten.size();
}
}
Solution
In Android, only the UI thread can update views. (It is possible to trigger UI updates in onPostExecute, since onPostExecute is switching to the UI thread.)
Since you are still in the doInBackground() function, you need a Handler to send a Runnable with your code to the UI thread's MessageQueue.
So in your DataContainer, change onProgressUpdate to
protected void onProgressUpdate(Void... values) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){
public void run() {
myAdapter.notifyDataSetChanged();
}
});
super.onProgressUpdate(values);
}
Answered By - David3103
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.