I am creating my application and I need to fill the recyclerview and then scroll to the desired item. To do this, I used AsyncTask, but the problem is that scrollToPosition () does not work. Maybe someone will tell me what I am doing wrong, since this is my first time working with AsyncTask and I do not understand what my mistake is.
public class SomeUserProfileFragment extends Fragment {
private void loadUserPosts() {
mDatabaseReference = FirebaseDatabase.getInstance().getReference().child("Posts");
new SetFirebaseRecyclerAdapter().execute();
}
class SetFirebaseRecyclerAdapter extends AsyncTask<Integer, Void, Void>
{
#Override
protected Void doInBackground(Integer... integers) {
FirebaseRecyclerOptions<TestPosts> options = new FirebaseRecyclerOptions.Builder<TestPosts>()
.setQuery(mDatabaseReference.orderByChild("uid").equalTo(uid), TestPosts.class)
.build();
mLinearLayoutManager = new LinearLayoutManager(mContext);
mLinearLayoutManager.setReverseLayout(true);
mLinearLayoutManager.setStackFromEnd(true);
adapter = new TestPostsAdapter(options, mContext);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mRecyclerView.setAdapter(adapter);
mRecyclerView.scrollToPosition(1);
adapter.startListening();
}
}
}
Related
I try to implement a timer using Work Manager.
"Timer button was hit" is appear in logcat, but nothing comes from worker. What I do wrong?
This is my ViewModel class:
public class MainViewModel extends ViewModel {
public static final String LOG_TAG = "MainActivity";
private final WorkManager workManager;
public MainViewModel(WorkManager workManager) {
this.workManager = workManager;
}
public void count() {
Log.d(LOG_TAG, "Timer button was hit!");
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker.class).build();
workManager.beginUniqueWork("count-work", ExistingWorkPolicy.APPEND, request).enqueue();
}
}
This is my worker. Nothing appear in logcat from here. I don't know why.
public class MainWorker extends Worker {
public MainWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.d(MainViewModel.LOG_TAG, "Created");
}
#NonNull
#Override
public Result doWork() {
Log.d(MainViewModel.LOG_TAG, "Work start");
return Result.success();
}
}
This is my activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainViewModel viewModel = new MainViewModel(WorkManager.getInstance(this));
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setMainViewModel(viewModel);
}
}
ViewModels are not initialized the way you did. If you have to pass something to ViewModel constructor, you should probably consider using ViewModelProvider.Factory().
You can make your own ViewModelProvider.Factory()
Refer this, https://medium.com/koderlabs/viewmodel-with-viewmodelprovider-factory-the-creator-of-viewmodel-8fabfec1aa4f#:~:text=And%20it%20is%20because%20you,it%20will%20create%20your%20ViewModel.
I have sometimes this error
The content of the adapter has changed but ListView did not receive a
notification. Make sure the content of your adapter is not modified
from a background thread
But i don't understand because i run to UI thread. If you have an idea, thks.
class LoadingProducts extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
loading_indicator.show();
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (isAdded()) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.setData(listProducts);
mAdapter.notifyDataSetChanged();
loading_indicator.hide();
}
});
}
}
#Override
protected Void doInBackground(Void... params) {
get_data();
return null;
}
}
UPDATED :
This problem appear on refreshing list by search
previous code onQueryTextChange :
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (mQueryStringSearch.length() > 2)
new LoadingProducts().execute();
}
}, 300);
I am reading about how to interact between UI and background thread here.
This article has following note:
The AsyncTask does not handle configuration changes automatically,
i.e. if the activity is recreated. The programmer has to handle that
in his coding. A common solution to this is to declare the AsyncTask
in a retained headless fragment.
I dont understand what is retained headless fragment.
For example, in this way I can add fragment:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.frame, new MyFragment());
transaction.commit();
And in fragment I can execute AsyncTask like this:
MyTask myTask = new MyTask();
String[] args = {"Hello"};
myTask.execute(args);
Is this called "to declare the AsyncTask in a retained headless fragment"?
Headless fragment is nothing but a fragment which does not have a view. In onCreate() of the fragment lifeCycle, use setRetainInstance(true);. This will not destroy the fragment even if the activity recreates. So if an AsyncTask is running in fragment, on recreation of the activity, you wont lose the AsyncTask.
In onCreate of the activity, you have to add the fragment with a tag. Before adding, check if the fragment exist using getFragmentManager().findFragmentByTag(TAG), if the fragment is null then create a new instance of the fragment and add it.
In Fragment there will not be any view inflated, so no need to override onCreateView().
An example of headlessFragment :
public class HeadlessProgressFragment extends Fragment {
private ProgressListener mProgressListener;
private AsyncTask<Void, Integer, Void> mProgressTask;
public interface ProgressListener {
void updateProgress(int progress);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public void setProgressListener(Context context) {
mProgressListener = (ProgressListener) context;
}
public void startProgress(final int size) {
if (mProgressTask == null || mProgressTask.getStatus() != AsyncTask.Status.RUNNING || mProgressTask.getStatus() == AsyncTask.Status.FINISHED) {
mProgressTask = new AsyncTask<Void, Integer, Void>() {
#Override
protected Void doInBackground(Void... params) {
for (int index = 0; index < size; index++) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
publishProgress(index + 1);
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (mProgressListener != null) {
mProgressListener.updateProgress(values[0]);
}
}
};
mProgressTask.execute();
}
}
}
In Activity Something like this :
public class MainActivity extends FragmentActivity implements HeadlessProgressFragment.ProgressListener {
private static final String TAG = "progress_fragment";
private ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dummy_view);
mHeadlessProgressFragment = (HeadlessProgressFragment) getSupportFragmentManager().findFragmentByTag(TAG);
if (mHeadlessProgressFragment == null) {
mHeadlessProgressFragment = new HeadlessProgressFragment();
getSupportFragmentManager().beginTransaction().add(mHeadlessProgressFragment,TAG).commit();
}
mHeadlessProgressFragment.setProgressListener(this);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
final Button startFillBtn = (Button) findViewById(R.id.btn_start_filling);
startFillBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mHeadlessProgressFragment.startProgress(100);
}
});
}
#Override
public void updateProgress(int progress) {
mProgressBar.setProgress(progress);
}
}
As i simplified the complexity in my case by Just update your UI (if you have to) by checking the calling fragment or activity is present or not. Start the asynctask by assigning the weakreference of calling entity.
I'm trying to get in my MyActivity an int from a View MyView. In my activity I have the following:
public class MyActivity extends AppCompatActivity implements MyView.GetCallBack {
final MyActivity context = this;
private AsyncTask<Void, Void, Void> task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_act);
task = new myTask();
task.execute();
}
#Override
public void onPercentageReceived(int msg){
// you have got your msg here.
}
public class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
}
#Override
protected void onPostExecute(Void result) {
LinearLayout surface = (LinearLayout) findViewById(R.id.surfaceView);
surface.addView(new MyView(getApplicationContext()));
surface.setBackgroundColor(Color.BLACK);
}
}
Now MyView contains the following code:
public class MyView extends View {
final MyView context = this;
private GetCallBack callback;
// Constructor
public PlacingBoxView(Context context) {
super(context);
callback = (GetCallBack) context;
}
#Override
protected void onDraw(Canvas canvas) {
dataPercentage(Percentage);
}
public void dataPercentage(int Percentage){
callback.onPercentageReceived(Percentage);
}
public interface GetCallBack{
void onPercentageReceived(int msg);
}
I can compile the code without problems, but in the LogCat I get the following mistake:
FATAL EXCEPTION: main
Process: com.example.ex, PID: 8035
java.lang.ClassCastException: android.app.Application cannot be cast
to com.example.ex.myView$GetCallBack
at com.example.ex.myView.(myView.java:49)
I know the error is related with the Context, but I still haven't found out a way to correct it,
Any idea will be really appreciated! :)
You have implemented the interface in myActivity but you are passing application context. That's why you are getting ClassCastException. Pass myActivity.this, so try like this:
surface.addView(new MyView(MyActivity.this);
**Updated: (See below)**I have been looking around for couple of days and can't find a straight answer to this.
Some say it possible to some say to accomplish some say it's not. I am getting crazy on this.
What I want is just to have the AsyncTaskTask showing a progressbar an external class. To do this I am passing the context as you can see in the main class. But whatever I try I get NullPointerException.
Working code examples is appreciated. Thank you
Using Android 2.2 by the way.
main:
import android.app.Activity;
import android.os.Bundle;
public class AsyncDemo extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AsyncClass(this).execute();
}
}
AsyncClass.java
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.SystemClock;
public class AsyncClass extends AsyncTask<Void, String, Void> {
private Context context;
ProgressDialog dialog = new ProgressDialog(context);
public AsyncClass(Context cxt) {
context = cxt;
}
#Override
protected void onPreExecute() {
dialog.setTitle("Please wait");
dialog.show();
}
#Override
protected Void doInBackground(Void... unused) {
SystemClock.sleep(2000);
return (null);
}
#Override
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
Update:
I have a follow up question: Using the above code, is it possible to return a value from the onPostExecute method back to the main class, somehow? (Sorry about beeing noobish)
I have tried something like this:
String result = new AsyncClass(this).execute();
and then a method that return back a string. But I can't do that because i got:
Type mismatch: cannot convert from AsyncTask<String,Void,Void> to String
What can I do to tackle this problem? Thanks.
You were creating the ProgressDialog with a null context. The following code worked for me.
public class AsyncClass extends AsyncTask<Void, String, Void> {
private Context context;
ProgressDialog dialog;
public AsyncClass(Context cxt) {
context = cxt;
dialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
dialog.setTitle("Please wait");
dialog.show();
}
#Override
protected Void doInBackground(Void... unused) {
SystemClock.sleep(2000);
return (null);
}
#Override
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
}
ok this is what I did as i was using fragments. This is how you call the AsyncTask inside a fragment:
String result=new AsyncClass(getActivity()).execute();
and this is how my AsyncTask outer class looks like:
public class AsyncClass extends AsyncTask<Void, Void, String> {
ProgressDialog pdialog;
public AsyncClass(Context context) {
pdialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
pdialog.setIndeterminate(true);
pdialog.setCancelable(false);
pdialog.setTitle("Loading Feed..");
pdialog.setMessage("Please wait.");pdialog.show();
}
#Override
protected String doInBackground(Void... params) {
String result=null;
//do your task here and generate result String
return result;
}
#Override
protected void onPostExecute(String result) {
if(pdialog.isShowing())
pdialog.dismiss();
}
}
#SSZero thanks great answer, helped a lot.
I would like to answer that follow up question i.e.
I have a follow up question: Using the above code, is it possible to return a value from the onPostExecute method back to the main class, somehow? (Sorry about beeing noobish) I have tried something like this:
String result = new AsyncClass(this).execute();
I did this in my code it worked.
AsyncClass ac=new AsyncClass();
ac.execute("");
String rslt=ac.get();
Call this code wherever you want to.
public class AsynchClass extends AsyncTask <String,Integer,String>
{
public String result=null;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
}
protected String doInBackground(String... params)
{
// Do all your background task here
return result;
}
#Override
protected void onProgressUpdate(Integer... values) {
}
protected void onPostExecute(String result) {
}
}