java - জনক - ভলিবলের ওজন কত




আমি ভলি সঙ্গে একটি সমলয় অনুরোধ করতে পারি? (4)

কল্পনা করুন যে আমি ইতিমধ্যে এমন একটি পরিষেবাতে যা একটি ব্যাকগ্রাউন্ড থ্রেড আছে। আমি কি একই থ্রেডে ভলি ব্যবহার করে একটি অনুরোধ করতে পারি, যাতে কলব্যাকগুলি সমান্তরালভাবে ঘটবে?

এর জন্য দুটি কারণ রয়েছে: - প্রথমে, আমাকে অন্য থ্রেডের দরকার নেই এবং এটি তৈরি করার জন্য এটি একটি বর্জ্য। - দ্বিতীয়ত, যদি আমি একটি পরিষেবা ইনন্টেন্টে থাকি, থ্রেডটি কার্যকর করা কলব্যাকের আগে শেষ হয়ে যাবে, এবং সেখানে আমার কাছে ভলি থেকে কোন প্রতিক্রিয়া হবে না। আমি জানি যে আমি আমার নিজের পরিষেবা তৈরি করতে পারি যার একটি রানলপ আমি নিয়ন্ত্রণ করতে পারি এমন কিছু থ্রেড আছে, তবে এটি ভলিলে এই কার্যকারিতা থাকার পক্ষে পছন্দসই হবে।

ধন্যবাদ!


@ বুন্ডেলস এবং @ ম্যাথুসের উত্তরগুলির পরিপূরক পর্যবেক্ষণ হিসাবে, আমি নিশ্চিত নই যে কোন কলটি ভলি দ্বারা প্রধান থ্রেড ছাড়া কিছুতেই বিতরণ করা হয়।

উৎস

RequestQueue বাস্তবায়নের দিকে তাকিয়ে মনে হচ্ছে RequestQueue অনুরোধটি চালানোর জন্য একটি NetworkDispatcher RequestQueue ব্যবহার করছে এবং ফলাফল সরবরাহ করার জন্য ResponseDelivery বিতরণ ( ResponseDelivery RequestQueue NetworkDispatcher RequestQueue প্রবেশ করা হয়)। ResponseDelivery RequestQueue মূলত থ্রেড থেকে Handler স্পন দিয়ে তৈরি হয় ( RequestQueue বাস্তবায়নে লাইন 112 এর কাছাকাছি কোথাও)।

NetworkDispatcher বাস্তবায়নে লাইন 135 সম্পর্কে কোথাও কোনও ত্রুটি হিসাবে একই ResponseDelivery NetworkDispatcher মাধ্যমে সফল ফলাফল বিতরণ করা হয়। আবার; প্রধান থ্রেড থেকে Handler স্পন উপর ভিত্তি করে একটি ResponseDelivery

যুক্তিসহ ব্যাখ্যা

IntentService থেকে অনুরোধ করার ক্ষেত্রে ব্যবহারের ক্ষেত্রে এটির পক্ষে অনুমান করা উপযুক্ত যে IntentService প্রতিক্রিয়া না হওয়া পর্যন্ত আমাদের পরিষেবার থ্রেডটি অবরুদ্ধ হওয়া উচিত (ফলস্বরূপ পরিচালনার জন্য জীবিত রানটাইম সুযোগটি নিশ্চিত করার জন্য)।

প্রস্তাবিত সমাধান

একটি পদ্ধতির একটি RequestQueue তৈরি করা ডিফল্ট ভাবে ওভাররাইড করা হবে, যেখানে পরিবর্তে একটি বিকল্প কনস্ট্রাকটর ব্যবহার করা হয়, একটি ResponseDelivery RequestQueue ইনজেকশন যা মূল থ্রেডের পরিবর্তে বর্তমান থ্রেড থেকে spawns। আমি এই, যদিও এর প্রভাব তদন্ত না।


আমি ম্যাথিউ এর গ্রহণযোগ্য উত্তর কিছু যোগ করতে চান। যখন RequestFuture আপনার তৈরি থ্রেড থেকে একটি সমলয় কল করতে পারে বলে মনে হচ্ছে, এটি হয় না। পরিবর্তে, কলটি একটি ব্যাকগ্রাউন্ড থ্রেডে মৃত্যুদন্ড কার্যকর করা হয়।

লাইব্রেরির মধ্য দিয়ে যা বুঝেছি তা থেকে, RequestQueue এর অনুরোধগুলি তার start() পদ্ধতিতে প্রেরিত হয়:

    public void start() {
        ....
        mCacheDispatcher = new CacheDispatcher(...);
        mCacheDispatcher.start();
        ....
           NetworkDispatcher networkDispatcher = new NetworkDispatcher(...);
           networkDispatcher.start();
        ....
    }

এখন উভয় CacheDispatcher এবং NetworkDispatcher CacheDispatcher ক্লাস থ্রেড প্রসারিত করে। অনুরোধের RequestFuture জন্য কার্যকরভাবে একটি নতুন কর্মী থ্রেড তৈরি করা হয়েছে এবং প্রতিক্রিয়া সফলভাবে RequestFuture এবং ত্রুটিপূর্ণ শ্রোতাদের RequestFuture দ্বারা অভ্যন্তরীণভাবে প্রয়োগ করা RequestFuture

যদিও আপনার দ্বিতীয় উদ্দেশ্যটি অর্জন করা হলেও আপনি প্রথম উদ্দেশ্যটি এমন নয় যে নতুন থ্রেড সর্বদা উদ্ভূত হয়, কোনও থ্রেড থেকে আপনি RequestFuture চালান।

সংক্ষেপে, ডিফল্ট ভলি লাইব্রেরি সহ সত্য সমলয় অনুরোধ সম্ভব নয়। আমি ভুল হলে আমাকে সংশোধন করুন।


দ্রষ্টব্য @ ম্যাথিউস উত্তর সঠিক কিন্তু যদি আপনি অন্য থ্রেডে থাকেন এবং আপনার কোন ইন্টারনেট না থাকলে আপনি ভলি কল করেন তবে আপনার ত্রুটির কলব্যাকটি প্রধান থ্রেডে কল করা হবে, তবে আপনার যে থ্রেডটি চালু আছে সেটি ব্লক করা হবে। (অতএব, যদি থ্রেডটি কোনও ইন্টেন্টসেয়ার হয় তবে আপনি এটিতে অন্য বার্তা পাঠাতে পারবেন না এবং আপনার পরিষেবা মূলত মৃত হয়ে যাবে)।

future.get(30, TimeUnit.SECONDS) get() , যা একটি টাইমআউট future.get(30, TimeUnit.SECONDS) এর সংস্করণটি ব্যবহার করুন এবং আপনার থ্রেড থেকে বেরিয়ে যাওয়ার জন্য ত্রুটিটি ধরুন।

@ ম্যাথুসের উত্তর মেলে:

        try {
            return future.get(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // exception handling
        } catch (ExecutionException e) {
            // exception handling
        } catch (TimeoutException e) {
            // exception handling
        }

নীচে আমি একটি পদ্ধতিতে এটি আবৃত এবং একটি ভিন্ন অনুরোধ ব্যবহার করুন:

   /**
     * Runs a blocking Volley request
     *
     * @param method        get/put/post etc
     * @param url           endpoint
     * @param errorListener handles errors
     * @return the input stream result or exception: NOTE returns null once the onErrorResponse listener has been called
     */
    public InputStream runInputStreamRequest(int method, String url, Response.ErrorListener errorListener) {
        RequestFuture<InputStream> future = RequestFuture.newFuture();
        InputStreamRequest request = new InputStreamRequest(method, url, future, errorListener);
        getQueue().add(request);
        try {
            return future.get(REQUEST_TIMEOUT, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Log.e("Retrieve cards api call interrupted.", e);
            errorListener.onErrorResponse(new VolleyError(e));
        } catch (ExecutionException e) {
            Log.e("Retrieve cards api call failed.", e);
            errorListener.onErrorResponse(new VolleyError(e));
        } catch (TimeoutException e) {
            Log.e("Retrieve cards api call timed out.", e);
            errorListener.onErrorResponse(new VolleyError(e));
        }
        return null;
    }

সম্ভবত এটি ফিউচার ব্যবহার করার পরামর্শ দেওয়া হয়, তবে যে কোন কারণে আপনি যদি নিজের সিঙ্ক্রোনাইজড ব্লকিং জিনিসটি রান্না করতে না চান তবে আপনাকে java.util.concurrent.CountDownLatch ব্যবহার করতে হবে। তাই এই ভালো কাজ করবে ..

//I'm running this in an instrumentation test, in real life you'd ofc obtain the context differently...
final Context context = InstrumentationRegistry.getTargetContext();
final RequestQueue queue = Volley.newRequestQueue(context);
final CountDownLatch countDownLatch = new CountDownLatch(1);
final Object[] responseHolder = new Object[1];

final StringRequest stringRequest = new StringRequest(Request.Method.GET, "http://google.com", new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        responseHolder[0] = response;
        countDownLatch.countDown();
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        responseHolder[0] = error;
        countDownLatch.countDown();
    }
});
queue.add(stringRequest);
try {
    countDownLatch.await();
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}
if (responseHolder[0] instanceof VolleyError) {
    final VolleyError volleyError = (VolleyError) responseHolder[0];
    //TODO: Handle error...
} else {
    final String response = (String) responseHolder[0];
    //TODO: Handle response...
}

যেহেতু লোকেরা আসলে এটি করার চেষ্টা করেছিল এবং কিছু সমস্যার মধ্যে দৌড়েছিল আমি সিদ্ধান্ত নিলাম যে আমি আসলেই এটির একটি "বাস্তব জীবন" কার্যকরী নমুনা সরবরাহ করব। এখানে এটি https://github.com/timolehto/SynchronousVolleySample

এখন সমাধান কাজ করে, যদিও এটি কিছু সীমাবদ্ধতা আছে। সবচেয়ে গুরুত্বপূর্ণ, আপনি এটি মূল UI থ্রেডে কল করতে পারবেন না। ভলি ব্যাকগ্রাউন্ডে অনুরোধ সম্পাদন করে, কিন্তু ডিফল্টরূপে ভলি প্রতিক্রিয়া প্রেরণ করার জন্য অ্যাপ্লিকেশনটির প্রধান Looper ব্যবহার করে। এটি একটি ডেডলক সৃষ্টি করে কারণ মূল UI থ্রেড প্রতিক্রিয়ার জন্য অপেক্ষা করছে, কিন্তু onCreate প্রক্রিয়াকরণের আগে onCreate শেষ করার জন্য অপেক্ষা করছে। যদি আপনি সত্যিই এটি করতে চান তবে স্ট্যাটিক হেলপার পদ্ধতির পরিবর্তে, আপনার নিজের RequestQueue প্রেরণ করুন আপনার নিজের ExecutorDelivery RequestQueue একটি Looper ব্যবহার করে একটি Handler সাথে সংযুক্ত যা মূল UI থ্রেড থেকে বিভিন্ন থ্রেডের সাথে সংযুক্ত।





android-volley