Работа с Picasso android в AsyncTask

318
26 ноября 2016, 19:13

Загружаю png изображение через Picasso по url, вот только перед relativeLayout.setBackground выдает исключение что я использую main поток, вызов SetBackground идет в методе OnCreate.

Подскажите, в чем может быть ошибка

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1 java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:299) at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) at java.util.concurrent.FutureTask.setException(FutureTask.java:124) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:856) Caused by: java.lang.IllegalStateException: Method call should happen from the main thread. at com.squareup.picasso.Utils.checkMain(Utils.java:136) at com.squareup.picasso.RequestCreator.into(RequestCreator.java:496) at com.example.user_android.otvchat.MainActivity$SetBackground.doInBackground(MainActivity.java:386) at com.example.user_android.otvchat.MainActivity$SetBackground.doInBackground(MainActivity.java:367) at android.os.AsyncTask$2.call(AsyncTask.java:287) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask.run(FutureTask.java:137)  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)  at java.lang.Thread.run(Thread.java:856) 

public class MainActivity extends AppCompatActivity {
private ImageButton btn;
private TextView txtMain;
private TextView txtSecond;
private TextView txtSecond2;
private EditText editPhone;
private EditText editCode;
private Button back;
private boolean numberPhone = true;
private boolean saveNumber = false;
public static String NUMBER_PHONE = "";
public static String NUMBER_PHONE2 = "";
public static String userID;
private int code;
private int editCodePush;
private boolean rules;
SharedPreferences sPref;
String url;
final String SAVED_PHONE = "saved_phone";
RelativeLayout relativeLayout;
String URL = "****";
/**
 * ATTENTION: This was auto-generated to implement the App Indexing API.
 * See https://g.co/AppIndexing/AndroidStudio for more information.
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn = (ImageButton) findViewById(R.id.imageButton3);
    txtMain = (TextView) findViewById(R.id.textView5);
    txtSecond = (TextView) findViewById(R.id.textView3);
    txtSecond2 = (TextView) findViewById(R.id.textView4);
    editPhone = (EditText) findViewById(R.id.editText);
    editCode = (EditText) findViewById(R.id.editText2);
    back = (Button) findViewById(R.id.button2);
    back.setVisibility(View.INVISIBLE);
    editCode.setVisibility(View.INVISIBLE);
    txtSecond2.setVisibility(View.INVISIBLE);
    txtSecond.setVisibility(View.INVISIBLE);
    editPhone.addTextChangedListener(new MaskedWatcher("+38 (###) ###-##-##"));
    setTitle("Авторизация");
    relativeLayout = (RelativeLayout)findViewById(R.id.activity_main);
    sPref = getPreferences(MODE_PRIVATE);
    Picasso.with(getApplicationContext()).load("http://sms.binovery.gq/img/heart-back.png").into(new Target(){
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            relativeLayout.setBackground(new BitmapDrawable(getApplicationContext().getResources(), bitmap));
            Toast.makeText(getApplicationContext(), "OK", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onBitmapFailed(final Drawable errorDrawable) {
            Toast.makeText(getApplicationContext(),"Error", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onPrepareLoad(final Drawable placeHolderDrawable) {
            Toast.makeText(getApplicationContext(),"Loading...", Toast.LENGTH_SHORT).show();
        }
    });
    btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (saveNumber) {
                if (editPhone.getText().toString().equals(sPref.getString(SAVED_PHONE, ""))) {
                    NUMBER_PHONE = editPhone.getText().toString();
                    new ShowDialogAsnc().execute();
                    SystemClock.sleep(1000);
                    Intent intent = new Intent(getApplicationContext(), NavigationDrawer.class);
                    intent.putExtra("regulations_btn", R.id.button6);
                    startActivity(intent);
                }
            } else if (true) {
                new ShowDialogAsnc().execute();
                getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
                Spannable text = new SpannableString(txtSecond.getText());
                text.setSpan(new UnderlineSpan(), 100, 104, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                txtSecond.setText(text);
                txtSecond.setTextColor(Color.WHITE);
                editPhone.setVisibility(View.INVISIBLE);
                txtMain.setVisibility(View.INVISIBLE);
                back.setVisibility(View.VISIBLE);
                editCode.setVisibility(View.VISIBLE);
                txtSecond2.setVisibility(View.VISIBLE);
                txtSecond.setVisibility(View.VISIBLE);
                NUMBER_PHONE = editPhone.getText().toString();
                btn.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        try {
                            editCodePush = Integer.parseInt(editCode.getText().toString());
                            if (editCodePush == code) {
                                sPref = getPreferences(MODE_PRIVATE);
                                SharedPreferences.Editor ed = sPref.edit();
                                ed.putString(SAVED_PHONE, NUMBER_PHONE.toString());
                                ed.commit();
                                if (!rules) {
                                    Intent intent = new Intent(getApplicationContext(), NavigationDrawer.class);
                                    intent.putExtra("regulations_btn", R.id.button6);
                                    startActivity(intent);
                                } else {
                                    Intent intent = new Intent(getApplicationContext(), Regulations.class);
                                    startActivity(intent);
                                }
                            } else {
                                Toast.makeText(getApplicationContext(), "Не верно введен код", Toast.LENGTH_SHORT).show();
                            }
                        } catch (NumberFormatException e) {
                            Toast.makeText(getApplicationContext(), "Не верно введен код", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            } else {
                Toast.makeText(getApplicationContext(), "Номер телефон введен не корректно", Toast.LENGTH_LONG).show();
            }
        }

    });
    back.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            back.setVisibility(View.INVISIBLE);
            editCode.setVisibility(View.INVISIBLE);
            txtSecond2.setVisibility(View.INVISIBLE);
            txtSecond.setVisibility(View.INVISIBLE);
            editPhone.setVisibility(View.VISIBLE);
            txtMain.setVisibility(View.VISIBLE);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (true) {
                        new ShowDialogAsnc().execute();
                        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
                        Spannable text = new SpannableString(txtSecond.getText());
                        text.setSpan(new UnderlineSpan(), 100, 104, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        txtSecond.setText(text);
                        txtSecond.setTextColor(Color.WHITE);
                        editPhone.setVisibility(View.INVISIBLE);
                        txtMain.setVisibility(View.INVISIBLE);
                        back.setVisibility(View.VISIBLE);
                        editCode.setVisibility(View.VISIBLE);
                        txtSecond2.setVisibility(View.VISIBLE);
                        txtSecond.setVisibility(View.VISIBLE);
                        NUMBER_PHONE = editPhone.getText().toString();
                        editCode.setText("");
                        btn.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                if (numberPhone) {
                                    Intent intent = new Intent(getApplicationContext(), Regulations.class);
                                    startActivity(intent);
                                }
                            }
                        });
                        btn.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                try {

                                    editCodePush = Integer.parseInt(editCode.getText().toString());
                                    if (editCodePush == code) {
                                        if (!rules) {
                                            Intent intent = new Intent(getApplicationContext(), NavigationDrawer.class);
                                            intent.putExtra("regulations_btn", R.id.button6);
                                            startActivity(intent);
                                        } else {
                                            Intent intent = new Intent(getApplicationContext(), Regulations.class);
                                            startActivity(intent);
                                        }
                                    } else {
                                        Toast.makeText(getApplicationContext(), "Не верно введен код", Toast.LENGTH_SHORT).show();
                                    }
                                } catch (NumberFormatException e) {
                                    Toast.makeText(getApplicationContext(), "Не верно введен код", Toast.LENGTH_SHORT).show();
                                }
                            }
                        });
                    }
                }
            });
        }
    });

}

private class ShowDialogAsnc extends AsyncTask<Void, Integer, Void> {
    String phone;
    JSONObject jsonObjectCode;
    @Override
    protected void onPreExecute() {
        phone = editPhone.getText().toString();
        super.onPreExecute();
    }
    @Override
    protected Void doInBackground(Void... voids) {
        try {
            NUMBER_PHONE = phone;
            jsonObjectCode = new JSONObject(new PostExample().PostExampleMethod("phone_number", phone));
            SystemClock.sleep(1000);
            code = jsonObjectCode.getInt("code");
            rules = jsonObjectCode.isNull("read_rules");
            userID = jsonObjectCode.getString("id");
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }
    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
    }
}
Answer 1

вот только перед relativeLayout.setBackground выдает исключение что я использую main поток

Исключение как раз говорит об обратном:

Method call should happen from the main thread

То, что Вы создаете и запускаете SetBackground extends AsyncTask в onCreate (то есть из главного потока) в данном случае не значит ничего, так как метод doInBackground(...) AsyncTask'а выполняется уже не в в главном потоке.

При загрузке изображений с помощью Picasso нет необходимости самостоятельно создавать новый поток, так как Picasso уже сам работает асинхронно.

Методы relativeLayout.setBackground и Toast.show() можно вызвать только из главного потока, а Вы пытаетесь вызвать их в методе doInBackground(...) AsyncTask'а, о чем Вам и говорится в стек-трейсе.

Для решения проблемы просто уберите AsyncTask и загружайте изображения прямо в методе onCreate(...).

UPD. Picasso хранит ссылку на инстанс Target'а в виде weak reference, которая может быть почищена Garbage collector'ом. Эту проблему можно решить сделав ссылку на Target сильной (strong).

Первый способ:

Добавляете

private Target mTarget;

как поле класса MainActivity.

Далее в методе OnCreate() создаете mTarget:

mTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        relativeLayout.setBackground(new BitmapDrawable(getApplicationContext().getResources(), bitmap));
        Toast.makeText(getApplicationContext(), "OK", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onBitmapFailed(final Drawable errorDrawable) {
        Toast.makeText(getApplicationContext(),"Error", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onPrepareLoad(final Drawable placeHolderDrawable) {
        Toast.makeText(getApplicationContext(),"Loading...", Toast.LENGTH_SHORT).show();
    }
};

и после этого загружаете изображение:

Picasso.with(getApplicationContext()).load("http://sms.binovery.gq/img/heart-back.png").into(mTarget);

Второй способ:

Реализуете интерфейс Target в Вашей MainActivity:

public class MainActivity extends AppCompatActivity implements Target {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ...
    }
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        relativeLayout.setBackground(new BitmapDrawable(getApplicationContext().getResources(), bitmap));
        Toast.makeText(getApplicationContext(), "OK", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onBitmapFailed(final Drawable errorDrawable) {
        Toast.makeText(getApplicationContext(),"Error", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onPrepareLoad(final Drawable placeHolderDrawable) {
        Toast.makeText(getApplicationContext(),"Loading...", Toast.LENGTH_SHORT).show();
    }
    ...
}

А в методе onCreate(...) загружаете изображение:

Picasso.with(getApplicationContext()).load("http://sms.binovery.gq/img/heart-back.png").into(this);
READ ALSO
Отправка запроса на удаление на REST сервер

Отправка запроса на удаление на REST сервер

Клиент шлет запрос на REST сервер на удаление записиИсполнение на Angular

443
Подключение к mysql (написание интерфейса)

Подключение к mysql (написание интерфейса)

Помогите пожалуйста разобраться с подключением к Базе данныхнужно сделать интерфейс и чтобы по нажатию кнопки программа подключалась к базе,...

202