簡體   English   中英

如何從(非活動)Java類調用活動類中定義的方法

[英]How to call a method defined in an Activity class from a (non-activity) Java class

在我的DataTrak活動中,我定義了以下方法:

    public void updateTotal(IAmount totalAmount, int transactionType) {
        switch (transactionType) {
            case AccountTotals.VALUE_CANCELS:
                txtView_cancels_value.setText("" +     (Long.parseLong(txtView_cancels_value.getText().toString()) + totalAmount.getValue()));          
                break;
            case AccountTotals.VALUE_PAYS:
                txtView_pays_value.setText("" + (Long.parseLong(txtView_pays_value.getText().toString()) + totalAmount.getValue()));            
                break;
            case AccountTotals.VALUE_SALES:
                txtView_sales_value.setText("" + (Long.parseLong(txtView_sales_value.getText().toString()) + totalAmount.getValue()));
                break;
            default:
                break;
    }
    btn_total.setBackgroundResource(R.drawable.button_green );

}

該方法計算並更新一些TextView,並更改按鈕的顏色。 然后,我需要從Java抽象類調用此方法。 該方法調用出現在非UI線程上運行的方法中。 這是我調用方法的方式:

            new Thread()
        {
            public void run()
            {
                new DataTrak().runOnUiThread(new Runnable()
                {
                    public void run()
                    {           
                        new DataTrak().updateTotal(totalAmount,transactionType);
                    }
                });
            }
        }.start();

問題是我遇到了運行時異常。 這是LogCat的輸出:

05-13 16:52:13.325: E/AndroidRuntime(22101): FATAL EXCEPTION: Thread-1577
05-13 16:52:13.325: E/AndroidRuntime(22101): Process: com.ilts.lct, PID: 22101
05-13 16:52:13.325: E/AndroidRuntime(22101): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
05-13 16:52:13.325: E/AndroidRuntime(22101):    at android.os.Handler.<init>    (Handler.java:200)
05-13 16:52:13.325: E/AndroidRuntime(22101):    at android.os.Handler.<init>(Handler.java:114)
05-13 16:52:13.325: E/AndroidRuntime(22101):    at android.app.Activity.<init>(Activity.java:786)
05-13 16:52:13.325: E/AndroidRuntime(22101):    at com.ilts.lct.ap.mainframe.DataTrak.<init>(DataTrak.java:37)
05-13 16:52:13.325: E/AndroidRuntime(22101):    at com.ilts.lct.ap.customerfunctions.CustomerTransaction$2.run(CustomerTransaction.java:736)

實際上,起初我只有方法調用這一行,但是卻遇到了相同的運行時異常。 我搜索“無法在尚未調用Looper.prepare()的線程內創建處理程序”,並且發現了有關此問題的幾篇文章。 其中之一使我將方法調用放入新的Thread中,如上所示。 但是我仍然遇到相同的運行時異常。 我應該改變什么? 您能幫助我了解實際的問題以及如何解決嗎? 提前致謝。

在閱讀@Metero的答案后,下面是Java抽象類中的代碼:

public abstract class CustomerTransaction extends Transaction {
...................................................

    public interface CallBack {
    public void updateTotal(IAmount a,int n);
}

private static CallBack callback;

public static void registerCallback(CallBack callback1){
   callback = callback1;
}

/**
 * Method to update the transaction state
 *
 * @param  state  The new transaction state
 **/
public void setState(final int state) {
    this.state = state;
    /*
     * Update the status
     */
    if (state == TRANSACTION_COMPLETE) {
                    new Thread()
        {
            public void run() {
                Looper.prepare();
                new DataTrak().runOnUiThread(new Runnable()
                {
                    public void run() {
                        Log.i("HERE", "HERE");
                        Looper.prepare(); 
                        callback.updateTotal(totalAmount,transactionType);
                        Looper.loop();
                    }
                });
            }
        }.start();

   }
   }
....................
}

您永遠不要自己實例化一個Activity,如果您這樣做的話,那將不是正常的活動,而只是一個有問題的計划Java對象。

因此,可能要解決的問題是使用觀察者模式 ,在該模式中可以使用“回調”方法定義一個接口,然后讓Activity實現它並使它訂閱通知的“提供者”。 因此,基本上,當此更新線程運行時,您將通過訂閱的偵聽器列表運行並調度該調用,就像正常的方法調用一樣。

只需記住:尊重活動生命周期的'subscribe'和'unsubscribe'.. like在onCreate()上訂閱,在onDestroy()上取消訂閱。

活動:

public class YourActivity extends Activity implements ControlListener {

public void onCreate(...) {
 ....
 control.registerListener(this);

 control.performOperation();

}

public void onDestroy(...) {
 ....
 control.unregisterListener(this);
}

public void updateTotal(String newValue) {
  runOnUiThread(new Runnable() {
   public void run() {
     textView.setText(newValue);
   } 
  });

   }
  }

控制類別:

   public class Control {

      private Set<ControlListener> listeners = new HashSet<ControlListener>();

     public synchronized void registerListener(ControlListener listener) {
       listeners.add(listener);
     }

    public synchronized void unRegisterListener(ControlListener listener) {
       listeners.remove(listener);
    }

    public synchronized void notifyListeners(String newValue) {
      for(ControlListener listener : listeners) {
        listener.updateTotal(newValue);
      }
    }

     public void performOperation() {

      new Thread() {
        public void run() { 
          String newValue= service.performBackgroundOperationToGetNewValue();

         notifyListeners(newValue);
        }
      }.start();
     }
   }

控制監聽器:

 public interface ControlListener {
    public void updateTotal(String newValue);
  }

另外,您可以使用非常方便的HANDY庫在項目上應用Observer模式,即Ottohttp : //square.github.io/otto/使用Otto,您不需要注冊/注銷/在您控件中的notifylisteners方法中,它會自動放置在其他位置。

這個問題的本質暗示存在違反MVC的行為。 而不是在Activity中調用模型的方法,它應該在Activity已在模型上注冊的某些回調中調用方法。 此回調應在UI線程中排隊。

這不是最佳選擇。

new Thread()
    {
        public void run()
        {
            new DataTrak().runOnUiThread(new Runnable()
            {
                public void run()
                {
                    Looper.prepare();//This is not the best choice.
                    new DataTrak().updateTotal(totalAmount,transactionType);
                }
            });
        }
    }.start();

我建議像這樣使用AsyncTask。

class SampleTask extends AsyncTask<Boolean, Boolean, Boolean> {

    private int totalAmount;
    private yourActivity activity;

    //passing parameters
    public void SampleTask(yourActivity activity){
        this.activity = activity;
    }

    @Override
    protected Boolean doInBackground(Boolean... params) {
        while (totalAmount < 10){
            totalAmount++;
        }
    }
    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
// this is not the best choice
// because you are creating two instances.
        new DataTrak().updateTotal(totalAmount,transactionType);

        //If you pass a parameter, this for me is the best option.

        activity.updateTotal(totalAmount,transactionType);
    }
}

我同意@Alécio,請使用回調執行此操作。 在非活動類中添加一個回調接口:

   class yourclass{
        public interface callBack{
               public void updateTotal(...);
         }

        private callBack callback;

        public void registerCallback(callBack callback){
              this.callback = callback;
        }

        //somewhere call the updateTotal(...)
        callback.updateTotal(...);
  }

在活動中

  //the activity implement the callback and then register it, and call the callback when neccesary

    class yourActivity extends Activity implement callBack{

        @Override
        onCreate(...){
        ...

        yourclass.registerCallback(this);

        }

        @Override
        public void updateTotal(...){
         .......
        }

    }

多類通信的示例代碼。

public class Controller {
    callBack callBack;

    public void registerCallBack(callBack back){
        this.callBack = back;
    }

    public void show(){
          callBack.update(1, "my name");
    }

    public interface callBack{
        public void update(int type, String message);
    }

    public callBack getCallBack(){
        return callBack;
    }

}

public class AnotherClass {
    Controller controller = new Controller();

    public void registerCallBack(callBack back){
        controller.registerCallBack(back);
    }

    public void show(){
        controller.getCallBack().update(1, "show me!");
    }

}


public class MyActivity extends Activity implements callBack {
    AnotherClass myclass = new AnotherClass();

    @Override
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        Log.d("TAG", "This is message!"); 
        setContentView(R.layout.main);
        myclass.registerCallBack(this);

    }

    @Override
    protected void onResume() {
        super.onResume();
        myclass.show();
    }

    @Override
    public void update(int type, String message) {
        ((TextView) findViewById(R.id.display)).setText(message);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM