I use Retrofit. Sometime I want integrate with AsyncTask for some purpose like Dialog Loading...
Here is my way:
public class RetrofitAsyncTask<T extends ResponseModel> {
public interface OnCompleteListener<T extends ResponseModel> {
public void onComplete(T t);
public void onError(Exception e);
}
public interface JsonConverter<T extends ResponseModel> {
public T getModel();
}
protected OnCompleteListener<T> onCompleteListener = null;
protected JsonConverter<T> jsonConverter;
protected ProgressDialog progressDialog;
protected int requestCode = Integer.MIN_VALUE;
public static RetrofitAsyncTask newInstance() {
return new RetrofitAsyncTask();
}
public RetrofitAsyncTask setOnCompleteListener(OnCompleteListener<T> l) {
onCompleteListener = l;
return this;
}
public RetrofitAsyncTask setJsonConverter(JsonConverter<T> converter) {
jsonConverter = converter;
return this;
}
public RetrofitAsyncTask setProgressDialog(ProgressDialog dlg) {
progressDialog = dlg;
return this;
}
public RetrofitAsyncTask setRequestCode(int reqCode) {
requestCode = reqCode;
return this;
}
public void execute() {
new AsyncTask<Void, Void, Exception>() {
private T result;
#Override
protected ProgressDialog getDialogRunOnPreStart() {
/** Retrun dialog will display. Will process on onPre & onPost. But current I will ignore it.**/
return progressDialog;
}
#Override
protected Exception doInBackground(Void... params) {
if (jsonConverter == null) {
return null;
}
try {
result = jsonConverter.getModel();
result.setRequestCode(requestCode);
} catch (Exception e) {
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception e) {
if (onCompleteListener != null) {
if (e != null || result == null) {
onCompleteListener.onError(e);
} else {
onCompleteListener.onComplete(result);
}
}
}
}.execute();
}
}
In this case class ResponseModel is Empty class.
public class ResponseModel {/** You will custom some filed default here **/}
Next you will define some Service Api.... look like:
public interface MyService {
#GET("/path")
public User getUserInfo(....);
}
(Notes class User Must be extend from ResponseModel).
Then you will custom some RetrofitAdapter...
Finally to use RetrofitAsyncTask you will do something like:
RetrofitAsyncTask.newInstance()
.setJsonConverter(
new RetrofitAsyncTask.JsonConverter<User>() {
#Override
public User getModel() {
return MyService.getUser(...);
}
}
)
.setOnCompleteListener(this)
.setRequestCode(requestCode)
.execute();
That's way I done. But current I feel it not good.
(setJsonConverter get much line :|, If you have any idea to make it better & shorter please comment ! Thanks so so much !)
Related
I have LibModule.java set as native module in reactnative
.....
class LibModule extends ReactContextBaseJavaModule {
boolean readingMyKad = false;
....
public void read_mykad_main() {
clear_results();
pre_card_status = -1;
new readMyKad(reactContext).execute();
}
public static class readMyKad extends AsyncTask<Void, Void, Integer> {
CountDownTimer readMyKadCdt;
readMyKad readMyKadObject;
private WeakReference<ReactApplicationContext> activityReference;
readMyKad(ReactApplicationContext reactContext) {
activityReference = new WeakReference<>(reactContext);
}
protected void onPreExecute() {
readMyKadObject = this;
readMyKadCdt = new CountDownTimer(25000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
if ( activityReference.get().readingMyKad ) {
try {
activityReference.get().readingMyKad = false;
if (readMyKadObject.getStatus() == AsyncTask.Status.RUNNING) {
boolean bret = readMyKadObject.cancel(true);
Log.e(TAG,"readMyKadAsyncTask Timeout, cancel: " + bret);
}
} catch (Exception ignored) {
}
}
}
};
readMyKadCdt.start();
}
...............
but in class readMyKad, i need to get variables from my main module LibModule such as activityReference.get().readingMyKad.
not just get the variable but also set and call function from LibModule. how can i do that because LibModule is not an activity.
im sorry for my english and the title.
I have some classes as presenter and in these classes I use retrofit for some methods. But some methods are duplicated. So I want to use a class for all retrofit and connect to server methods and call them when I want.
But when I created that class it has NullpointerException Error
I will be very thankful if you help me
this is presenter codes:
public class DefinitionPresenter implements DefinitionContract.Presenter {
private KalaBeanDataSource kalaBeanDataSource;
private DefinitionContract.View view;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private DatabaseMethods databaseMethods;
private ActivityKindList activityKindList;
public DefinitionPresenter(KalaBeanDataSource kalaBeanDataSource){
this.kalaBeanDataSource = kalaBeanDataSource;
databaseMethods = new DatabaseMethods(kalaBeanDataSource,compositeDisposable);
activityKindList = new ActivityKindList();
}
#Override
public void attachView(DefinitionContract.View view) {
this.view = view;
}
#Override
public void detachView() {
view = null;
if(compositeDisposable != null && compositeDisposable.size() > 0){
compositeDisposable.clear();
}
}
#Override
public void activityKind() {
activityKindList = databaseMethods.getActivityKind();
if(activityKindList.getItems().size() > 0){
view.getActivityKind(activityKindList);
}else{
view.showMessage(databaseMethods.message);
}
}
}
And this is a class that I created for get data from server with retrofit and RxJava
public class DatabaseMethods {
private KalaBeanDataSource kalaBeanDataSource;
private CompositeDisposable compositeDisposable;
private ActivityKindList activityKindListResult;
public String message = null;
public DatabaseMethods(KalaBeanDataSource kalaBeanDataSource,CompositeDisposable compositeDisposable){
this.kalaBeanDataSource = kalaBeanDataSource;
this.compositeDisposable = compositeDisposable;
activityKindListResult = new ActivityKindList();
}
public ActivityKindList getActivityKind(){
kalaBeanDataSource.getActivityKind().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<ActivityKindList>() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onSuccess(ActivityKindList activityKindList) {
activityKindListResult = activityKindList;
}
#Override
public void onError(Throwable e) {
message = e.toString();
}
});
if(message == null && activityKindListResult.getItems().size() > 0){
return activityKindListResult;
}else{
return null;
}
}
this method always returns null:
public ActivityKindList getActivityKind(){
kalaBeanDataSource.getActivityKind().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<ActivityKindList>() {
#Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
#Override
public void onSuccess(ActivityKindList activityKindList) {
activityKindListResult = activityKindList;
}
#Override
public void onError(Throwable e) {
message = e.toString();
}
});
if(message == null && activityKindListResult.getItems().size() > 0){
return activityKindListResult;
}else{
return null;
}
}
1) make this method void
2) create an interface and call it in onSuccess() and onError()
3) implement interface in your presenter
I have the following AsyncTask class which I want to handle multiple api calls and return a List back to my activity. I am having a problems trying to make this work.
How can I return an object back to my activity when onPostExecute() method does not return anything?
public class NetworkCall extends AsyncTask<Call, Void, List<Student>> {
#Override
protected List<Students> doInBackground(Call... calls) {
try {
Call<Students> call = calls[0];
Response<Students> response = call.execute();
return response.body().getStudents();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(List<Students> students) {
}
}
One of the options is to create interface and use as callback.
In async task class :
public class NetworkCall extends AsyncTask<Call, Void, List<Student>> {
public interface NetworkCallback{
void onResponse(List<Students> students);
}
private NetworkCallback callback;
public void setCallback(NetworkCallback callback){
this.callback = callback;
}
#Override
protected List<Students> doInBackground(Call... calls) {
try {
Call<Students> call = calls[0];
Response<Students> response = call.execute();
return response.body().getStudents();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(List<Students> students) {
callback.onResponse(students)
}
}
and now in your activity implement the interface and provide to the async task via setter.
public class StudentsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//.... you setup for activity
NetworkCall networkCall = new NetworkCall();
networkCall.setCallback(new NetworkCall.NetworkCallback() {
#Override
public void onResponse(List<Students> students) {
//update your UI here
}
});
}
}
Based on the Docs onPostExecute runs on the main UI thread so no need to the runOnUiThread and Runnable
you can implement like this:
Your interface:
public interface OnTaskCompleted{
void onTaskCompleted(Object o);
}
Your Activity:
public class YourActivity implements OnTaskCompleted{
// your Activity
#Override
void onTaskCompleted(Object o){
}
And your AsyncTask:
public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object
to required type
private OnTaskCompleted listener;
public YourTask(OnTaskCompleted listener){
this.listener=listener;
}
// required methods
protected void onPostExecute(Object o){
// your stuff
listener.onTaskCompleted(o);
}
}
I have an issue with runOnuiThread and AsyncTask getting called together.
My AsynchTask gets data to populate a listView through runOnUIThread call.
This Asych Task can get data even when UI is not in focus . It starts from a UI screen and runs until application is logged out.
Now data coming from this Task can populate only a particular listview.
Now if i invoke another Asynch Task from another view using call executeOnExecutor call for AsynchTask, the Asynch Task does not run to compeltion. It locks up.
If I comment out code for the never ending AsychTask called Receiver.. then all UI's listview get populated and no Asych Task locks.
This Receiver waits on a REST API call for response to return but since I am running through executeonExecutor call, it should be parallel processing.
I need to have the receiver running all the time as that is an integral of my application.
What strategy can I use here to fix this issue.
Here are my code snippets.
public class Receiver {
private final static String QUEUE_NAME = "hello";
private String m_ErrorMessage;
private IRunOnUIThreadCallback iRunOnUIThreadCallback;
private Send m_Received;
private int m_TimeoutDuration;//how long the reading of new message waits in milli seconds
public void SetCallback(IRunOnUIThreadCallback runOnUIThreadCallback)
{
iRunOnUIThreadCallback = runOnUIThreadCallback;
}
public void SetTimeoutDuration(int timeout)
{
m_TimeoutDuration = timeout;
}
public void StartReceiver(Send receiverInfo)
{
String receivedInfo = null;
try {
new ReceiveInfo ().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, receiverInfo);
}
catch(Exception exp)
{
m_ErrorMessage = exp.getMessage();
}
}
private class ReceiveInfo extends AsyncTask<Send, Void, Send>
{
//initiate vars
public receive() {
super();
//my params here
}
protected Message doInBackground(Send... receiverInfo)
{
Send recv=null;
try {
PreferenceSingleton single = PreferenceSingleton.getInstance();
final User user = single.getUser();
final SvcApi svc = LoginAuthSvc.init();
Send send=(Send)receiverInfo[0];
send.setUserId(user.getUsername());
//dxbrem
while (true) {
recv=svc.receive(send);
String str= recv.get();
if ((str == null || (str.trim().length() == 0))) {
continue;
}
//DJ uncomment
iRunOnUIThreadCallback.RunAfterIsReceived(recv);
//messages.add(message);
System.out.println(" [x] Received '" + recv + "'");
}
}catch(Exception exp)
{
m_ErrorMessage = exp.getMessage();
}
return recv;
}
}
public String getErrorMessage() {
return m_ErrorMessage;
}
}
public interface IRunOnUIThreadCallback {
public void RunAfterIsReceived(ByteSent m);
public void RunAfterIsReceived(Send m);
}
The class that handles this.. has the following code and
public class MainFragment extends Fragment implements MFragment.OnFragmentInteractionListener, IRunOnUIThreadCallback {
private Receiver mReceiver;
public void SetUICallbackOnMessageReceiver()
{
mReceiver.SetCallback(this);
}
private void callRunUIThread(final SentInfo m) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
if (m!= null) {
mGridArray.add(message);
if (mListAdapter != null) {
mListAdapter.notifyDataSetChanged();
mListView.setSelection(mListAdapter.getCount());
mListView.smoothScrollToPosition(mListAdapter.getCount());
}
}
}
}); // end of runOnUiThread
}
#Override
public void RunAfterIsReceived(ByteSent m) {
}
#Override
public void RunAfterIsReceived(Sent m) {
SentInfo m= new SentInfo(false, recv.getInfo());
callRunUIThread(msg);
}
mListAdapter is the ListAdapater
mListView is the ListView
Here is the AsynchTask code
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
public class CallableTask<T> extends AsyncTask<Void,Double,T> {
private static final String TAG = CallableTask.class.getName();
public static <V> void invoke(Callable<V> call,Activity activity, TaskCallback<V> callback){
new CallableTask<V>(activity,call, callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
private Callable<T> callable_;
private AsyncTask<Void, Void, String> asyncTask_;
private Context context;
private Activity activity;
private Fragment fragmentActivity;
private android.support.v4.app.Fragment dynamicFragment;
private TaskCallback<T> callback_;
private Exception error_;
public CallableTask(Fragment actvy,Callable<T> callable, TaskCallback<T> callback) {
callable_ = callable;
callback_ = callback;
fragmentActivity=actvy;
}
public CallableTask(Activity actvy,Callable<T> callable, TaskCallback<T> callback) {
callable_ = callable;
callback_ = callback;
activity=actvy;
}
#Override
protected T doInBackground(Void... ts) {
T result = null;
try{
result = callable_.call();
} catch (Exception e){
Log.e(TAG, "Error invoking callable in AsyncTask callable: " + callable_, e);
error_ = e;
}
return result;
}
#Override
protected void onPostExecute(T r) {
if(error_ != null){
callback_.error(error_);
}
else {
callback_.success(r,activity);
}
}
public static <V> void invoke(Callable<V> call, Fragment _frg, TaskCallback<V> callback) {
new CallableTask<V>(_frg,call, callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
// public CallableTask(android.support.v4.app.Fragment chatActivity,Callable<T> callable, TaskCallback<T> callback) {
// callable_ = callable;
// callback_ = callback;
// dynamicFragment=chatActivity;
// }
public CallableTask(android.support.v4.app.Fragment actvy,Callable<T> callable, TaskCallback<T> callback) {
callable_ = callable;
callback_ = callback;
dynamicFragment=actvy;
}
public static <V> void invoke(Callable<V> call, android.support.v4.app.Fragment _frg, TaskCallback<V> callback) {
new CallableTask<V>(_frg,call, callback).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
}
This gets called here... only when clicking on a button Send.
CallableTask.invoke(new Callable<Sent>() {
#Override
public Sent call() throws Exception {
}, this, new TaskCallback<Sent>() {
#Override
public void success(Sent result, Context context) {
mGridArray.add(result);
if (mListAdapter != null) {
mListAdapter.notifyDataSetChanged();
mListView.setSelection(mListAdapter.getCount());
mListView.smoothScrollToPosition(mListAdapter.getCount());
}
#Override
public void error(Exception e) {
}
});
Thanks
Dhiren
I finally resolved this by running a Asynch.cancel call on the thread from the activity fragment that started this thread. when I move away from activity. If I did not , it blocked any other tasks from running,
I have a class "HomeActivity", which is as follows:
public class HomeActivity extends FragmentActivity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
public void Work() {}
}
}
I have another class WebServiceTask, which is as follows:
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// Here I am trying to call the work() method in HomeFragment, How can I do that?
}
My question is how can i call the work() method in HomeFragment class from onPostExecute().
I would propose making a listener for you task, and invoke its method in post execute. It will geve you a lot more flexibility and control on what you want to deafter the task finishes. Here is sample code I would use:
public class MyTask extend AsyncTask<Void, Void, Boolean> {
public interface MyTaskListener {
void onSuccess();
void onFailure();
void onError(Throwable t);
}
private Throwable error;
private MyTaskListener listener;
public MyTask(MyTaskListener listener) {
this.listener = listener;
}
#Overrride
public Boolean doInBackground(Void... params) {
try {
if (workCompleted()) {
//work completed without error - return true
return Boolean.TRUE;
} else {
//work failed to complete - return false
return Boolean.FALSE;
}
} catch(Exception e) {
//unexpected error happened - remember error and return null
this.error = e;
return null;
}
}
#Override
public void onPostExecute(Boolean result){
if (!isCancelled()) { //you only want to process if task wasn't cancelled
if (this.error != null && result == null) { //we have error, process it
if (listener != null) {
listener.onError(this.error);
}
}
if (Boolean.FALSE.equals(result)) { //we have faile, process it
if (listener != null) {
listener.onFail();
}
}
if (Boolean.TRUE.equals(result)) { //we have success
if (listener != null) {
listener.onSuccess();
}
}
}
}
}
And then, in you activit/fragment/service/ use something like this:
public class MyActivity extends Activity {
private void someInstanceMethod() {/ *do your work here */}
#Override
public void onCreate(Bundle savedInstanceState) {
//setup ui, or do whatever you need
//create MyAsyncTask with proper listener
MyAsyncTask task = new MyAsyncTask(new MyAsyncTask.MyAsyncTaskListener() {
#Override
public void onSuccess() {
//call your instance method here
someInstanceMethod();
}
#Override
public void onFailure() {
//process fail
}
#Override
public void onError() {
//process error
}
});
}
}
This is one method. I don't know if it is the best one:
Make work function as public static void. Call it from Asynctask onpostexecute as
HomeActivity.Work();
Edit:
One more way( again not sure if this is the best way):
If you cant make this work, consider putting your asynctask class inside the home activity class
Well using the FragmentManger findFragmentById() or findFragmentByTag() you can get an instance of the current fragment and call your fragment method.
Create an interface file
public interface AsynAction
{
public void Work();
}
Implements AsynAction in HomeActivity
public class HomeActivity extends FragmentActivity implements OnClickListener,AsyncAction {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
HomeFragment list = new HomeFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class HomeFragment extends Fragment {
webServiceTask = WebServiceTask.getInstance(
getActivity(), Constants.METHOD_NAME_PRODUCTS,
Constants.PRODUCT_NAME, null);
#Override
public void Work()
{
}
}
}
Then make changes in you asynctask to receive asyncAction object as reference
final public class WebServiceTask extends AsyncTask<String, String, String> {
private WebServiceTask(final AyscAction asycAction,final Activity activity, final String methodName,
final String productName, final String addInfo[]) {
super();
this.activity = activity;
this.asycAction=asycAction;
this.methodName = methodName;
this.productName = productName;
this.addInfo = addInfo;
}
public static WebServiceTask getInstance(final AyscAction asycAction,final Activity activity,
final String methodName, final String productName,
final String additionalInfo[]) {
webServiceTask = new WebServiceTask(asycAction,activity, methodName, productName,
additionalInfo);
return webServiceTask;
}
protected void onPostExecute() {
// You can call work from here
if(asynAction!=null)
asyncAction.Work();
}